import { SYSTEM } from "../config/system.mjs"
import { prompt } from "./roll-prompt.mjs"
import { promptInitiative, promptCombatAction, promptRangedDefense, promptRangedAttack } from "./roll-combat.mjs"
import { rollSpellDamageToMessage } from "./roll-damage.mjs"

export default class LethalFantasyRoll extends Roll {
  /**
   * The HTML template path used to render dice checks of this type
   * @type {string}
   */
  static CHAT_TEMPLATE = "systems/fvtt-lethal-fantasy/templates/chat-message.hbs"

  get type() {
    return this.options.type
  }

  get titleFormula() {
    return this.options.titleFormula
  }

  get rollName() {
    return this.options.rollName
  }

  get target() {
    return this.options.target
  }

  get value() {
    return this.options.value
  }

  get treshold() {
    return this.options.treshold
  }

  get actorId() {
    return this.options.actorId
  }

  get actorName() {
    return this.options.actorName
  }

  get actorImage() {
    return this.options.actorImage
  }

  get modifier() {
    return this.options.modifier
  }

  get resultType() {
    return this.options.resultType
  }

  get isFailure() {
    return this.resultType === "failure"
  }

  get hasTarget() {
    return this.options.hasTarget
  }

  get targetName() {
    return this.options.targetName
  }

  get targetArmor() {
    return this.options.targetArmor
  }

  get targetMalus() {
    return this.options.targetMalus
  }

  get realDamage() {
    return this.options.realDamage
  }

  get rollTotal() {
    return this.options.rollTotal
  }

  get diceResults() {
    return this.options.diceResults
  }

  get rollTarget() {
    return this.options.rollTarget
  }

  get D30result() {
    return this.options.D30result
  }

  get D30message() {
    return this.options.D30message
  }

  get badResult() {
    return this.options.badResult
  }

  get rollData() {
    return this.options.rollData
  }

  get defenderId() {
    return this.options.defenderId
  }

  /**
   * Creates a title based on the given type.
   *
   * @param {string} type The type of the roll.
   * @param {string} target The target of the roll.
   * @returns {string} The generated title.
   */
  static createTitle(type, target) {
    switch (type) {
      case "challenge":
        return `${game.i18n.localize("LETHALFANTASY.Label.titleChallenge")}`
      case "save":
        return `${game.i18n.localize("LETHALFANTASY.Label.titleSave")}`
      case "monster-skill":
      case "skill":
        return `${game.i18n.localize("LETHALFANTASY.Label.titleSkill")}`
      case "weapon-attack":
        return `${game.i18n.localize("LETHALFANTASY.Label.weapon-attack")}`
      case "weapon-defense":
        return `${game.i18n.localize("LETHALFANTASY.Label.weapon-defense")}`
      case "weapon-damage":
        return `${game.i18n.localize("LETHALFANTASY.Label.weapon-damage")}`
      case "spell":
      case "spell-attack":
      case "spell-power":
        return `${game.i18n.localize("LETHALFANTASY.Label.spell")}`
      case "miracle":
      case "miracle-attack":
      case "miracle-power":
        return `${game.i18n.localize("LETHALFANTASY.Label.miracle")}`
      default:
        return game.i18n.localize("LETHALFANTASY.Label.titleStandard")
    }
  }

  /** @override */
  async render(chatOptions = {}) {
    let chatData = await this._getChatCardData(chatOptions.isPrivate)
    log("ChatData", chatData)
    return await foundry.applications.handlebars.renderTemplate(this.constructor.CHAT_TEMPLATE, chatData)
  }

