import { SYSTEM } from "../config/system.mjs"

/** Construit la formule de jet à partir du nombre de dés et du modificateur total. */
function buildFormula(nbDice, totalModifier) {
  if (totalModifier > 0) return `${nbDice}d8 + ${totalModifier}`
  if (totalModifier < 0) return `${nbDice}d8 - ${Math.abs(totalModifier)}`
  return `${nbDice}d8`
}

/**
 * Système de dés de Célestopol 1922.
 *
 * Formule de base : 2d8 + Spécialisation + modificateurs (aspect, blessures, manual)
 * Destin (jauge pleine à 8) : 3d8 + modificateurs, puis reset de la jauge à 0
 * Dé de la Lune (optionnel) : 1d8 séparé → résultat narratif (Triomphe/Brio/Contrecoup/Catastrophe)
 */
export class CelestopolRoll extends Roll {
  static CHAT_TEMPLATE = "systems/fvtt-celestopol/templates/chat-message.hbs"

  get resultType()       { return this.options.resultType }
  get isSuccess()        { return this.resultType === "success" || this.resultType === "critical-success" }
  get isFailure()        { return this.resultType === "failure" || this.resultType === "critical-failure" }
  get isCriticalSuccess(){ return this.resultType === "critical-success" }
  get isCriticalFailure(){ return this.resultType === "critical-failure" }
  get actorId()          { return this.options.actorId }
  get actorName()        { return this.options.actorName }
  get actorImage()       { return this.options.actorImage }
  get skillLabel()       { return this.options.skillLabel }
  get difficulty()       { return this.options.difficulty }

  /**
   * Ouvre le dialogue de configuration du jet via DialogV2 et exécute le jet.
   * @param {object} options
   * @returns {Promise<CelestopolRoll|null>}
   */
  static async prompt(options = {}) {
    const woundMalus    = options.woundMalus ?? 0
    const skillValue    = options.skillValue ?? 0
    const woundLevelId  = options.woundLevel ?? 0
    const destGaugeFull = options.destGaugeFull ?? false
    const woundLabel    = woundLevelId > 0
      ? game.i18n.localize(SYSTEM.WOUND_LEVELS[woundLevelId]?.label ?? "")
      : null

    const dialogContext = {
      actorName:          options.actorName,
      statLabel:          options.statLabel,
      skillLabel:         options.skillLabel,
      skillValue,
      woundMalus,
      woundLabel,
      difficultyChoices:  SYSTEM.DIFFICULTY_CHOICES,
      defaultDifficulty:  options.difficulty ?? "normal",
      destGaugeFull,
      defaultRollMoonDie: options.rollMoonDie ?? false,
    }

    const content = await foundry.applications.handlebars.renderTemplate(
      "systems/fvtt-celestopol/templates/roll-dialog.hbs",
      dialogContext
    )

    const skillLocalized = game.i18n.localize(options.skillLabel ?? "")
    const statLocalized  = options.statLabel ? game.i18n.localize(options.statLabel) : null
    const title = statLocalized ? `${statLocalized} › ${skillLocalized}` : skillLocalized

    const rollContext = await foundry.applications.api.DialogV2.wait({
      window: { title },
      classes: ["fvtt-celestopol", "roll-dialog"],
      content,
      buttons: [
        {
          label: game.i18n.localize("CELESTOPOL.Roll.roll"),
          icon:  "fa-solid fa-dice",
          callback: (event, button) => {
            return Array.from(button.form.elements).reduce((obj, input) => {
              if (input.name) {
                obj[input.name] = input.type === "checkbox" ? input.checked : input.value
              }
              return obj
            }, {})
          },
        },
      ],
      rejectClose: false,
    })

    if (!rollContext) return null

    const difficulty    = rollContext.difficulty ?? "normal"
    const diffConfig    = SYSTEM.DIFFICULTY_CHOICES[difficulty] ?? SYSTEM.DIFFICULTY_CHOICES.normal
    const modifier      = parseInt(rollContext.modifier ?? 0) || 0
    const aspectMod     = parseInt(rollContext.aspectModifier ?? 0) || 0
    const useDestin     = destGaugeFull && (rollContext.useDestin === true || rollContext.useDestin === "true")
    const rollMoonDie   = rollContext.rollMoonDie === true || rollContext.rollMoonDie === "true"
    const nbDice        = useDestin ? 3 : 2
    const totalModifier = skillValue + woundMalus + aspectMod + modifier
    const formula       = buildFormula(nbDice, totalModifier)

    // Jet du dé de lune séparé (narratif)
    let moonDieResult  = null
    let moonFace       = null
    let moonResultType = null
    if (rollMoonDie) {
      const moonRoll = await new Roll("1d8").evaluate()
      moonDieResult  = moonRoll.total
      moonFace       = SYSTEM.MOON_DIE_FACES[moonDieResult] ?? null
      moonResultType = moonFace ? SYSTEM.MOON_RESULT_TYPES[moonFace.result] ?? null : null
    }

    const rollData = {
      ...options,
      difficulty,
      difficultyValue: diffConfig.value,
      modifier,
      aspectMod,
      useDestin,
      nbDice,
      formula,
      rollMode:      rollContext.visibility ?? "publicroll",
      rollMoonDie,
      moonDieResult,
      moonFace,
      moonResultType,
    }

    const roll = new this(formula, {}, rollData)
    await roll.evaluate()
    roll.computeResult()
    await roll.toMessage({}, { rollMode: rollData.rollMode })

    // Destin utilisé → vider la jauge (reset à 0)
    const actor = game.actors.get(options.actorId)
    if (useDestin && actor) {
      await actor.update({
        "system.destin.lvl":         0,
        "system.destin.d1.checked":  false,
        "system.destin.d2.checked":  false,
        "system.destin.d3.checked":  false,
        "system.destin.d4.checked":  false,
        "system.destin.d5.checked":  false,
        "system.destin.d6.checked":  false,
        "system.destin.d7.checked":  false,
        "system.destin.d8.checked":  false,
      })
    }

    // Mémoriser les préférences sur l'acteur
    if (actor) {
      await actor.update({
        "system.prefs.rollMoonDie": rollMoonDie,
        "system.prefs.difficulty":  difficulty,
      })
    }

    return roll
  }

