import { SYSTEM } from "../config/system.mjs"
import { log } from "./helpers.mjs"
import { processD30BonusDice, hasD30Reroll } from "./d30.mjs"

export async function handleSocketEvent(msg = {}) {
  log(`handleSocketEvent !`, msg)
  let actor
  switch (msg.type) {
    case "applyDamage":
      if (game.user.isGM) {
        // Prefer the specific token actor (correct for unlinked monsters); fall back to world actor.
        actor = msg.tokenId
          ? canvas.tokens?.placeables?.find(t => t.id === msg.tokenId)?.actor
          : (game.combat?.combatants?.find(c => c.actorId === msg.actorId)?.actor
            ?? game.actors.get(msg.actorId))
        if (actor) await actor.applyDamage(msg.damage)
      }
      break
    case "rollInitiative":
      if (msg.userId && msg.userId !== game.user.id) break
      actor = game.actors.get(msg.actorId)
      await actor.system.rollInitiative(msg.combatId, msg.combatantId)
      break
    case "rollProgressionDice":
      if (msg.userId && msg.userId !== game.user.id) break
      actor = game.actors.get(msg.actorId)
      await actor.system.rollProgressionDice(msg.combatId, msg.combatantId, msg.rollProgressionCount)
      break
    case "requestDefense":
      // Vérifier si le message est destiné à cet utilisateur
      if (msg.userId === game.user.id) {
        showDefenseRequest(msg)
      }
      break
    case "offerAttackerGrit":
      // Vérifier si le message est destiné à cet utilisateur
      if (msg.userId === game.user.id) {
        handleAttackerGritOffer(msg)
      }
      break
    case "applyBleeding":
      if (game.user.isGM) {
        actor = msg.tokenId
          ? canvas.tokens?.placeables?.find(t => t.id === msg.tokenId)?.actor
          : game.actors.get(msg.actorId)
        if (actor && actor.system.hp?.wounds && msg.damage > 0) {
          const wounds = foundry.utils.duplicate(actor.system.hp.wounds)
          const slot = wounds.findIndex(w => !w.value && !w.duration)
          if (slot !== -1) {
            wounds[slot] = { value: msg.damage, duration: msg.damage, description: "Bleeding" }
            await actor.update({ "system.hp.wounds": wounds })
          }
        }
      }
      break
    case "attackBoosted":
      if (msg.userId === game.user.id) {
        handleAttackBoosted(msg)
      }
      break
  }
}

export async function handleAttackerGritOffer(msg) {
  const { attackerId, attackRoll, defenseRoll, attackerName, defenderName, attackWeaponId, attackRollType, attackRollKey, defenderId } = msg

  const attacker = game.actors.get(attackerId)
  if (!attacker) {
    console.warn("Attacker not found:", attackerId)
    return
  }

  const attackBonus = await offerAttackerGritBonus(
    attacker,
    attackRoll,
    defenseRoll,
    attackerName,
    defenderName
  )

  const attackRollFinal = attackRoll + attackBonus

  // Maintenant créer le message de comparaison
  await compareAttackDefense({
    attackerName,
    attackerId,
    attackRoll: attackRollFinal,
    attackWeaponId,
    attackRollType,
    attackRollKey,
    defenderName,
    defenderId,
    defenseRoll
  })
}

