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

export default class HamalronTirageTarot {
  /**
   * The HTML template path used to render dice checks of this type
   * @type {string}
   */
  static CHAT_TEMPLATE = "systems/fvtt-hamalron/templates/chat-message.hbs"

  static async prompt(options = {}) {
    let formula = `3D6 + 0D6KH - 0D6KH + ${options?.rollItem?.value}`

    let actor = game.actors.get(options.actorId)
    switch (options.rollType) {
      case "stat":
        break
      case "damage":
        {
          let formula = options.rollItem.system.damage
          if (options.rollItem?.system?.damageStat && options.rollItem.system.damageStat !== "none" && options.rollItem.system.damageStat !== "") {
            let statKey = options.rollItem.system?.damageStat.toLowerCase()
            let statValue = actor.system.stats[statKey].value
            formula = `${formula} + ${statValue}`
          }
          let damageRoll = new Roll(formula)
          await damageRoll.evaluate()
          await damageRoll.toMessage({
            flavor: `<div class="flavor-text-damage"><h2>${options.rollItem.name}</h2>
            <BR><span class="chat-damage-type"><span>${options.rollItem.system.damageType}</span></span></div>`,
          });
          return
        }
      case "weapon":
        {
          options.weapon = foundry.utils.duplicate(options.rollItem)
          let statKey = options.weapon.system.stat.toLowerCase()
          options.rollItem = actor.system.stats[statKey]
        }
        break
      default:
        break
    }

    const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes)
    const fieldRollMode = new foundry.data.fields.StringField({
      choices: rollModes,
      blank: false,
      default: "public",
    })

    options.formula = formula
    options.nbAdvantages = "0"
    options.nbDisadvantages = "0"

    let dialogContext = {
      actorId: options.actorId,
      actorName: options.actorName,
      rollType: options.rollType,
      rollItem: foundry.utils.duplicate(options.rollItem), // Object only, no class
      weapon: options?.weapon,
      formula: formula,
      fullFormula: formula,
      rollModes,
      fieldRollMode,
      choiceAdvantages: SYSTEM.CHOICE_ADVANTAGES_DISADVANTAGES,
      choiceDisadvantages: SYSTEM.CHOICE_ADVANTAGES_DISADVANTAGES,
      hasTarget: options.hasTarget,
      difficulty: "0",
      nbAdvantages: "0",
      nbDisadvantages: "0",
    }
    const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-hamalron/templates/roll-dialog.hbs", dialogContext)

    const title = HamalronRoll.createTitle(options.rollType, options.rollTarget)
    const label = game.i18n.localize("HAMALRON.Roll.roll")
    const rollContext = await foundry.applications.api.DialogV2.wait({
      window: { title: title },
      classes: ["fvtt-hamalron"],
      content,
      buttons: [
        {
          label: label,
          callback: (event, button, dialog) => {
            const output = Array.from(button.form.elements).reduce((obj, input) => {
              if (input.name) obj[input.name] = input.value
              return obj
            }, {})
            return output
          },
        },
      ],
      actions: {
      },
      rejectClose: false, // Click on Close button will not launch an error
      render: (event, dialog) => {
        $(".roll-stat-advantages").change(event => {
          options.nbAdvantages = Number(event.target.value)
          HamalronRoll.updateFullFormula(options)
        })
        $(".roll-stat-disadvantages").change(event => {
          options.nbDisadvantages = Number(event.target.value)
          HamalronRoll.updateFullFormula(options)
        })
        $(".select-combat-option").change(event => {
          let field = $(event.target).data("field")
          let modifier = SYSTEM.ATTACK_MODIFIERS[field]
          if (event.target.checked) {
            options.numericModifier += modifier
          } else {
            options.numericModifier -= modifier
          }
          HamalronRoll.updateFullFormula(options)
        })
      }
    })

    // If the user cancels the dialog, exit
    if (rollContext === null) return

    let rollData = foundry.utils.mergeObject(foundry.utils.duplicate(options), rollContext)
    rollData.rollMode = rollContext.visibility
    rollData.targetScore = 8

    if (Hooks.call("fvtt-hamalron.preRoll", options, rollData) === false) return

    options.nbAdvantages = Number(options.nbAdvantages)
    options.nbDisadvantages = Number(options.nbDisadvantages)
    let dice = 3;
    let keep = ""
    if ((options.nbAdvantages !== options.nbDisadvantages) && options.nbAdvantages > 0 || options.nbDisadvantages > 0) {
      dice = 3 + Math.abs(options.nbAdvantages - options.nbDisadvantages)
      if (options.nbAdvantages > options.nbDisadvantages) {
        keep = "kh3"
      } else if (options.nbAdvantages < options.nbDisadvantages) {
        keep = "kl3"
      }
    }
    let diceFormula = `${dice}D6${keep} +  ${options.rollItem.value}`
    const roll = new this(diceFormula, options.data, rollData)
    await roll.evaluate()
    console.log("Roll", rollData, roll)
    options.difficulty = (rollData.difficulty === "unknown") ? 0 : (Number(rollData.difficulty) || 0)

    roll.displayRollResult(roll, options, rollData, roll)

    if (Hooks.call("fvtt-hamalron.Roll", options, rollData, roll) === false) return