  /*
   * Generates the data required for rendering a roll chat card.
   */
  async _getChatCardData(isPrivate) {
    // Générer la liste des combatants de la scène
    let combatants = []
    let isAttack = this.type === "weapon-attack" || this.type === "monster-attack" || this.type === "spell-attack" || this.type === "miracle-attack"
    if (this.rollData?.isDamage || isAttack) {
      // D'abord, ajouter les combattants du combat actif
      const defeatedTokenIds = new Set()
      if (game?.combat?.combatants) {
        for (let c of game.combat.combatants) {
          if (c.actorId !== this.actorId && !c.isDefeated) {
            combatants.push({ id: c.id, name: c.name, tokenId: c.token.id })
          }
          if (c.isDefeated && c.token?.id) {
            defeatedTokenIds.add(c.token.id)
          }
        }
      }

      // Ensuite, ajouter tous les tokens de la scène active qui ne sont pas déjà dans la liste
      if (canvas?.scene?.tokens) {
        const existingTokenIds = new Set(combatants.map(c => c.tokenId))
        for (let token of canvas.scene.tokens) {
          if (token.actorId !== this.actorId && !existingTokenIds.has(token.id) && !defeatedTokenIds.has(token.id)) {
            // Skip dead monsters (0 HP). Use token.actor for unlinked tokens.
            const tokenActor = token.actor ?? game.actors.get(token.actorId)
            if (tokenActor?.type === "monster" && (Number(tokenActor?.system?.hp?.value) || 0) <= 0) continue
            combatants.push({
              id: token.id,
              name: token.name,
              tokenId: token.id
            })
          }
        }
      }
    }

    // Récupérer les informations de l'arme pour les attaques réussies
    let weaponDamageOptions = null
    log("Roll type:", this.type, "rollTarget:", this.rollTarget, "Has weapon:", !!this.rollTarget?.weapon)
    if (this.type === "weapon-attack" && this.rollTarget?.weapon) {
      const weapon = this.rollTarget.weapon
      weaponDamageOptions = {
        weaponId: weapon._id || weapon.id,
        weaponName: weapon.name,
        damageM: weapon.system?.damage?.damageM
      }
      log("Weapon damage options:", weaponDamageOptions)
    } else if (this.type === "monster-attack" && this.rollTarget) {
      weaponDamageOptions = {
        weaponId: this.rollTarget.rollKey,
        weaponName: this.rollTarget.name,
        damageFormula: this.rollTarget.damageDice,
        damageModifier: this.rollTarget.damageModifier,
        isMonster: true
      }
      log("Monster damage options:", weaponDamageOptions)
    }

    const cardData = {
      css: [SYSTEM.id, "dice-roll"],
      data: this.data,
      diceTotal: this.dice.reduce((t, d) => t + d.total, 0),
      isGM: game.user.isGM,
      formula: this.formula,
      titleFormula: this.titleFormula,
      rollName: this.rollName,
      rollType: this.type,
      rollTarget: this.rollTarget,
      total: this.rollTotal,
      isFailure: this.isFailure,
      actorId: this.actorId,
      diceResults: this.diceResults,
      actingCharName: this.actorName,
      actingCharImg: this.actorImage,
      resultType: this.resultType,
      hasTarget: this.hasTarget,
      targetName: this.targetName,
      targetArmor: this.targetArmor,
      D30result: this.D30result,
      D30message: this.D30message,
      badResult: this.badResult,
      rollData: this.rollData,
      isPrivate: isPrivate,
      combatants: combatants,
      weaponDamageOptions: weaponDamageOptions,
      isAttack: isAttack,
      defenderId: this.defenderId,
      // Vérifier si l'utilisateur peut sélectionner une cible (est GM ou possède l'acteur)
      canSelectTarget: game.user.isGM || game.actors.get(this.actorId)?.testUserPermission(game.user, "OWNER")
    }
    cardData.cssClass = cardData.css.join(" ")
    cardData.tooltip = isPrivate ? "" : await this.getTooltip()
    return cardData
  }

  /**
   * Converts the roll result to a chat message.
   *
   * @param {Object} [messageData={}] Additional data to include in the message.
   * @param {Object} options Options for message creation.
   * @param {string} options.messageMode The mode of the roll (e.g., public, private).
   * @param {boolean} [options.create=true] Whether to create the message.
   * @returns {Promise} - A promise that resolves when the message is created.
   */
  async toMessage(messageData = {}, { messageMode, create = true } = {}) {
    return await super.toMessage(
      {
        isSave: this.isSave,
        isChallenge: this.isChallenge,
        isFailure: this.resultType === "failure",
        rollType: this.type,
        rollTarget: this.rollTarget,
        actingCharName: this.actorName,
        actingCharImg: this.actorImage,
        hasTarget: this.hasTarget,
        targetName: this.targetName,
        targetArmor: this.targetArmor,
        targetMalus: this.targetMalus,
        realDamage: this.realDamage,
        rollData: this.rollData,
        ...messageData,
      },
      { messageMode, create },
    )
  }
}

// Attach imported prompt methods
LethalFantasyRoll.prompt = prompt
LethalFantasyRoll.promptInitiative = promptInitiative
LethalFantasyRoll.promptCombatAction = promptCombatAction
LethalFantasyRoll.promptRangedDefense = promptRangedDefense
LethalFantasyRoll.promptRangedAttack = promptRangedAttack
LethalFantasyRoll.rollSpellDamageToMessage = rollSpellDamageToMessage
