
import { SYSTEM } from "../config/system.mjs"
export default class CthulhuEternalRoll extends Roll {
  /**
   * The HTML template path used to render dice checks of this type
   * @type {string}
   */
  static CHAT_TEMPLATE = "systems/fvtt-cthulhu-eternal/templates/chat-message.hbs"

  get type() {
    return this.options.type
  }

  get isDamage() {
    return this.type === ROLL_TYPE.DAMAGE
  }

  get target() {
    return this.options.target
  }

  get value() {
    return this.options.value
  }

  get actorId() {
    return this.options.actorId
  }

  get actorName() {
    return this.options.actorName
  }

  get actorImage() {
    return this.options.actorImage
  }

  get help() {
    return this.options.help
  }

  get gene() {
    return this.options.gene
  }

  get modifier() {
    return this.options.modifier
  }

  get resultType() {
    return this.options.resultType
  }

  get isFailure() {
    return this.resultType === "failure"
  }

  get hasTarget() {
    return this.options.hasTarget
  }

  get targetName() {
    return this.options.targetName
  }

  get targetArmor() {
    return this.options.targetArmor
  }

  get targetMalus() {
    return this.options.targetMalus
  }

  get realDamage() {
    return this.options.realDamage
  }

  get weapon() {
    return this.options.weapon
  }

  get isLowWP() {
    return this.options.isLowWP
  }

  get isZeroWP() {
    return this.options.isZeroWP
  }

  get isExhausted() {
    return this.options.isExhausted
  }
  