export async function handleAttackBoosted(msg) {
  const {
    attackerName, attackerId, defenderName, defenderId, defenderTokenId,
    attackerHandledBonus, attackRollFinal, defenseRoll, attackWeaponId, attackRollType, attackRollKey,
    shieldDamageReduction: initialShieldDR,
    d30Bleed, d30DamageMultiplier, d30DrMultiplier,
    damageTier, attackD30message, defenseD30message, defenseRerollContext,
    hasShield, shieldLabel, shieldFormula, shieldDr, canAdHocShield
  } = msg

  const defender = game.actors.get(defenderId)
  const attacker = game.actors.get(attackerId)
  if (!defender) return

  // The createChatMessage hook is suppressed on this client in two cases:
  //   1. Attacker is a PC on another client — the hook's defense reaction loop
  //      and shouldCreateMessage are both skipped.
  //   2. Attacker is GM-controlled with D30 — the hook skips everything and
  //      waits for this socket handler.
  // In both cases, this handler must run to show the defense dialog and create
  // the comparison message. The common condition: the current user is the
  // defender's primary controller.
  const _isPrimaryController = actor => {
    if (!actor) return false
    const activePlayerOwners = game.users.filter(u => u.active && !u.isGM && actor.testUserPermission(u, "OWNER"))
    if (activePlayerOwners.length > 0) return activePlayerOwners[0].id === game.user.id
    return game.user.isGM
  }
  const defenderIsMine = _isPrimaryController(defender)
  if (!defenderIsMine) return

  let updatedDefenseRoll = defenseRoll
  let shieldBlocked = false
  let shieldReaction = null
  let canShieldReact = hasShield
  let canAdHoc = canAdHocShield

  // ── D30 bonus dice (defense) — resolved before grit/luck/shield ───────
  let defenseDrMultiplier = null
  if (defenseD30message && defender) {
    const d30Result = await processD30BonusDice(defenseD30message, "defense", null, defender, true)
    if (d30Result.modifier) {
      updatedDefenseRoll += d30Result.modifier
      if (d30Result.modifier > 0) {
        const msg = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"d30Bonus", actorName:defenderName, value:d30Result.modifier, side:"defense"})
        await ChatMessage.create({content: msg, speaker: ChatMessage.getSpeaker({actor: defender})})
      }
    }
    if (d30Result.specialEffect === "flag") {
      const msg = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"d30Flag", actorName:defenderName, specialName:d30Result.specialName || "Special Effect"})
      await ChatMessage.create({content: msg, speaker: ChatMessage.getSpeaker({actor: defender})})
    }
    if (d30Result.specialEffect === "drMultiplier") {
      defenseDrMultiplier = d30Result.multiplier
      const msg = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"d30DRMultiplier", actorName:defenderName, value:d30Result.multiplier})
      await ChatMessage.create({content: msg, speaker: ChatMessage.getSpeaker({actor: defender})})
    }
  }

  // Show the defense reaction dialog — while-loop for multiple reactions
  if (defender) {
    while (updatedDefenseRoll < attackRollFinal) {
      const shieldData = canShieldReact ? { label: shieldLabel, formula: shieldFormula, damageReduction: shieldDr } : null
      const buttons = buildDefenseReactionButtons(defender, { canRerollDefense: hasD30Reroll(defenseD30message), shieldData, canShieldReact, canAdHocShield: canAdHoc })

      const choice = await foundry.applications.api.DialogV2.wait({
        window: { title: "Defense reactions — attack boosted" },
        classes: ["lethalfantasy"],
        content: await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/dialogs/defense-reaction.hbs", {
          attackerName,
          attackRoll: attackRollFinal,
          attackStatus: "boosted attack to",
          defenderName,
          defenseRoll: updatedDefenseRoll,
          defenseStatus: "currently has",
          d30message: defenseD30message || null,
          offerText: "The attack was boosted! Choose how to improve the defense."
        }),
        buttons,
        rejectClose: false
      })

      if (!choice || choice === "continue") break

      if (choice === "grit") {
        const bonusRoll = await rollBonusDie("1d6", defender)
        updatedDefenseRoll += bonusRoll
        await defender.update({ "system.grit.current": Math.max(0, (Number(defender.system?.grit?.current) || 0) - 1) })
        const gritRmContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"grit", actorName:defenderName, resource:"Grit", value:bonusRoll, side:"defense"})
        await ChatMessage.create({content: gritRmContent, speaker: ChatMessage.getSpeaker({actor: defender})})
      } else if (choice === "luck") {
        const bonusRoll = await rollBonusDie("1d6", defender)
        updatedDefenseRoll += bonusRoll
        await defender.update({ "system.luck.current": Math.max(0, (Number(defender.system?.luck?.current) || 0) - 1) })
        const luckRmContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"luck", actorName:defenderName, resource:"Luck", value:bonusRoll, side:"defense"})
        await ChatMessage.create({content: luckRmContent, speaker: ChatMessage.getSpeaker({actor: defender})})
      } else if (choice === "bonusDie") {
        const bonusDie = await promptCombatBonusDie(defenderName, "attack", updatedDefenseRoll, attackRollFinal)
        if (bonusDie) {
          const bonusRoll = await rollBonusDie(bonusDie, defender)
          updatedDefenseRoll += bonusRoll
          const bonusRmContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"bonusDie", actorName:defenderName, formula:bonusDie.toUpperCase(), value:bonusRoll, side:"defense"})
          await ChatMessage.create({content: bonusRmContent, speaker: ChatMessage.getSpeaker({actor: defender})})
        }
      } else if (choice === "shieldReact" && canShieldReact) {
        const shieldBonus = await rollBonusDie(shieldFormula, defender)
        const newDefenseTotal = updatedDefenseRoll + shieldBonus
        updatedDefenseRoll = newDefenseTotal
        canShieldReact = false
        if (newDefenseTotal >= attackRollFinal) {
          shieldBlocked = true
          shieldReaction = { damageReduction: shieldDr, label: shieldLabel, bonus: shieldBonus }
          const shieldBlockContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"shieldBlock", actorName:defenderName, shieldLabel, shieldBonus, newTotal:newDefenseTotal, opposingRoll:attackRollFinal, shieldDR:shieldDr})
          await ChatMessage.create({
            content: shieldBlockContent,
            speaker: ChatMessage.getSpeaker({ actor: defender })
          })
        } else {
          const shieldFailContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"shieldFail", actorName:defenderName, shieldLabel, shieldBonus, newTotal:newDefenseTotal, opposingRoll:attackRollFinal})
          await ChatMessage.create({
            content: shieldFailContent,
            speaker: ChatMessage.getSpeaker({ actor: defender })
          })
        }
      } else if (choice === "rerollDefense" && defenseRerollContext) {
        const oldDefenseRoll = updatedDefenseRoll
        const reroll = await rerollConfiguredRoll(defenseRerollContext)
        if (!reroll) continue
        updatedDefenseRoll = reroll.options?.rollTotal || reroll.total || oldDefenseRoll
        let newD30message = reroll.options?.D30message || null
        try {
          const mulliganContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {
            type: "mulligan",
            actorName: defenderName,
            side: "defense",
            oldRoll: oldDefenseRoll,
            newRoll: updatedDefenseRoll,
            diceResults: reroll.options?.diceResults || [],
            D30result: reroll.options?.D30result,
            D30message: newD30message
          })
          await ChatMessage.create({content: mulliganContent, speaker: ChatMessage.getSpeaker({actor: defender})})
        } catch(e) {
          console.error("Mulligan message creation failed (non-fatal):", e)
        }
        // Process new D30 bonus dice from the reroll
        if (newD30message) {
          defenseD30message = newD30message
          const d30Result = await processD30BonusDice(defenseD30message, "defense", null, defender, true)
          if (d30Result.modifier) {
            updatedDefenseRoll += d30Result.modifier
            if (d30Result.modifier > 0) {
              const rmContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"d30Bonus", actorName:defenderName, value:d30Result.modifier, side:"defense"})
              await ChatMessage.create({content: rmContent, speaker: ChatMessage.getSpeaker({actor: defender})})
            }
          }
          if (d30Result.specialEffect === "flag") {
            const rmContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"d30Flag", actorName:defenderName, specialName:d30Result.specialName || "Special Effect"})
            await ChatMessage.create({content: rmContent, speaker: ChatMessage.getSpeaker({actor: defender})})
          }
          if (d30Result.specialEffect === "drMultiplier") {
            defenseDrMultiplier = d30Result.multiplier
            const rmContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"d30DRMultiplier", actorName:defenderName, value:d30Result.multiplier})
            await ChatMessage.create({content: rmContent, speaker: ChatMessage.getSpeaker({actor: defender})})
          }
        }
        continue
      } else if (choice === "adHocShield" && canAdHoc) {
        const adHoc = await promptAdHocShield(defenderName, attackRollFinal, updatedDefenseRoll)
        if (adHoc) {
          const shieldBonus = await rollBonusDie(adHoc.formula, defender)
          const newDefenseTotal = updatedDefenseRoll + shieldBonus
          updatedDefenseRoll = newDefenseTotal
          canShieldReact = false
          canAdHoc = false
          if (newDefenseTotal >= attackRollFinal) {
            shieldBlocked = true
            shieldReaction = { damageReduction: adHoc.damageReduction, label: `${adHoc.formula.toUpperCase()} shield`, bonus: shieldBonus }
            const adHocShieldBlockContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"shieldBlock", actorName:defenderName, shieldLabel: `${adHoc.formula.toUpperCase()} shield`, shieldBonus, newTotal:newDefenseTotal, opposingRoll:attackRollFinal, shieldDR:adHoc.damageReduction})
            await ChatMessage.create({
              content: adHocShieldBlockContent,
              speaker: ChatMessage.getSpeaker({ actor: defender })
            })
          } else {
            const adHocShieldFailContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"shieldFail", actorName:defenderName, shieldLabel: `${adHoc.formula.toUpperCase()} shield`, shieldBonus, newTotal:newDefenseTotal, opposingRoll:attackRollFinal})
            await ChatMessage.create({
              content: adHocShieldFailContent,
              speaker: ChatMessage.getSpeaker({ actor: defender })
            })
          }
        }
      }
    }
  }

  const finalShieldDR = shieldBlocked ? (shieldReaction?.damageReduction || 0) : 0
  const outcome = shieldBlocked ? "shielded-hit" : (updatedDefenseRoll >= attackRollFinal ? "miss" : "hit")

  await compareAttackDefense({
    attackerName,
    attackerId,
    attackRoll: attackRollFinal,
    attackWeaponId,
    attackRollType,
    attackRollKey,
    defenderName,
    defenderId,
    defenderTokenId,
    defenseRoll: updatedDefenseRoll,
    outcome,
    shieldDamageReduction: finalShieldDR,
    d30Bleed: d30Bleed || "",
    d30DamageMultiplier: d30DamageMultiplier || 1,
    d30DrMultiplier: (d30DrMultiplier != null && d30DrMultiplier !== 1) ? d30DrMultiplier : (defenseDrMultiplier ?? d30DrMultiplier ?? 1),
    damageTier: damageTier || "standard",
    attackD30message
  })
}

