import { MournbladeUtility } from "../mournblade-utility.js"

export default class MournbladeInvocationDemonDialog {

  /**
   * Normalize a string for fuzzy matching: lowercase, remove diacritics,
   * replace œ/æ ligatures, collapse whitespace and punctuation.
   */
  static _normalize(str) {
    return (str ?? "")
      .toLowerCase()
      .replace(/œ/g, "oe")
      .replace(/æ/g, "ae")
      .normalize("NFD")
      .replace(/[\u0300-\u036f]/g, "")  // strip combining diacritics
      .replace(/[^a-z0-9]+/g, " ")       // replace any non-alnum with space
      .trim()
  }

  /**
   * Returns the first competence item whose name contains all of the given keywords.
   * Keywords are normalized before comparison.
   */
  static _findCompetence(actor, ...keywords) {
    const normKeys = keywords.map(k => MournbladeInvocationDemonDialog._normalize(k))
    return actor.items.find(item => {
      if (item.type !== "competence") return false
      const norm = MournbladeInvocationDemonDialog._normalize(item.name)
      return normKeys.every(k => norm.includes(k))
    }) ?? null
  }

  /**
   * Returns true if the actor has a capacite or don whose name contains all given keywords.
   */
  static _hasCapacite(actor, ...keywords) {
    const normKeys = keywords.map(k => MournbladeInvocationDemonDialog._normalize(k))
    return actor.items.some(item => {
      if (item.type !== "capacite" && item.type !== "don") return false
      const norm = MournbladeInvocationDemonDialog._normalize(item.name)
      return normKeys.every(k => norm.includes(k))
    })
  }

  static async create(actor, rollData) {
    const ameDisponible = Math.max(0, (actor.system.ame.currentmax - actor.system.ame.value))

    // Robust skill detection: partial keyword matching, diacritic-insensitive
    const coercitionComp = MournbladeInvocationDemonDialog._findCompetence(actor, "coercition")
    const hautParlerComp = MournbladeInvocationDemonDialog._findCompetence(actor, "haut", "parler")
    const loiChaosComp   = MournbladeInvocationDemonDialog._findCompetence(actor, "loi", "chaos")

    // Check prerequisites — robust capacite/rune detection
    const isChaotique = actor.system.balance.chaos > actor.system.balance.loi
    const hasOeilSorcier = MournbladeInvocationDemonDialog._hasCapacite(actor, "oeil", "sorcier")
    const hasRuneChaos = actor.items.some(i => {
      if (i.type !== "rune") return false
      return MournbladeInvocationDemonDialog._normalize(i.name).includes("chaos")
    })
    const prerequisOk = isChaotique && hasOeilSorcier && hasRuneChaos

    // Auto-detect chaos link bonuses
    const aspectGe8 = (actor.system.balance.aspect ?? 0) >= 8
    // hasPacte: true if actor has a Pacte item whose associated deity matches a demon
    // (simplified: just expose it as a selectable option — can't auto-detect)
    const hasPacte = false

    const context = {
      ...rollData,
      img: actor.img,
      name: actor.name,
      ameDisponible,
      modOptions: Array.from({ length: 21 }, (_, i) => i - 10),
      coercitionNiveau: coercitionComp ? coercitionComp.system.niveau : null,
      hautParlerNiveau: hautParlerComp ? hautParlerComp.system.niveau : null,
      loiChaosNiveau: loiChaosComp ? loiChaosComp.system.niveau : null,
      isChaotique,
      hasOeilSorcier,
      hasRuneChaos,
      prerequisOk,
      aspectGe8,
      hasPacte,
    }

    const content = await foundry.applications.handlebars.renderTemplate(
      "systems/fvtt-mournblade/templates/dialog-invocation-demon.hbs",
      context
    )

    Hooks.once("renderDialogV2", (_app, html) => {
      const form = html.querySelector ? html : html[0]
      MournbladeInvocationDemonDialog._attachListeners(form, ameDisponible, prerequisOk)
    })

    return foundry.applications.api.DialogV2.wait({
      window: { title: "Invoquer un Démon", icon: "fa-solid fa-skull" },
      classes: ["mournblade-roll-dialog"],
      position: { width: 560 },
      modal: false,
      content,
      buttons: [
        {
          action: "invoquer",
          label: "Invoquer",
          icon: "fa-solid fa-skull",
          default: true,
          callback: async (event, button, dialog) => {
            MournbladeInvocationDemonDialog._updateRollData(rollData, button.form.elements, actor, {
              coercitionComp, hautParlerComp, loiChaosComp
            })
            await MournbladeUtility.rollInvocationDemon(rollData)
          }
        },
      ],
      rejectClose: false,
    })
  }

  static _calculateSeuil(html) {
    const get = (name) => parseInt(html.querySelector(`[name="${name}"]`)?.value ?? 0) || 0
    const seuil = get("seuil_nature")
      + get("seuil_traits")
      + get("seuil_augmentation")
      + get("seuil_service")
      + get("seuil_duree")
      + get("seuil_marche")
      + get("seuil_chaos")
      + get("seuil_sacrifice")
    return Math.max(1, seuil)
  }

  static _attachListeners(html, ameDisponible, prerequisOk = true) {
    const invoquerBtn = html.querySelector('button[data-action="invoquer"]')
    if (invoquerBtn) invoquerBtn.disabled = !prerequisOk

    const coutEl = html.querySelector('#invoc-demon-cout')
    const totalEl = html.querySelector('#invoc-demon-seuil-total')
    const hiddenEl = html.querySelector('#invoc-demon-seuil-hidden')
    const warnEl = html.querySelector('#invoc-demon-ame-warn')

    const criteriaNames = [
      "seuil_nature", "seuil_traits", "seuil_augmentation",
      "seuil_service", "seuil_duree", "seuil_marche",
      "seuil_chaos", "seuil_sacrifice"
    ]

    const recalculate = () => {
      const seuil = MournbladeInvocationDemonDialog._calculateSeuil(html)
      if (totalEl) totalEl.textContent = seuil
      if (hiddenEl) hiddenEl.value = seuil
      if (coutEl) coutEl.textContent = seuil
      if (warnEl) warnEl.style.display = seuil > ameDisponible ? "" : "none"
    }

    for (const name of criteriaNames) {
      const el = html.querySelector(`[name="${name}"]`)
      if (el) el.addEventListener('change', recalculate)
      if (el && el.type === 'number') el.addEventListener('input', recalculate)
    }

    recalculate()
  }

  static _updateRollData(rollData, formElements, actor, { coercitionComp }) {
    const seuil = parseInt(formElements['seuil']?.value ?? 5)
    const modificateur = parseInt(formElements['modificateur']?.value ?? 0)

    rollData.invocationSeuil = seuil
    rollData.invocationSoulCost = seuil
    rollData.difficulte = seuil
    rollData.modificateur = modificateur
    rollData.competence = coercitionComp ?? null
  }
}
