import { YggdrasillUtility } from "../yggdrasill-utility.js"

const dureeGaldrSD = { "1d5a": 3, "1d10t": 6, "1d10m": 9, "1d10h": 12, "1d5j": 15}
const ciblesGaldrSD = { "1": 3, "2_4": 6, "5_9": 9, "10_49": 12, "50plus": 15}
const zonesciblesGaldrSD = { "INS10cm3": 3, "INS50cm3": 6, "INS1m3": 9, "INS5m3": 12, "INS10m3": 15}

/**
 * Dialogue de jet de dé pour Yggdrasill - Version DialogV2
 */
export class YggdrasillRollDialog {

  /**
   * Create and display the roll dialog
   * @param {YggdrasillActor} actor - The actor making the roll
   * @param {Object} rollData - Data for the roll
   * @returns {Promise}
   */
  static async create(actor, rollData) {
    // Initialiser attackData pour les armes si nécessaire
    if ((rollData.mode === "armecc" || rollData.mode === "armetir" || rollData.mode === "armedist") && rollData.attackDef) {
      // Les données sont déjà calculées dans attackDef par getAttaqueData/getTirData
      // On les copie simplement dans attackData pour le template
      rollData.attackData = { ...rollData.attackDef }
    }

    // Calculer srTotal pour les sorts
    if (rollData.mode === "galdr") {
      this._updateGaldrSD(rollData)
      rollData.srTotal = 14 + (rollData.sdGaldr || 0)
    } else if (rollData.mode === "sejdr") {
      rollData.srTotal = 14 + (rollData.bonusdefense || 0)
    } else if (rollData.mode === "rune") {
      this._updateRuneData(rollData, actor)
    }

    // Préparer le contexte pour le template
    const context = {
      ...rollData,
      img: actor.img,
      name: actor.name,
      config: game.system.yggdrasill.config,
    }

    // Titre selon le mode
    let title = "Test"
    if (rollData.mode === "competence") title = "Test de Compétence"
    else if (rollData.mode === "carac") title = "Test de Caractéristique"
    else if (rollData.mode === "attribut") title = "Test d'Attribut"
    else if (rollData.mode === "armecc") title = "Attaque au Corps à Corps"
    else if (rollData.mode === "armetir" || rollData.mode === "armedist") title = "Attaque à Distance"
    else if (rollData.mode === "sejdr") title = "Sort Sejdr"
    else if (rollData.mode === "galdr") title = "Sort Galdr"
    else if (rollData.mode === "rune") title = "Rune"

    // Rendre le template en HTML
    const content = await foundry.applications.handlebars.renderTemplate(
      "systems/fvtt-yggdrasill/templates/roll-dialog-generic-new.hbs",
      context
    )

    // Utiliser DialogV2.wait avec le HTML rendu
    return foundry.applications.api.DialogV2.wait({
      window: { 
        title: title,
        icon: "fa-solid fa-dice-d20" 
      },
      classes: ["yggdrasill-roll-dialog"],
      position: { width: 600 },
      modal: false,
      content,
      buttons: [
        {
          action: "roll",
          label: "Lancer le Test",
          icon: "fa-solid fa-dice",
          default: true,
          callback: (event, button, dialog) => {
            this._updateRollDataFromForm(rollData, button.form.elements, actor)
            this._performRoll(rollData)
          }
        },
      ],
      actions: {},
      render: (event, dialog) => {
        // Pour Galdr: recalculer srTotal quand durée, cibles ou zone changent
        if (rollData.mode === "galdr") {
          $("#dureeGaldr, #nbCibles, #zoneGaldr").on("change", () => {
            rollData.dureeGaldr = $("#dureeGaldr").val()
            rollData.nbCibles = $("#nbCibles").val()
            rollData.zoneGaldr = $("#zoneGaldr").val()
            this._updateGaldrSD(rollData)
            rollData.srTotal = 14 + (rollData.sdGaldr || 0)
            $("#srTotal").text(rollData.srTotal)
          })
        }

        // Pour armes : mettre à jour l'effet affiché quand le type d'attaque change
        if (rollData.mode === "armecc" || rollData.mode === "armetir" || rollData.mode === "armedist") {
          $("#typeAttack").on("change", () => {
            rollData.attackDef = rollData.attackDef || {}
            rollData.attackDef.typeAttack = $("#typeAttack").val()
            this._updateAttackData(rollData, actor)
            $("#attackDescr").text(rollData.attackData.description || "")
            $("#caracName").text(`${rollData.attackData.categName || ""} / ${rollData.attackData.caracName || ""}`)
            $("#malus").text(rollData.attackData.malus ?? 0)
          })
        }
        
        // Pour Sejdr: recalculer srTotal quand DM change
        if (rollData.mode === "sejdr") {
          $("#bonusdefense").on("change", () => {
            rollData.bonusdefense = parseInt($("#bonusdefense").val()) || 0
            rollData.srTotal = 14 + rollData.bonusdefense
            $("#srTotal").text(rollData.srTotal)
          })
        }
        
        // Pour Rune: recalculer srTotal quand support ou puissance changent
        if (rollData.mode === "rune") {
          $("#supportRune, #puissanceRune").on("change", () => {
            rollData.supportRune = $("#supportRune").val()
            rollData.puissanceRune = parseInt($("#puissanceRune").val()) || 1
            this._updateRuneData(rollData, actor)
            $("#runeDuree").text(rollData.runeDuree)
            $("#runeDureeVie").text(rollData.runeDureeVie)
            $("#srTotal").text(rollData.srTotal)
          })
        }
      },
      rejectClose: false,
    })
  }