export async function showDefenseRequest(msg) {
  const attackerName = msg.attackerName
  const attackerId = msg.attackerId
  const defenderName = msg.defenderName
  const weaponName = msg.weaponName || "attack"
  const attackRoll = msg.attackRoll
  const attackWeaponId = msg.attackWeaponId
  const attackRollType = msg.attackRollType
  const attackRollKey = msg.attackRollKey
  const attackD30result = msg.attackD30result
  const attackD30message = msg.attackD30message
  const attackRerollContext = msg.attackRerollContext
  const d30AttackEffects = msg.d30AttackEffects
  const combatantId = msg.combatantId
  const tokenId = msg.tokenId

  // Récupérer le défenseur - essayer d'abord depuis le combat, puis depuis le token
  let defender = null

  if (game.combat && combatantId) {
    const combatant = game.combat.combatants.get(combatantId)
    if (combatant) {
      defender = combatant.actor
    }
  }

  // Si pas trouvé dans le combat, chercher le token directement
  if (!defender && tokenId) {
    const token = canvas.tokens.get(tokenId)
    if (token) {
      defender = token.actor
    }
  }

  if (!defender) {
    ui.notifications.error("Defender actor not found")
    return
  }

  // Resolve the specific token ID now while we still have combatant/token context.
  // This is passed through to the damage roll so the GM-side socket handler can find the
  // correct synthetic actor for unlinked tokens (avoids wrong-instance damage with multiple
  // unlinked copies of the same monster).
  const defenderTokenId = (() => {
    if (game.combat && combatantId) {
      const cbt = game.combat.combatants.get(combatantId)
      if (cbt?.token?.id) return cbt.token.id
    }
    return tokenId ?? canvas.tokens?.placeables?.find(t => t.actor?.id === defender.id)?.id ?? null
  })()

  const isMonster = defender.type === "monster"

  const _storeNextDefenseData = (opts = {}) => {
    game.lethalFantasy = game.lethalFantasy || {}
    game.lethalFantasy.nextDefenseData = {
      attackerId, attackRoll, attackerName, defenderName,
      attackWeaponId, attackRollType, attackRollKey,
      attackD30result, attackD30message, attackRerollContext,
      damageTier: msg.damageTier,
      defenderId: defender.id, defenderTokenId,
      ...(msg.attackNaturalRoll !== undefined && { attackNaturalRoll: msg.attackNaturalRoll }),
      ...(d30AttackEffects !== undefined && { d30AttackEffects }),
      ...(opts.isRanged !== undefined && { isRanged: opts.isRanged })
    }
  }

  log(`[LF] showDefenseRequest | attackRollType=${attackRollType} isMonster=${isMonster} defender=${defender?.name}`)

  // Spell/miracle attacks use saving throws instead of weapon defense
  const isSpellAttack = attackRollType === "spell-attack" || attackRollType === "miracle-attack"
  if (isSpellAttack) {
    const savesConfig = isMonster ? SYSTEM.MONSTER_SAVES : SYSTEM.SAVES
    const combatSaves = ["will", "dodge", "toughness"]
    const savesList = Object.values(savesConfig)
      .filter(s => combatSaves.includes(s.id))
      .map(s => ({id: s.id, label: game.i18n.localize(s.label)}))

    const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/dialogs/defense-request-save.hbs", {
      attackerName, defenderName, weaponName, attackRoll, saves: savesList
    })

    const result = await foundry.applications.api.DialogV2.wait({
      window: { title: "Saving Throw vs Spell" },
      classes: ["lethalfantasy"],
      content,
      buttons: [
        {
          action: "rollSave",
          type: "button",
          label: "Roll Save",
          icon: "fa-solid fa-person-running",
          callback: (event, button) => button.form.elements.saveKey.value,
        },
      ],
      rejectClose: false
    })

    if (result) {
      game.lethalFantasy = game.lethalFantasy || {}
      game.lethalFantasy.spellDefense = true // pré-cocher "Save against spell" dans le dialog
      _storeNextDefenseData()
      if (isMonster) {
        await defender.system.prepareMonsterRoll("save", result)
      } else {
        await defender.prepareRoll("save", result)
      }
    }
    return
  }

  // Pour les monstres, récupérer les attaques activées
  if (isMonster) {
    const attacksSet = defender.system.attackMode === "ranged" ? defender.system.rangedAttacks : defender.system.attacks
    const enabledAttacks = Object.entries(attacksSet).filter(([key, attack]) => attack.enabled)

    if (enabledAttacks.length === 0) {
      ui.notifications.warn("No enabled attacks available for defense")
      return
    }

    // Créer le contenu du dialogue pour monstre
    const attacksList = enabledAttacks.map(([key, attack]) => ({key, name: attack.name}))

    const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/dialogs/defense-request-monster.hbs", {
      attackerName, defenderName, weaponName, attackRoll, attacks: attacksList
    })

    // Afficher le dialogue
    const result = await foundry.applications.api.DialogV2.wait({
      window: { title: msg.isRanged ? "Ranged Defense Roll" : "Defense Roll" },
      classes: ["lethalfantasy"],
      content,
      buttons: [
        {
          action: "rangeDefense",
          type: "button",
          label: "Roll Defense",
          icon: "fa-solid fa-shield",
          callback: (event, button, dialog) => {
            const attackKey = button.form.elements.attackKey.value
            return attackKey
          },
        },
      ],
      rejectClose: false
    })

    // Si l'utilisateur a validé, lancer le jet de défense
    if (result) {
      _storeNextDefenseData({ isRanged: msg.isRanged })

      await defender.system.prepareMonsterRoll("monster-defense", result)
    }
    return
  }

  // Pour les personnages, récupérer les armes équipées
  // Si l'attaque est une attaque à distance, utiliser le dialogue de défense à distance
  if (msg.isRanged) {
    const { default: LethalFantasyRoll } = await import("../documents/roll.mjs")
    const roll = await LethalFantasyRoll.promptRangedDefense({
      actorId: defender.id,
      actorName: defender.name,
      actorImage: defender.img,
    })
    if (roll) {
      _storeNextDefenseData({ isRanged: true })
      await roll.toMessage({}, { messageMode: roll.options.rollMode })
    }
    return
  }

  // Pour les personnages, récupérer les armes équipées
  const equippedWeapons = defender.items.filter(i =>
    i.type === "weapon" && i.system.equipped === true
  )

  if (equippedWeapons.length === 0) {
    ui.notifications.warn("No equipped weapons for defense")
    return
  }

  // Créer le contenu du dialogue pour personnage
  const weaponsList = equippedWeapons.map(w => ({id: w.id, name: w.name}))

  const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/dialogs/defense-request-character.hbs", {
    attackerName, defenderName, weaponName, attackRoll, weapons: weaponsList
  })

  // Afficher le dialogue
  const result = await foundry.applications.api.DialogV2.wait({
    window: { title: "Defense Roll" },
    classes: ["lethalfantasy"],
    content,
    buttons: [
      {
        action: "defenseRoll",
        type: "button",
        label: "Roll Defense",
        icon: "fa-solid fa-shield",
        callback: (event, button, dialog) => {
          const weaponId = button.form.elements.weaponId.value
          return weaponId
        },
      },
    ],
    rejectClose: false
  })

  // Si l'utilisateur a validé, lancer le jet de défense
  if (result) {
    _storeNextDefenseData({ isRanged: msg.isRanged })

    log("Storing defense data for character:", defender.id)

    await defender.prepareRoll("weapon-defense", result)
  }
}

