import { RollDataAjustements } from "./rolldata-ajustements-v1.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemSort } from "./item-sort.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
import { CARACS, RdDCarac } from "./rdd-carac.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { Grammar } from "./grammar.js";
import { ACTOR_TYPES, RDD_CONFIG, renderTemplate } from "./constants.js";
import { EMPOIGNADE } from "./item/arme.js";

export class RdDRoll extends foundry.applications.api.DialogV2 {
  static async create(actor, rollData, dialogConfig, action) {
    RdDRoll._ensureCorrectAction(action)
    RdDRoll._setDefaultOptions(actor, rollData)
    const content = await renderTemplate(dialogConfig.html, rollData)
    const options = { classes: ["rdd-roll-dialog"], width: 650, height: "fit-content" }
    return new RdDRoll(actor, rollData, content, options, action)
  }

  static _setDefaultOptions(actor, rollData) {
    let defaultRollData = {
      alias: actor.getAlias(),
      ajustementsConditions: CONFIG.RDD.ajustementsConditions,
      difficultesLibres: CONFIG.RDD.difficultesLibres,
      etat: actor.getEtatGeneral(),
      moral: actor.getMoralTotal(),
      amoureux: actor.listeAmoureux(),
      carac: foundry.utils.deepClone(actor.system.carac),
      finalLevel: 0,
      diffConditions: 0,
      diffLibre: rollData.competence?.system.default_diffLibre ?? 0,
      perteMoralEchec: false,
      use: {
        astrologique: true,
        moral: false,
        libre: true,
        coeur: undefined,
        conditions: true,
        surenc: actor.isSurenc(),
        encTotal: true
      },
      isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence?.name),
      encTotal: actor.getEncTotal(),
      ajustementAstrologique: actor.ajustementAstrologique(),
      surprise: actor.getSurprise(false),
      canClose: true,
      isGM: game.user.isGM,
      forceDiceResult: -1
    }
    if (actor.type == ACTOR_TYPES.personnage) {
      defaultRollData.carac[CARACS.REVE_ACTUEL] = actor.system.reve.reve
    }
    foundry.utils.mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false })
    if (rollData.forceCarac) {
      rollData.carac = rollData.forceCarac
    }
    rollData.diviseurSignificative = RdDRoll.getDiviseurSignificative(rollData)
    RollDataAjustements.calcul(rollData, actor)
  }

  static getDiviseurSignificative(rollData) {
    let facteurSign = 1
    if (rollData.surprise == "demi") facteurSign *= 2
    if (rollData.needParadeSignificative) facteurSign *= 2
    if (RdDBonus.isDefenseAttaqueFinesse(rollData)) facteurSign *= 2
    if (!ReglesOptionnelles.isUsing("tripleSignificative")) facteurSign = Math.min(facteurSign, 4)
    return facteurSign
  }

  static _ensureCorrectAction(action) {
    if (action.callbacks == undefined) {
      console.warn("No callback defined for ", action.name)
      action.callbacks = [{ action: r => console.warn(action.name, r) }]
    }
  }

  constructor(actor, rollData, content, options, action) {
    super(foundry.utils.mergeObject(options, {
      title: action.label,
      content,
      tag: "div",
      buttons: [
        { label: action.label, action: "onAction", callback: () => { this.rollData.canClose = true; this.onAction(action) } }
      ]
    }))
    this.actor = actor
    this.rollData = rollData
  }

  async _onFirstRender(context, options) {
    // DialogV2._onFirstRender calls this.element.show() which fails in V14
    // because this.element is HTMLElement (not jQuery). Override to use native DOM.
    if (this.options.modal && typeof this.element.showModal === 'function') {
      this.element.showModal();
    } else if (this.element?.style) {
      if (this.element.style.display === 'none') this.element.style.removeProperty('display');
      this.element.classList.remove('hidden');
    }
  }

  _onRender(context) {
    super._onRender(context)
    this.bringToFront()
    console.log("RdDRoll._onRender", this.rollData)
    const el = this.element
    if (!this.rollData.selectedCarac && this.rollData.competence) {
      this.rollData.selectedCarac = this.rollData.carac[this.actor.mapCarac(this.rollData.competence.system.defaut_carac)]
    }
    if (this.rollData.selectedCarac) {
      const caracEl = el.querySelector("[name='carac']")
      if (caracEl) {
        caracEl.value = RdDCarac.caracDetails(this.rollData.selectedCarac.label, { onMessage: () => {} })?.code
          ?? this.rollData.selectedCarac.code
          ?? Grammar.toLowerCaseNoAccentNoSpace(this.rollData.selectedCarac.label)
      }
    }
    if (this.rollData.selectedSort) {
      this.setSelectedSort(this.rollData.selectedSort)
      const dracEl = el.querySelector(".draconic")
      if (dracEl) dracEl.value = this.rollData.selectedSort.system.listIndex
    }
    RdDItemSort.setCoutReveReel(this.rollData.selectedSort)
    const dl = el.querySelector("[name='diffLibre']")
    if (dl) dl.value = Misc.toInt(this.rollData.diffLibre)
    const dc = el.querySelector("[name='diffConditions']")
    if (dc) dc.value = Misc.toInt(this.rollData.diffConditions)
    this.updateRollResult()

    el.querySelector("[name='diffLibre']")?.addEventListener("change", event => {
      this.rollData.diffLibre = Misc.toInt(event.currentTarget.value)
      this.updateRollResult()
    })
    el.querySelector("[name='diffConditions']")?.addEventListener("change", event => {
      this.rollData.diffConditions = Misc.toInt(event.currentTarget.value)
      this.updateRollResult()
    })
    el.querySelector("[name='force-dice-result']")?.addEventListener("change", event => {
      this.rollData.forceDiceResult = Misc.toInt(event.currentTarget.value)
    })
    el.querySelector("[name='carac']")?.addEventListener("change", event => {
      this.rollData.selectedCarac = this.rollData.carac[event.currentTarget.value]
      this.updateRollResult()
    })
    el.querySelector(".roll-draconic")?.addEventListener("change", event => {
      this.rollData.competence = this.rollData.draconicList[Misc.toInt(event.currentTarget.value)]
      this.updateRollResult()
    })
    el.querySelector(".roll-sort")?.addEventListener("change", event => {
      this.setSelectedSort(this.rollData.sortList[Misc.toInt(event.currentTarget.value)])
      this.updateRollResult()
      const dl2 = el.querySelector("[name='diffLibre']")
      if (dl2) dl2.value = this.rollData.diffLibre
    })
    el.querySelector(".roll-text")?.addEventListener("change", event => {
      this.rollData.competence = this.rollData.competences.find(it => Grammar.equalsInsensitive(it.name, event.currentTarget.value))
      this.updateRollResult()
    })
    el.querySelector(".select-suivant-coeur")?.addEventListener("change", event => {
      const selectedActorId = event.currentTarget.value
      this.rollData.use.coeur = this.actor.getSuivant(selectedActorId)
      if (this.rollData.use.coeur) {
        const img = el.querySelector(".utilisation-coeur img.selected-suivant-coeur")
        if (img) {
          img.src = this.rollData.use.coeur?.img
          img.title = this.rollData.use.coeur?.name
        }
      }
      this.updateRollResult()
    })
    el.querySelector(".roll-signedraconique")?.addEventListener("change", event => {
      this.setSelectedSigneDraconique(this.rollData.signes[Misc.toInt(event.currentTarget.value)])
      this.updateRollResult()
    })
    el.querySelector("[name='ptreve-variable']")?.addEventListener("change", event => {
      this.rollData.selectedSort.system.ptreve_reel = Misc.toInt(event.currentTarget.value)
      console.log("RdDRollSelectDialog - Cout reve", this.rollData.selectedSort.system.ptreve_reel)
      this.updateRollResult()
    })
    el.querySelector("input.check-mortalite")?.addEventListener("change", event => {
      this.rollData.dmg.mortalite = event.currentTarget.checked ? RDD_CONFIG.encaissement.nonmortel : RDD_CONFIG.encaissement.mortel
      this.updateRollResult()
    })
    el.querySelector(".cuisine-proportions")?.addEventListener("change", event => {
      this.rollData.proportions = Number(event.currentTarget.value)
      this.updateRollResult()
    })
    el.querySelectorAll(".select-by-name").forEach(input =>
      input.addEventListener("change", event => {
        this.rollData[event.currentTarget.name] = event.currentTarget.value
        this.updateRollResult()
      })
    )
    el.querySelectorAll(".checkbox-by-name").forEach(input =>
      input.addEventListener("change", event => {
        this.rollData[event.currentTarget.name] = event.currentTarget.checked
        this.updateRollResult()
      })
    )
    el.querySelectorAll("input.use-astrologique").forEach(input =>
      input.addEventListener("change", event => {
        this.rollData.use.astrologique = event.currentTarget.checked
        this.updateRollResult()
      })
    )
    el.querySelectorAll("input.use-encTotal").forEach(input =>
      input.addEventListener("change", event => {
        this.rollData.use.encTotal = event.currentTarget.checked
        this.updateRollResult()
      })
    )
    el.querySelectorAll("input.use-surenc").forEach(input =>
      input.addEventListener("change", event => {
        this.rollData.use.surenc = event.currentTarget.checked
        this.updateRollResult()
      })
    )
    el.querySelector(".appel-moral")?.addEventListener("click", () => {
      this.rollData.use.moral = !this.rollData.use.moral
      const icon = el.querySelector(".icon-appel-moral")
      const tooltip = el.querySelector(".tooltipAppelAuMoralText")
      if (this.rollData.use.moral) {
        if (this.rollData.moral > 0) {
          if (tooltip) tooltip.innerHTML = "Appel au moral"
          if (icon) icon.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-heureux.svg"
        } else {
          if (tooltip) tooltip.innerHTML = "Appel à l'énergie du désespoir"
          if (icon) icon.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-malheureux.svg"
        }
      } else {
        if (tooltip) tooltip.innerHTML = "Sans appel au moral"
        if (icon) icon.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-neutre.svg"
      }
      this.updateRollResult()
    })
    el.querySelectorAll(".conditionMeditation").forEach(input =>
      input.addEventListener("change", event => {
        this.rollData.conditionMeditation[event.currentTarget.name] = event.currentTarget.checked
        this.updateRollResult()
      })
    )
  }

  close() {
    if (this.rollData.canClose) {
      return super.close()
    }
    ui.notifications.info("Vous devez faire ce jet de dés!")
  }

  async onAction(action) {
    const el = this.element
    this.rollData.forceDiceResult = Number.parseInt(el.querySelector("[name='force-dice-result']")?.value) ?? -1
    await RdDResolutionTable.rollData(this.rollData)
    for (let callback of action.callbacks) {
      await callback.action(this.rollData)
    }
  }

  async setSelectedSort(sort) {
    this.rollData.selectedSort = sort
    this.rollData.competence = RdDItemSort.getBestDraconicSort(this.rollData.draconicList, sort)
    this.rollData.bonus = RdDItemSort.getCaseBonus(sort, this.rollData.tmr.coord, this.actor)
    this.rollData.diffLibre = RdDItemSort.getDifficulte(sort, -7)
    RdDItemSort.setCoutReveReel(sort)
    const descHtml = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.hbs", { sort })
    const el = this.element
    const sortEl = el.querySelector(".sort-ou-rituel")
    if (sortEl) sortEl.textContent = sort.system.isrituel ? "rituel" : "sort"
    const bonusEl = el.querySelector(".bonus-case")
    if (bonusEl) bonusEl.textContent = `${this.rollData.bonus}%`
    const descPlace = el.querySelector(".placeholder-description-sort")
    if (descPlace) descPlace.innerHTML = descHtml
    const dracEl = el.querySelector(".roll-draconic")
    if (dracEl) dracEl.value = sort.system.listIndex
    const diffFixe = el.querySelector(".div-sort-difficulte-fixe")
    if (diffFixe) diffFixe.textContent = Misc.toSignedString(sort.system.difficulte)
    const ptFixe = el.querySelector(".div-sort-ptreve-fixe")
    if (ptFixe) ptFixe.textContent = sort.system.ptreve
    const diffVariable = RdDItemSort.isDifficulteVariable(sort)
    const coutVariable = RdDItemSort.isCoutVariable(sort)
    const show = (sel, v) => { const e = el.querySelector(sel); if (e) HtmlUtility.showControlWhen(e, v) }
    show(".div-sort-non-rituel", !sort.system.isrituel)
    show(".div-sort-difficulte-var", diffVariable)
    show(".div-sort-difficulte-fixe", !diffVariable)
    show(".div-sort-ptreve-var", coutVariable)
    show(".div-sort-ptreve-fixe", !coutVariable)
  }

  async setSelectedSigneDraconique(signe) {
    this.rollData.signe = signe
    this.rollData.diffLibre = signe.system.difficulte
    const sd = this.element.querySelector(".signe-difficulte")
    if (sd) sd.textContent = Misc.toSignedString(this.rollData.diffLibre)
  }

  async updateRollResult() {
    const rollData = this.rollData
    rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor)
    rollData.caracValue = parseInt(rollData.selectedCarac.value)
    rollData.dmg.mortalite = rollData.dmg.mortalite ?? "mortel"
    rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac?.label)
    RollDataAjustements.calcul(rollData, this.actor)
    const resolutionTable = await RdDResolutionTable.buildHTMLTable(RdDResolutionTable.subTable(rollData.caracValue, rollData.finalLevel))
    const adjustements = await this.buildAjustements(rollData)
    const el = this.element
    const show = (sel, v) => { const e = el.querySelector(sel); if (e) HtmlUtility.showControlWhen(e, v) }
    show(".use-encTotal", rollData.ajustements.encTotal.visible && RdDCarac.isAgiliteOuDerobee(rollData.selectedCarac?.label))
    show(".use-surenc", rollData.ajustements.surenc.visible && RdDCarac.isActionPhysique(rollData.selectedCarac?.label))
    show(".use-astrologique", rollData.ajustements.astrologique.visible)
    show(".utilisation-moral", rollData.use.appelAuMoral)
    show(".divAppelAuMoral", rollData.use.appelAuMoral)
    show(".utilisation-coeur", rollData.ajustements.coeur.visible)
    show(".utilisation-coeur img.selected-suivant-coeur", rollData.ajustements.coeur.visible && rollData.use.coeur != undefined)
    const titleEl = el.querySelector(".dialog-roll-title")
    if (titleEl) titleEl.textContent = this._getTitle(rollData)
    const mortEl = el.querySelector("input.check-mortalite")
    if (mortEl) mortEl.checked = rollData.dmg.mortalite == RDD_CONFIG.encaissement.nonmortel
    const dmgLabel = el.querySelector("label.dmg-arme-actor")
    if (dmgLabel) dmgLabel.textContent = rollData.dmg.isEmpoignade ? EMPOIGNADE : Misc.toSignedString(rollData.dmg.total)
    const mortLabel = el.querySelector("label.arme-mortalite")
    if (mortLabel) mortLabel.textContent = rollData.dmg.mortalite
    const ajPlace = el.querySelector("div.placeholder-ajustements")
    if (ajPlace) ajPlace.innerHTML = adjustements
    const resPlace = el.querySelector("div.placeholder-resolution")
    if (resPlace) resPlace.innerHTML = resolutionTable
  }

  async buildAjustements(rollData) {
    return await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.hbs", rollData)
  }

  _getTitle(rollData) {
    const alias = rollData.alias
    const carac = rollData.selectedCarac.label
    if (!rollData.competence) return `${alias}: ${carac}`
    const compName = rollData.competence.name
    const niveau = Misc.toSignedString(rollData.competence.system.niveau)
    if (compName == carac) return `${alias}: ${carac} Niveau ${niveau}`
    if (rollData.draconicList && rollData.selectedSort) return `${alias}: ${rollData.competence.name} Niveau ${niveau} ${rollData.selectedSort.name}`
    if (rollData.arme && rollData.arme.name != compName) return `${alias}: ${carac} / ${compName} (${rollData.arme.name}) Niveau ${niveau}`
    return `${alias}: ${carac} / ${compName} Niveau ${niveau}`
  }
}