  /**
   * Perform the roll based on mode
   * @param {Object} rollData - The roll data
   * @private
   */
  static _performRoll(rollData) {
    if (rollData.mode === "attribut") {
      YggdrasillUtility.rollAttribute(rollData)
    } else {
      YggdrasillUtility.rollYggdrasill(rollData)
    }
  }

  /**
   * Mettre à jour rollData avec les valeurs du formulaire
   * @param {Object} rollData - L'objet rollData à mettre à jour
   * @param {HTMLFormControlsCollection} formElements - Les éléments du formulaire
   * @param {YggdrasillActor} actor - L'acteur pour récupérer les données
   * @private
   */
  static _updateRollDataFromForm(rollData, formElements, actor) {
    // Caractéristique (pour compétences)
    if (formElements.caracName) {
      const caracKey = formElements.caracName.value
      rollData.caracName = caracKey
      rollData.selectedCarac = this._findCaracByKey(actor, caracKey)
    }

    // Type d'attaque (pour armes)
    if (formElements.typeAttack) {
      rollData.attackDef = rollData.attackDef || {}
      rollData.attackDef.typeAttack = formElements.typeAttack.value
      this._updateAttackData(rollData, actor)
    }

    // Bonus/Malus
    if (formElements.bonusMalus) {
      rollData.bonusMalus = parseInt(formElements.bonusMalus.value) || 0
    }

    // Furor
    if (formElements.furorUsage) {
      rollData.furorUsage = parseInt(formElements.furorUsage.value) || 0
    }

    // Seuil de Réussite
    if (formElements.sr) {
      rollData.sr = parseInt(formElements.sr.value) || 9
    }

    // Galdr options
    if (formElements.dureeGaldr) {
      rollData.dureeGaldr = formElements.dureeGaldr.value
    }
    if (formElements.nbCibles) {
      rollData.nbCibles = formElements.nbCibles.value
    }
    if (formElements.zoneGaldr) {
      rollData.zoneGaldr = formElements.zoneGaldr.value
    }
    if (rollData.mode === "galdr") {
      this._updateGaldrSD(rollData)
      rollData.srTotal = 14 + (rollData.sdGaldr || 0)
    }

    // Sejdr options
    if (formElements.bonusdefense) {
      rollData.bonusdefense = parseInt(formElements.bonusdefense.value) || 0
    }
    if (rollData.mode === "sejdr") {
      rollData.srTotal = 14 + (rollData.bonusdefense || 0)
    }

    // Rune options
    if (formElements.runeDuree) {
      rollData.runeDuree = formElements.runeDuree.value
    }
  }