export function buildDefenseReactionButtons(defender, { canRerollDefense = false, shieldData = null, canShieldReact = false, canAdHocShield = false } = {}) {
  const currentGrit = Number(defender.system?.grit?.current) || 0
  const currentLuck = Number(defender.system?.luck?.current) || 0
  const buttons = []
  if (currentGrit > 0) {
    buttons.push({ action: "grit", type: "button", label: `Spend 1 Grit (+1D6) [${currentGrit} left]`, icon: "fa-solid fa-fist-raised", callback: () => "grit" })
  }
  if (currentLuck > 0) {
    buttons.push({ action: "luck", type: "button", label: `Spend 1 Luck (+1D6) [${currentLuck} left]`, icon: "fa-solid fa-clover", callback: () => "luck" })
  }
  buttons.push({ action: "bonusDie", type: "button", label: "Add bonus die", icon: "fa-solid fa-dice", callback: () => "bonusDie" })
  if (canRerollDefense) {
    buttons.push({ action: "rerollDefense", type: "button", label: "Re-roll defense (Mulligan)", icon: "fa-solid fa-rotate-right", callback: () => "rerollDefense" })
  }
  if (canShieldReact && shieldData) {
    buttons.push({ action: "shieldReact", type: "button", label: `Roll shield (${shieldData.label})`, icon: "fa-solid fa-shield", callback: () => "shieldReact" })
  } else if (canAdHocShield) {
    buttons.push({ action: "adHocShield", type: "button", label: "Roll ad-hoc shield (choose dice + DR)", icon: "fa-solid fa-shield-halved", callback: () => "adHocShield" })
  }
  buttons.push({ action: "continue", type: "button", label: "Continue (no defense bonus)", icon: "fa-solid fa-forward", callback: () => "continue" })
  return buttons
}