    return roll
  }

  displayRollResult(formula, options, rollData, roll) {
    let resultType = "failure"
    if (options.difficulty === 0) {
      resultType = "unknown"
    } else if (this.total >= options.difficulty) {
      resultType = "success"
    }

    // Compute the result quality
    this.options.satanicSuccess = false
    this.options.fiendishFailure = false
    this.options.rollData = foundry.utils.duplicate(rollData)

    // Check if all results are equal
    let workResults = foundry.utils.duplicate(roll.terms[0].results)
    // Get the most common result of the roll
    let commonResult = workResults.reduce((acc, r) => {
      acc[r.result] = (acc[r.result] || 0) + 1
      return acc
    }, {})
    commonResult = Object.entries(commonResult).reduce((a, b) => (a[1] > b[1]) ? a : b)[0]
    let nbEqual = workResults.filter(r => Number(r.result) === Number(commonResult)).length

    if (resultType === "success" && commonResult >= 4 && nbEqual >= 3) {
      this.options.satanicSuccess = true
      if (this.options.satanicSuccess) {
        resultType = "success"
      }
    }
    if (resultType === "failure" && commonResult <= 3 && nbEqual >= 3) {
      this.options.fiendishFailure = true
      if (this.options.fiendishFailure) {
        resultType = "failure"
      }
    }
    this.options.resultType = resultType
    this.options.isSuccess = resultType === "success"
    this.options.isFailure = resultType === "failure"
    this.options.results = roll.terms[0].results
  }

  /**
   * Creates a title based on the given type.
   *
   * @param {string} type The type of the roll.
   * @param {string} target The target of the roll.
   * @returns {string} The generated title.
   */
  static createTitle(type, target) {
    switch (type) {
      case "stat":
        return `${game.i18n.localize("HAMALRON.Label.titleStat")}`
      case "weapon":
        return `${game.i18n.localize("HAMALRON.Label.titleWeapon")}`
      default:
        return game.i18n.localize("HAMALRON.Label.titleStandard")
    }
  }

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

  /**
   * Generates the data required for rendering a roll chat card.
   *
   * @param {boolean} isPrivate Indicates if the chat card is private.
   * @returns {Promise<Object>} A promise that resolves to an object containing the chat card data.
   * @property {Array<string>} css - CSS classes for the chat card.
   * @property {Object} data - The data associated with the roll.
   * @property {number} diceTotal - The total value of the dice rolled.
   * @property {boolean} isGM - Indicates if the user is a Game Master.
   * @property {string} formula - The formula used for the roll.
   * @property {number} total - The total result of the roll.
   * @property {boolean} isFailure - Indicates if the roll is a failure.
   * @property {string} actorId - The ID of the actor performing the roll.
   * @property {string} actingCharName - The name of the character performing the roll.
   * @property {string} actingCharImg - The image of the character performing the roll.
   * @property {string} resultType - The type of result (e.g., success, failure).
   * @property {boolean} hasTarget - Indicates if the roll has a target.
   * @property {string} targetName - The name of the target.
   * @property {number} targetArmor - The armor value of the target.
   * @property {number} realDamage - The real damage dealt.
   * @property {boolean} isPrivate - Indicates if the chat card is private.
   * @property {string} cssClass - The combined CSS classes as a single string.
   * @property {string} tooltip - The tooltip text for the chat card.
   */
  async _getChatCardData(isPrivate) {
    let cardData = foundry.utils.duplicate(this.options)
    cardData.css = [SYSTEM.id, "dice-roll"]
    cardData.data = this.data
    cardData.diceTotal = this.dice.reduce((t, d) => t + d.total, 0)
    cardData.isGM = game.user.isGM
    cardData.formula = this.formula
    cardData.fullFormula = this.options.fullFormula
    cardData.numericModifier = this.options.numericModifier
    cardData.total = this.total
    cardData.actorId = this.actorId
    cardData.actingCharName = this.actorName
    cardData.actingCharImg = this.actorImage
    cardData.resultType = this.resultType
    cardData.hasTarget = this.hasTarget
    cardData.targetName = this.targetName
    cardData.targetArmor = this.targetArmor
    cardData.realDamage = this.realDamage
    cardData.isPrivate = isPrivate
    cardData.weapon = this.weapon

    cardData.cssClass = cardData.css.join(" ")
    cardData.tooltip = isPrivate ? "" : await this.getTooltip()
    return cardData
  }

  /**
   * Converts the roll result to a chat message.
   *
   * @param {Object} [messageData={}] Additional data to include in the message.
   * @param {Object} options Options for message creation.
   * @param {string} options.rollMode The mode of the roll (e.g., public, private).
   * @param {boolean} [options.create=true] Whether to create the message.
   * @returns {Promise} - A promise that resolves when the message is created.
   */
  async toMessage(messageData = {}, { rollMode, create = true } = {}) {
    super.toMessage(
      {
        isFailure: this.resultType === "failure",
        actingCharName: this.actorName,
        actingCharImg: this.actorImage,
        hasTarget: this.hasTarget,
        realDamage: this.realDamage,
        ...messageData,
      },
      { rollMode: rollMode },
    )
  }

}