  /**
   * Détermine succès/échec selon la marge (total − seuil).
   * - Marge ≥ 5  → succès critique
   * - Marge ≥ 0  → succès
   * - Marge ≤ −5 → échec critique
   * - Marge < 0  → échec
   */
  computeResult() {
    const threshold = SYSTEM.DIFFICULTY_CHOICES[this.options.difficulty]?.value ?? 0
    if (threshold === 0) {
      this.options.resultType = "unknown"
      this.options.margin     = null
      return
    }
    const margin = this.total - threshold
    this.options.margin = margin
    if      (margin >= 5)  this.options.resultType = "critical-success"
    else if (margin >= 0)  this.options.resultType = "success"
    else if (margin <= -5) this.options.resultType = "critical-failure"
    else                   this.options.resultType = "failure"
  }

  /** @override */
  async render(chatOptions = {}) {
    const data = await this._getChatCardData(chatOptions.isPrivate)
    return foundry.applications.handlebars.renderTemplate(this.constructor.CHAT_TEMPLATE, data)
  }

  async _getChatCardData(isPrivate) {
    const statLabel    = this.options.statLabel
    const skillLabel   = this.options.skillLabel
    const resultType   = this.resultType
    const diceResults  = this.dice[0]?.results?.map(r => r.result) ?? []
    const diceSum      = diceResults.reduce((a, b) => a + b, 0)
    const threshold    = SYSTEM.DIFFICULTY_CHOICES[this.options.difficulty]?.value ?? 0
    const margin       = this.options.margin
    const woundMalus   = this.options.woundMalus ?? 0
    const woundLevelId = this.options.woundLevel ?? 0
    const woundLabel   = woundLevelId > 0
      ? game.i18n.localize(SYSTEM.WOUND_LEVELS[woundLevelId]?.label ?? "")
      : null

    // Dé de lune
    const moonDieResult  = this.options.moonDieResult ?? null
    const moonFace       = this.options.moonFace ?? null
    const moonResultType = this.options.moonResultType ?? null

    const resultClassMap = {
      "critical-success": "critical-success",
      "success":          "success",
      "failure":          "failure",
      "critical-failure": "critical-failure",
      "unknown":          "",
    }

    return {
      cssClass:          [SYSTEM.id, "dice-roll"].join(" "),
      actorId:           this.actorId,
      actorName:         this.actorName,
      actorImg:          this.actorImage,
      statLabel:         statLabel ? game.i18n.localize(statLabel) : "",
      skillLabel:        skillLabel ? game.i18n.localize(skillLabel) : "",
      formula:           this.formula,
      total:             this.total,
      diceSum,
      diceResults,
      resultType,
      resultClass:       resultClassMap[resultType] ?? "",
      isSuccess:         this.isSuccess,
      isFailure:         this.isFailure,
      isCriticalSuccess: this.isCriticalSuccess,
      isCriticalFailure: this.isCriticalFailure,
      difficulty:        this.options.difficulty,
      difficultyLabel:   game.i18n.localize(SYSTEM.DIFFICULTY_CHOICES[this.options.difficulty]?.label ?? ""),
      difficultyValue:   threshold,
      margin,
      marginAbs:         margin !== null ? Math.abs(margin) : null,
      marginAbove:       margin !== null && margin >= 0,
      modifier:          this.options.modifier,
      aspectMod:         this.options.aspectMod ?? 0,
      useDestin:         this.options.useDestin ?? false,
      nbDice:            this.options.nbDice ?? diceResults.length,
      woundMalus,
      woundLabel,
      // Dé de lune
      hasMoonDie:        moonDieResult !== null,
      moonDieResult,
      moonFaceSymbol:    moonFace?.symbol ?? "",
      moonFaceLabel:     moonFace ? game.i18n.localize(moonFace.label) : "",
      moonResultClass:   moonResultType?.cssClass ?? "",
      moonResultLabel:   moonResultType ? game.i18n.localize(moonResultType.label) : "",
      moonResultDesc:    moonResultType ? game.i18n.localize(moonResultType.desc) : "",
      isPrivate,
      tooltip:           isPrivate ? "" : await this.getTooltip(),
    }
  }

  /** @override */
  async toMessage(messageData = {}, { rollMode, create = true } = {}) {
    const skillLocalized = this.skillLabel ? game.i18n.localize(this.skillLabel) : ""
    const statLocalized  = this.options.statLabel
      ? game.i18n.localize(this.options.statLabel) : ""
    const flavor = statLocalized
      ? `<strong>${statLocalized} › ${skillLocalized}</strong>`
      : `<strong>${skillLocalized}</strong>`
    return super.toMessage({ flavor, ...messageData }, { rollMode })
  }
}