export function getCombatBonusDiceChoices() {
  return ["1d4", "1d6", "1d8", "1d10", "1d12", "1d20", "1d20e"]
}

export function getShieldReactionData(actor) {
  if (!actor) return null
  if (actor.type === "monster") {
    const formula = actor.system.combat?.shieldDefenseDice
    const damageReduction = actor.getShieldDR()
    if (!formula || damageReduction <= 0) return null
    return {
      label: game.i18n.localize("LETHALFANTASY.Label.shieldDefenseDice"),
      formula,
      damageReduction
    }
  }

  const equippedShields = actor.items.filter(item => item.type === "shield" && item.system.equipped)
  if (equippedShields.length === 0) return null

  const shield = equippedShields[0]
  return {
    label: shield.name,
    formula: shield.system.defense,
    damageReduction: actor.getShieldDR(),
    shieldId: shield.id
  }
}

export async function promptCombatBonusDie(actorName, sideLabel, currentRoll, opposingRoll) {
  const choicesList = getCombatBonusDiceChoices()
  const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/dialogs/bonus-die-select.hbs", {
    actorName, currentRoll, opposingRoll, sideLabel, choices: choicesList
  })

  return await foundry.applications.api.DialogV2.wait({
    window: { title: "Add Bonus Die" },
    classes: ["lethalfantasy"],
    content,
    buttons: [
      {
        action: "roll",
        type: "button",
        label: "Roll Bonus Die",
        icon: "fa-solid fa-dice",
        callback: (event, button) => {
          const sel = button.form?.elements?.bonusDie ?? button.closest("form")?.elements?.bonusDie
          return sel?.value ?? choicesList[0]
        }
      },
      {
        action: "cancel",
        type: "button",
        label: "Cancel",
        icon: "fa-solid fa-xmark",
        callback: () => null
      }
    ],
    rejectClose: false
  })
}

