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

export default class MournbladeInvocationDialog {

  /**
   * 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, "")
      .replace(/[^a-z0-9]+/g, " ")
      .trim()
  }

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

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

    // Detect elemental pacte bonus — the bonus is always available,
    // but we display it dynamically based on chosen element.
    // We pass the pactes to let JS listeners detect the match.
    const pactes = actor.getPactes().map(p => ({
      name: p.name,
      allegeance: (p.system.allegeance || "").toLowerCase()
    }))

    // Robust skill detection: partial keyword matching, diacritic-insensitive
    const hautParlerComp = MournbladeInvocationDialog._findCompetence(actor, "haut", "parler")
    const seigneursElemComp = MournbladeInvocationDialog._findCompetence(actor, "seigneurs", "elementaires")

    const context = {
      ...rollData,
      img: actor.img,
      name: actor.name,
      ameDisponible,
      ameExtraOptions: Array.from({ length: maxExtra + 1 }, (_, i) => i),
      modOptions: Array.from({ length: 21 }, (_, i) => i - 10),
      hautParlerNiveau: hautParlerComp ? hautParlerComp.system.niveau : null,
      seigneursElemNiveau: seigneursElemComp ? seigneursElemComp.system.niveau : null,
      bonusPacte: false,
      pactes,
    }

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

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

    return foundry.applications.api.DialogV2.wait({
      window: { title: "Invoquer un Élémentaire", icon: "fa-solid fa-wind" },
      classes: ["mournblade-roll-dialog"],
      position: { width: 480 },
      modal: false,
      content,
      buttons: [
        {
          action: "invoquer",
          label: "Invoquer",
          icon: "fa-solid fa-wind",
          default: true,
          callback: async (event, button, dialog) => {
            MournbladeInvocationDialog._updateRollData(rollData, button.form.elements, actor, pactes)
            await MournbladeUtility.rollInvocationElementaire(rollData)
          }
        },
      ],
      rejectClose: false,
    })
  }

  static _elementKeywords = {
    air: ["air", "vent", "sylphe", "seigneur de l'air"],
    terre: ["terre", "gnome", "seigneur de la terre"],
    feu: ["feu", "flamme", "salamandre", "seigneur du feu"],
    eau: ["eau", "ondine", "seigneur de l'eau"],
  }

  static _hasPacteBonus(element, pactes) {
    const keywords = MournbladeInvocationDialog._elementKeywords[element] || []
    return pactes.some(p => keywords.some(kw => p.allegeance.includes(kw)))
  }

  static _attachListeners(html, pactes) {
    const tierSeuils = { mineur: 15, median: 20, majeur: 25 }
    const tierTemps = { mineur: "1 tour", median: "1 minute", majeur: "1 heure" }

    const recalculate = () => {
      const element = html.querySelector('[name="element"]')?.value ?? "air"
      const tier = html.querySelector('[name="tier"]')?.value ?? "mineur"
      const ameExtra = parseInt(html.querySelector('[name="ameExtra"]')?.value ?? 0)

      const seuilBase = tierSeuils[tier] ?? 15
      const seuil = seuilBase + ameExtra
      const hasPacte = MournbladeInvocationDialog._hasPacteBonus(element, pactes)

      const seuilEl = html.querySelector('#invoc-seuil')
      const coutEl = html.querySelector('#invoc-cout')
      const tempsEl = html.querySelector('#invoc-temps')
      const pacteBanner = html.querySelector('.invoc-bonus-pacte')

      if (seuilEl) seuilEl.textContent = seuil + (hasPacte ? " (-5 avec bonus Pacte)" : "")
      if (coutEl) coutEl.textContent = seuil
      if (tempsEl) tempsEl.textContent = tierTemps[tier] ?? "1 tour"
      if (pacteBanner) pacteBanner.style.display = hasPacte ? "" : "none"
    }

    html.querySelectorAll('[name="element"], [name="tier"], [name="ameExtra"]').forEach(el => {
      el.addEventListener('change', recalculate)
    })
    recalculate()
  }

  static _updateRollData(rollData, formElements, actor, pactes) {
    const element = formElements['element']?.value ?? "air"
    const tier = formElements['tier']?.value ?? "mineur"
    const ameExtra = parseInt(formElements['ameExtra']?.value ?? 0)
    const modificateur = parseInt(formElements['modificateur']?.value ?? 0)

    const tierSeuils = { mineur: 15, median: 20, majeur: 25 }
    const seuilBase = tierSeuils[tier] ?? 15
    const seuil = seuilBase + ameExtra

    rollData.invocationElement = element
    rollData.invocationTier = tier
    rollData.invocationSeuil = seuil
    rollData.invocationAmeExtra = ameExtra
    rollData.invocationSoulCost = seuil
    rollData.difficulte = seuil
    rollData.modificateur = modificateur
    rollData.bonusPacte = MournbladeInvocationDialog._hasPacteBonus(element, pactes) ? 5 : 0
  }
}