  /**
   * Find characteristic by key in actor
   * @param {YggdrasillActor} actor
   * @param {String} caracKey
   * @returns {Object}
   * @private
   */
  static _findCaracByKey(actor, caracKey) {
    for (let [categKey, categ] of Object.entries(actor.system.carac)) {
      for (let [key, carac] of Object.entries(categ.carac)) {
        if (key === caracKey) {
          return { ...carac, categName: categKey, caracName: key }
        }
      }
    }
    return null
  }

  /**
   * Update attack data based on attack type
   * @param {Object} rollData
   * @param {YggdrasillActor} actor
   * @private
   */
  static _updateAttackData(rollData, actor) {
    const attackType = rollData.attackDef.typeAttack

    let attackData
    if (rollData.mode === "armecc") {
      attackData = actor.getAttaqueData(attackType)
    } else {
      attackData = actor.getTirData(attackType)
    }

    if (attackData) {
      rollData.attackDef = { ...rollData.attackDef, ...attackData }
      rollData.attackData = { ...rollData.attackDef }
      // Mettre à jour la caractéristique utilisée pour le jet (nbDice)
      rollData.selectedCarac = attackData.carac
    }
  }

  /**
   * Compute value from string formula like "puissance;3"
   * @param {String|Number} value
   * @param {YggdrasillActor} actor
   * @returns {Number}
   * @private
   */
  static _computeValue(value, actor) {
    if (typeof value === 'number') return value
    if (!value || value === "0") return 0
    
    const parts = String(value).split(';')
    if (parts.length === 2) {
      const caracName = parts[0]
      const multiplier = parseInt(parts[1]) || 1
      const caracValue = this._getCaracValue(actor, caracName)
      return caracValue * multiplier
    }
    return 0
  }

  /**
   * Get characteristic value by name
   * @param {YggdrasillActor} actor
   * @param {String} caracName
   * @returns {Number}
   * @private
   */
  static _getCaracValue(actor, caracName) {
    for (let categ of Object.values(actor.system.carac)) {
      if (categ.carac && categ.carac[caracName]) {
        return categ.carac[caracName].value || 0
      }
    }
    return 0
  }

  /**
   * Update rune data based on support and power
   * @param {Object} rollData
   * @param {YggdrasillActor} actor
   * @private
   */
  static _updateRuneData(rollData, actor) {
    let support = 0
    
    rollData.dureeRune = 6 - (rollData.agiliteCarac?.value || 0)
    
    if (rollData.supportRune === "peau") {
      support = 3
      rollData.echelleDuree = "Actions"
      rollData.echelleDureeVie = "Heures"
    } else if (rollData.supportRune === "tissu") {
      support = 6
      rollData.echelleDuree = "Tours"
      rollData.echelleDureeVie = "Jours"
    } else if (rollData.supportRune === "cuir") {
      support = 9
      rollData.echelleDuree = "Minutes"
      rollData.echelleDureeVie = "Semaines"
    } else if (rollData.supportRune === "bois") {
      support = 12
      rollData.echelleDuree = "Heures"
      rollData.echelleDureeVie = "Mois"
    } else if (rollData.supportRune === "pierremetal") {
      support = 15
      rollData.echelleDuree = "Jours"
      rollData.echelleDureeVie = "Années"
    }
    
    rollData.runeDuree = `${rollData.dureeRune} ${rollData.echelleDuree}`
    rollData.runeDureeVie = `${rollData.competence?.system.niveau || 1} ${rollData.echelleDureeVie}`
    rollData.srTotal = (rollData.puissanceRune || 1) + (Number(rollData.sort?.system.niveau || 0) * 3) + support
  }

  /**
   * Update Galdr SD based on duration and targets
   * @param {Object} rollData
   * @private
   */
  static _updateGaldrSD(rollData) {
    let sdDuree = Number(dureeGaldrSD[rollData.dureeGaldr]) || 0
    let sdVar = 0
    
    if (rollData.sort?.system.voie === "illusion") {
      sdVar = Number(zonesciblesGaldrSD[rollData.zoneGaldr]) || 0
    } else {
      sdVar = Number(ciblesGaldrSD[rollData.nbCibles]) || 0
    }
    
    rollData.sdGaldr = sdDuree + sdVar
  }
}