/**
 * Prompt the GM or player to choose an ad-hoc shield dice and DR value.
 * Used when the defender has no pre-configured shield equipment.
 * @param {string} defenderName
 * @param {number} attackRoll
 * @param {number} defenseRoll
 * @returns {Promise<{formula: string, damageReduction: number}|null>}
 */
export async function promptAdHocShield(defenderName, attackRoll, defenseRoll) {
  const choicesList = getCombatBonusDiceChoices()
  const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/dialogs/ad-hoc-shield.hbs", {
    defenderName, attackRoll, defenseRoll, choices: choicesList
  })

  const raw = await foundry.applications.api.DialogV2.wait({
    window: { title: "Ad-hoc Shield Roll" },
    classes: ["lethalfantasy"],
    content,
    buttons: [
      {
        action: "roll",
        type: "button",
        label: "Roll Shield",
        icon: "fa-solid fa-shield",
        callback: (event, button) => {
          const shieldDice = button.form?.elements?.shieldDice ?? button.closest("form")?.elements?.shieldDice
          const shieldDR = button.form?.elements?.shieldDR ?? button.closest("form")?.elements?.shieldDR
          return {
            formula: shieldDice?.value ?? "1d6",
            damageReduction: Number(shieldDR?.value) || 0
          }
        }
      },
      {
        action: "cancel",
        type: "button",
        label: "Cancel",
        icon: "fa-solid fa-xmark",
        callback: () => null
      }
    ],
    rejectClose: false
  })

  return raw ?? null
}

/**
 * Roll a bonus die formula, optionally showing Dice So Nice animation.
 * @param {string} formula
 * @param {Actor} actor
 * @returns {Promise<number>}
 */
export async function rollBonusDie(formula, actor) {
  const roll = new Roll(formula)
  await roll.evaluate()
  if (game?.dice3d) {
    await game.dice3d.showForRoll(roll, game.user, true)
  }
  return roll.total
}

export async function rerollConfiguredRoll(rerollContext = {}) {
  const RollClass = CONFIG.Dice.rolls.find(r => r.name === "LethalFantasyRoll")
  if (typeof RollClass?.prompt !== "function") {
    ui.notifications.error("Lethal Fantasy roll class not available for reroll")
    return null
  }

  return await RollClass.prompt({
    ...foundry.utils.duplicate(rerollContext),
    rollContext: foundry.utils.duplicate(rerollContext.rollContext || {}),
    hasTarget: false,
    target: false
  })
}