  /**
   * Prompt the user with a dialog to configure and execute a roll.
   *
   * @param {Object} options Configuration options for the roll.
   * @param {string} options.rollType The type of roll being performed.
   * @param {string} options.rollTarget The target of the roll.
   * @param {string} options.actorId The ID of the actor performing the roll.
   * @param {string} options.actorName The name of the actor performing the roll.
   * @param {string} options.actorImage The image of the actor performing the roll.
   * @param {boolean} options.hasTarget Whether the roll has a target.
   * @param {Object} options.data Additional data for the roll.
   *
   * @returns {Promise<Object|null>} The roll result or null if the dialog was cancelled.
   */
  static async prompt(options = {}) {
    let formula = "1d100"
    switch (options.rollType) {        
      case "skill":
        console.log(options.rollItem)
        options.initialScore = options.rollItem.system.computeScore()
        break
      case "san":
      case "char":
        options.initialScore = options.rollItem.targetScore
        break
      case "damage": 
        let formula = options.rollItem.system.damage 
        let damageRoll = new Roll(formula)
        await damageRoll.evaluate()
        await damageRoll.toMessage({
          flavor: `${options.rollItem.name} - Damage Roll`
        });
        let isLethal = false
        if (options.rollItem.system.lethality > 0 ) {
          let lethalityRoll = new Roll("1d100")
          await lethalityRoll.evaluate()
          isLethal = (lethalityRoll.total <= options.rollItem.system.lethality) 
          await lethalityRoll.toMessage({
            flavor: `${options.rollItem.name} - Lethality Roll : ${lethalityRoll.total} <= ${options.rollItem.system.lethality} => ${isLethal}`
          });
          }
        return
      case "weapon":  
        let era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
        if (!SYSTEM.WEAPON_SKILL_MAPPING[era] || !SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) {
          ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponType") )  
          return
        }
        let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])  
        let actor = game.actors.get(options.actorId)
        options.weapon = options.rollItem
        options.rollItem = actor.items.find(i => i.type === "skill" && i.name.toLowerCase() === skillName.toLowerCase())
        if (!options.rollItem) {
          ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponSkill") )
          return
        }
        options.initialScore = options.rollItem.system.computeScore()
        console.log("WEAPON", skillName, era, options.rollItem)
        break
      default:
        options.initialScore = 50
        break
    }

    const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
    const fieldRollMode = new foundry.data.fields.StringField({
      choices: rollModes,
      blank: false,
      default: "public",
    })

    const choiceModifier = {
      "-10": "-10",
      "-20": "-20",
      "-40": "-40",
      "0": "0",
      "+10": "+10",
      "+20": "+20",
      "+40": "+40",
    }

    let modifier = "0"
    let targetMalus = "0"
    let targetName
    let targetArmor

    let dialogContext = {
      rollType: options.rollType,
      rollItem: foundry.utils.duplicate(options.rollItem), // Object only, no class
      weapon: options?.weapon, 
      initialScore: options.initialScore,
      targetScore: options.initialScore,
      isLowWP: options.isLowWP,
      isZeroWP: options.isZeroWP,
      isExhausted: options.isExhausted,
      rollModes,
      fieldRollMode,
      choiceModifier,
      formula,
      hasTarget: options.hasTarget,
      modifier,
      targetName,
      targetArmor
    }
    const content = await renderTemplate("systems/fvtt-cthulhu-eternal/templates/roll-dialog.hbs", dialogContext)

    const title = CthulhuEternalRoll.createTitle(options.rollType, options.rollTarget)
    const label = game.i18n.localize("CTHULHUETERNAL.Roll.roll")
    const rollContext = await foundry.applications.api.DialogV2.wait({
      window: { title: title },
      classes: ["fvtt-cthulhu-eternal"],
      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
          },
        },
      ],
      rejectClose: false, // Click on Close button will not launch an error
      render: (event, dialog) => {
      },
    })

    // 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.targetName = targetName
    rollData.targetArmor = targetArmor
    rollData.targetMalus = targetMalus

    // Update target score
    console.log(rollData)
    rollData.targetScore =  Math.min( Math.max(options.initialScore + Number(rollData.modifier), 0), 100)
    if ( rollData.isLowWP || rollData.isExhausted) {
      rollData.targetScore -= 20
    }
    if ( rollData.isZeroWP ) {
      rollData.targetScore = 0
    }
    rollData.targetScore = Math.min( Math.max(rollData.targetScore, 0), 100)

    /**
     * A hook event that fires before the roll is made.
     */
    if (Hooks.call("fvtt-cthulhu-eternal.preRoll", options, rollData) === false) return

    const roll = new this(formula, options.data, rollData)
    await roll.evaluate()

    // Compute the result quality
    let resultType = "failure"  
    let dec = Math.floor(roll.total/10)
    let unit = roll.total - (dec*10)
    if (roll.total <= rollData.targetScore) {
      resultType = "success"
      // Detect if decimal == unit in the dire total result 
      if (dec === unit || roll.total === 1) {
        resultType = "successCritical"
      }
    } else {
      // Detect if decimal == unit in the dire total result 
      if (dec === unit || roll.total === 100) {
        resultType = "failureCritical"
      }
    }

    roll.options.resultType = resultType
    roll.options.isSuccess = resultType === "success" || resultType === "successCritical"
    roll.options.isFailure = resultType === "failure" || resultType === "failureCritical"
    roll.options.isCritical = resultType === "successCritical" || resultType === "failureCritical"
    roll.options.isLowWP = rollData.isLowWP
    roll.options.isZeroWP = rollData.isZeroWP
    roll.options.isExhausted = rollData.isExhausted

    /**
     * A hook event that fires after the roll has been made.
     */
    if (Hooks.call("fvtt-cthulhu-eternal.Roll", options, rollData, roll) === false) return

    return roll
  }

  /**
   * 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 "skill":
        return `${game.i18n.localize("CTHULHUETERNAL.Label.titleSkill")}`
      case "weapon":
        return `${game.i18n.localize("CTHULHUETERNAL.Label.titleWeapon")}`
      case "char": 
        return `${game.i18n.localize("CTHULHUETERNAL.Label.titleCharacteristic")}`
      case "san": 
        return `${game.i18n.localize("CTHULHUETERNAL.Label.titleSAN")}`
      default:
        return game.i18n.localize("CTHULHUETERNAL.Label.titleStandard")
    }
  }

  /** @override */
  async render(chatOptions = {}) {
    let chatData = await this._getChatCardData(chatOptions.isPrivate)
    return await 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.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.isLowWP = this.isLowWP
    cardData.isZeroWP = this.isZeroWP
    cardData.isExhausted = this.isExhausted
    

    console.log(cardData)

    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,
        targetName: this.targetName,
        targetArmor: this.targetArmor,
        targetMalus: this.targetMalus,
        realDamage: this.realDamage,
        ...messageData,
      },
      { rollMode: rollMode },
    )
  }

}
