import { Grammar } from "./grammar.js"
import { ITEM_TYPES, renderTemplate } from "./constants.js"
import { Misc } from "./misc.js"
import { RdDAlchimie } from "./rdd-alchimie.js"
import { RdDCarac } from "./rdd-carac.js"
import { RdDRoll } from "./rdd-roll.js"
import { extraireEtapesAlchimie } from "./roll/extraire-etapes-alchimie.mjs"

const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api

export class DialogLancerRecette extends HandlebarsApplicationMixin(ApplicationV2) {

  static DEFAULT_OPTIONS = {
    tag: "form",
    classes: ["dialog-lancer-recette"],
    form: { submitOnChange: false, closeOnSubmit: false },
    position: { width: 650, height: "auto" },
    window: { title: "Lancer une recette", icon: "fa-solid fa-flask" },
    actions: {
      lancerOperations: DialogLancerRecette.#onLancerOperations,
    },
  }

  static PARTS = {
    form: { template: "systems/foundryvtt-reve-de-dragon/templates/item/dialog-lancer-recette.hbs" },
  }

  static async create(item, actor) {
    const dialog = new DialogLancerRecette({ item, actor })
    dialog.render(true)
  }

  constructor(options) {
    super(options)
    this.item = options.item
    this.actor = options.actor
    this.etapes = []
    this.enCours = false
    this.termine = false
    this.allReussi = false
    this.consomme = false
  }

  /* -------------------------------------------- */
  async _prepareContext() {
    const ingredients = Misc.safeJsonParse(this.item.system.ingredients, [])
    const inventoryItems = this.actor.items.filter(i =>
      [ITEM_TYPES.herbe, ITEM_TYPES.plante, ITEM_TYPES.ingredient,
       ITEM_TYPES.objet, ITEM_TYPES.nourritureboisson, ITEM_TYPES.faune,
       ITEM_TYPES.potion].includes(i.type))

    const ingredientRows = ingredients.map(ing => {
      const matches = inventoryItems.filter(inv => Grammar.matchName(ing.nom, inv.name))
      const foundQty = matches.reduce((sum, inv) => sum + (parseInt(inv.system.quantite) || 0), 0)
      const requiredQty = parseInt(ing.quantite) || 1
      return {
        nom: ing.nom,
        quantiteRequise: requiredQty,
        quantiteTrouvee: foundQty,
        unite: ing.unite,
        consommable: ing.consommable,
        suffisant: foundQty >= requiredQty,
      }
    })

    if (!this.etapes.length) {
      this.etapes = extraireEtapesAlchimie(this.item.system.manipulation || '')
      for (const [i, e] of this.etapes.entries()) {
        e.num = i + 1
        e.status = 'pending'
        e.caracValue = this.actor.system.carac[e.caracKey]?.value ?? 0
        e.sansCristal = e.type === 'couleur' && !this.actor.items.some(it =>
          it.type === 'objet' && Grammar.toLowerCaseNoAccent(it.name) === 'cristal alchimique' && it.system.quantite > 0)
        e.diffConditions = e.sansCristal ? -4 : 0
      }
    }

      const resultat = Misc.safeJsonParse(this.item.system.resultat, null)

    return {
      recette: this.item.name,
      personnage: this.actor.name,
      but: this.item.system.but,
      ingredients: ingredientRows,
      allIngredientsOk: ingredientRows.every(r => r.suffisant),
      etapes: this.etapes,
      enCours: this.enCours,
      termine: this.termine,
      allReussi: this.allReussi,
      peutLancer: !this.enCours && !this.termine,
      resultat,
    }
  }

  /* -------------------------------------------- */
  async _onRender(context, options) {
  }

  /* -------------------------------------------- */
  static async #onLancerOperations(event, target) {
    if (this.enCours) return
    this.enCours = true
    this.render(true)

    for (let i = 0; i < this.etapes.length; i++) {
      const etape = this.etapes[i]
      etape.status = 'rolling'
      this._updateEtapeRow(i)
      const rolled = await this._effectuerEtape(etape)
      etape.status = rolled.isSuccess ? 'success' : 'failure'
      this._updateEtapeRow(i)
      if (!rolled.isSuccess) break
    }