export async function offerAttackerGritBonus(attacker, currentAttackRoll, defenseRoll, attackerName, defenderName) {
  let totalBonus = 0
  let keepOffering = true

  while (keepOffering && currentAttackRoll + totalBonus <= defenseRoll) {
    const currentGrit = attacker.system.grit.current

    if (currentGrit <= 0) {
      break
    }

    const buttons = [
      {
        action: "grit",
        type: "button",
        label: `Spend 1 Grit (+1D6) [${currentGrit} left]`,
        icon: "fa-solid fa-fist-raised",
        callback: () => "grit"
      },
      {
        action: "continue",
        type: "button",
        label: "Continue (no bonus)",
        icon: "fa-solid fa-forward",
        callback: () => "continue"
      }
    ]

    const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/dialogs/attack-grit.hbs", {
      attackerName,
      currentAttackRollWithBonus: currentAttackRoll + totalBonus,
      defenderName,
      defenseRoll,
      totalBonus
    })

    const choice = await foundry.applications.api.DialogV2.wait({
      window: { title: "Attack with Grit" },
      classes: ["lethalfantasy"],
      content,
      buttons,
      rejectClose: false
    })

    if (!choice || choice === "continue") {
      keepOffering = false
      break
    }

    const bonusRoll = new Roll("1d6")
    await bonusRoll.evaluate()

    if (game?.dice3d) {
      await game.dice3d.showForRoll(bonusRoll, game.user, true)
    }

    totalBonus += bonusRoll.total

    await attacker.update({ "system.grit.current": currentGrit - 1 })
    const gritRm = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {type:"grit", actorName:attackerName, resource:"Grit", value:bonusRoll.total, side:"attack"})
    await ChatMessage.create({content: gritRm, speaker: ChatMessage.getSpeaker({actor: attacker})})
  }

  return totalBonus
}

export async function compareAttackDefense(data) {
  log("compareAttackDefense called with:", data)

  // Compute D30 effects from the attack D30 message directly.
  // This is more reliable than depending on the caller-provided values, which are
  // computed per-client and may differ between clients due to cross-client processing order.
  const d30DamageMultiplier = data.attackD30message?.type === "damage_multiplier"
    ? data.attackD30message.multiplier
    : (data.d30DamageMultiplier || 1)
  const d30Bleed = data.attackD30message?.type === "combo"
    ? (data.attackD30message.effects?.some(e => e.type === "bleed" || e.type === "internal_injury") ? "true" : "")
    : data.attackD30message?.type === "bleed" ? "true" : (data.d30Bleed || "")
  const d30DrMultiplier = data.d30DrMultiplier || 1

  const shieldDamageReduction = data.shieldDamageReduction || 0
  const outcome = data.outcome || (data.attackRoll > data.defenseRoll ? "hit" : "miss")
  const isAttackWin = outcome !== "miss"
  log("isAttackWin:", isAttackWin, "attackRoll:", data.attackRoll, "defenseRoll:", data.defenseRoll)

  let damageButton = ""
  if (isAttackWin && (data.attackWeaponId || data.attackRollKey)) {
    log("Creating damage button. defenderId:", data.defenderId)
    // Déterminer le type de dégâts à lancer
    if (data.attackRollType === "weapon-attack") {
      damageButton = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/damage-button.hbs", {
        type: "weapon",
        attackerId: data.attackerId,
        defenderId: data.defenderId,
        defenderTokenId: data.defenderTokenId || "",
        shieldDamageReduction: shieldDamageReduction,
        attackWeaponId: data.attackWeaponId,
        d30Bleed,
        d30DamageMultiplier,
        d30DrMultiplier
      })
    } else if (data.attackRollType === "monster-attack") {
      damageButton = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/damage-button.hbs", {
        type: "monster",
        attackerId: data.attackerId,
        defenderId: data.defenderId,
        defenderTokenId: data.defenderTokenId || "",
        shieldDamageReduction: shieldDamageReduction,
        attackRollKey: data.attackRollKey,
        d30Bleed,
        d30DamageMultiplier,
        d30DrMultiplier
      })
    } else if (data.attackRollType === "spell-attack" || data.attackRollType === "miracle-attack") {
      const attacker = game.actors.get(data.attackerId)
      const spell = attacker?.items.get(data.attackWeaponId || data.attackRollKey)
      const chosenTier = data.damageTier || "standard"
      const allTiers = [
        { id: "standard", formula: spell?.system?.damageDice, label: "Standard" },
        { id: "overpowered", formula: spell?.system?.damageDiceOverpowered, label: "Overpowered" },
        { id: "overpowered2", formula: spell?.system?.damageDiceOverpowered2, label: "Overpowered 2" },
      ]
      const tierData = allTiers.filter(t => t.id === chosenTier && t.formula).map(t => ({
        formula: Handlebars.escapeExpression(t.formula),
        label: t.label
      }))
      if (tierData.length) {
        damageButton = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/damage-button.hbs", {
          type: "spell",
          attackerId: data.attackerId,
          defenderId: data.defenderId,
          defenderTokenId: data.defenderTokenId || "",
          tiers: tierData,
          d30Bleed,
          d30DamageMultiplier,
          d30DrMultiplier
        })
      }
    }
  }

  const resultMessage = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/combat-result.hbs", {
    isAttackWin,
    outcome,
    attackerName: data.attackerName,
    defenderName: data.defenderName,
    attackRoll: data.attackRoll,
    defenseRoll: data.defenseRoll,
    shieldDamageReduction: shieldDamageReduction,
    damageButton
  })

  log("Creating combat result message...")
  await ChatMessage.create({
    content: resultMessage,
    speaker: { alias: "Combat System" }
  })
  log("Combat result message created!")
}

export async function applyDamage(message, event) {
  // Récupérer les données du message
  let combatantId = event.currentTarget.dataset.combatantId
  if (!combatantId) {
    ui.notifications.error("No combatant selected")
    return
  }

  // Try to find the target: first as a combat combatant, then as a scene token
  let targetActor = null
  if (game.combat) {
    const combatant = game.combat.combatants.get(combatantId)
    if (combatant) {
      targetActor = combatant.token?.actor || game.actors.get(combatant.actorId)
    }
  }
  if (!targetActor) {
    // Fall back to scene token lookup (non-combat tokens use tokenId as their combatantId)
    const token = canvas.tokens?.placeables?.find(t => t.id === combatantId)
    targetActor = token?.actor
  }
  if (!targetActor) {
    ui.notifications.error("Target actor not found")
    return
  }

  // Récupérer les données de dégâts du message
  // Use options.rollTotal (includes weapon modifier bonus) rather than roll.total (dice formula only)
  let damageTotal = message.rolls[0]?.options?.rollTotal ?? message.rolls[0]?.total ?? 0
  let weaponName = message.rolls[0]?.options?.rollName || "Unknown Weapon"

  // Calculer les DR
  let armorDR = targetActor.computeDamageReduction() || 0
  let shieldDR = targetActor.getShieldDR() || 0
  let totalDR = armorDR + shieldDR

  // Créer le dialogue
  const content = await foundry.applications.handlebars.renderTemplate(
    "systems/fvtt-lethal-fantasy/templates/apply-damage-dialog.hbs",
    {
      targetName: targetActor.name,
      weaponName: weaponName,
      damageTotal: damageTotal,
      armorDR: armorDR,
      shieldDR: shieldDR,
      totalDR: totalDR,
      damageNoDR: damageTotal,
      damageWithArmor: Math.max(0, damageTotal - armorDR),
      damageWithAll: Math.max(0, damageTotal - totalDR)
    }
  )

  const result = await foundry.applications.api.DialogV2.wait({
    window: { title: "Apply Damage" },
    classes: ["lethalfantasy"],
    position: { width: 280 },
    content,
    buttons: [
      {
        action: "noDR",
        type: "button",
        label: "No DR",
        callback: () => ({ drType: "none", damage: damageTotal })
      },
      {
        action: "armorDR",
        type: "button",
        label: "With Armor DR",
        callback: () => ({ drType: "armor", damage: Math.max(0, damageTotal - armorDR) })
      },
      {
        action: "allDR",
        type: "button",
        label: "With Armor + Shield DR",
        callback: () => ({ drType: "all", damage: Math.max(0, damageTotal - totalDR) })
      },
      {
        action: "cancel",
        type: "button",
        label: "Cancel",
        callback: () => null
      }
    ],
    rejectClose: false
  })

  if (result && result.damage !== undefined) {
    await targetActor.applyDamage(-result.damage)

    // Message de confirmation
    let drText = ""
    if (result.drType === "armor") {
      drText = `Armor DR: ${armorDR}`
    } else if (result.drType === "all") {
      drText = `Total DR: ${totalDR}`
    }

    const messageContent = await foundry.applications.handlebars.renderTemplate(
      "systems/fvtt-lethal-fantasy/templates/damage-applied-message.hbs",
      {
        targetName: targetActor.name,
        damage: result.damage,
        drText: drText,
        weaponName: weaponName
      }
    )

    await ChatMessage.create({
      user: game.user.id,
      speaker: { alias: targetActor.name },
      mode: "gm",
      content: messageContent
    })
  }
}