    this.enCours = false
    this.termine = true
    this.allReussi = this.etapes.every(e => e.status === 'success')

    await this._consommerIngredients()

    this.consomme = true
    this.render(true)

    if (this.allReussi) {
      ui.notifications.info('Toutes les opérations alchimiques ont réussi !')
      const resultat = Misc.safeJsonParse(this.item.system.resultat, null)
      if (resultat && resultat.type) {
        const msg = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-alchimie-reussite.hbs', {
          recette: this.item.name,
          resultat,
          resultatJson: JSON.stringify(resultat),
          actorId: this.actor.id,
          recipeImg: this.item.img,
          alias: this.actor.getAlias ? this.actor.getAlias() : this.actor.name,
        })
        await ChatMessage.create({
          content: msg,
          speaker: ChatMessage.getSpeaker({ actor: this.actor }),
        })
      }
    } else {
      ui.notifications.warn('La recette a échoué. Les ingrédients ont été consommés.')
    }
  }

  /* -------------------------------------------- */
  async _effectuerEtape(etape) {
    const tacheAlchimie = etape.type
    const texteTache = etape.termes
    const sansCristal = etape.sansCristal
    const caracTache = RdDAlchimie.getCaracTache(tacheAlchimie)
    const alchimieData = this.actor.getCompetence('alchimie')

    const rollData = {
      recette: this.item,
      carac: { [caracTache]: this.actor.system.carac[caracTache] },
      selectedCarac: this.actor.system.carac[caracTache],
      competence: alchimieData,
      diffLibre: RdDAlchimie.getDifficulte(texteTache),
      diffConditions: sansCristal ? -4 : 0,
      alchimie: {
        tache: Misc.upperFirst(tacheAlchimie),
        texte: texteTache,
        sansCristal,
      },
    }
    if (rollData.competence) {
      rollData.competence.system.defaut_carac = caracTache
    }

    return new Promise(resolve => {
      const callbacks = []
      if (this.actor.createCallbackExperience) callbacks.push(this.actor.createCallbackExperience())
      if (this.actor.createCallbackAppelAuMoral) callbacks.push(this.actor.createCallbackAppelAuMoral())
      callbacks.push({
        action: async r => {
          resolve(r.rolled)
          if (this.actor._alchimieResult) await this.actor._alchimieResult(r)
        },
      })

      RdDRoll.create(this.actor, rollData,
        { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-alchimie.hbs' },
        { name: 'tache-alchimique', label: 'Tâche Alchimique', callbacks }
      ).then(dialog => {
        dialog.render(true)
        dialog.bringToFront()
      })
    })
  }

  /* -------------------------------------------- */
  _updateEtapeRow(index) {
    const etape = this.etapes[index]
    if (!etape) return
    const row = this.element?.querySelector(`.etape-row[data-index="${index}"]`)
    if (!row) return
    row.className = `etape-row etape-${etape.status}`
    const cell = row.querySelector('.etape-status')
    if (!cell) return
    const icons = {
      pending: '<i class="fas fa-circle status-pending"></i>',
      rolling: '<i class="fas fa-spinner fa-pulse status-rolling"></i>',
      success: '<i class="fas fa-check-circle status-success"></i>',
      failure: '<i class="fas fa-times-circle status-failure"></i>',
    }
    cell.innerHTML = icons[etape.status] || ''
  }

  /* -------------------------------------------- */
  async _consommerIngredients() {
    const ingredients = Misc.safeJsonParse(this.item.system.ingredients, [])
    for (const ing of ingredients) {
      if (!ing.consommable) continue
      const matches = this.actor.items.filter(inv => Grammar.matchName(ing.nom, inv.name))
      let remaining = parseInt(ing.quantite) || 1
      for (const item of matches) {
        if (remaining <= 0) break
        const qty = parseInt(item.system.quantite) || 0
        if (qty <= 0) continue
        const toTake = Math.min(qty, remaining)
        await item.diminuerQuantite(toTake, { supprimerSiZero: true })
        remaining -= toTake
      }
    }
  }

}
