export let RollHandler = null

Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
  /**
   * Extends Token Action HUD Core's RollHandler class and handles action events triggered when an action is clicked
  */
  RollHandler = class RollHandler extends coreModule.api.RollHandler {
    /**
     * Handle action click
     * Called by Token Action HUD Core when an action is left or right-clicked
     * @override
     * @param {object} event        The event
     * @param {string} encodedValue The encoded value
     */
    async handleActionClick(event, encodedValue) {
      const [actionTypeId, actionId] = encodedValue.split('|')

      const knownCharacters = ['protagonist', 'creature']

      // If single actor is selected
      if (this.actor) {
        await this.#handleAction(event, this.actor, this.token, actionTypeId, actionId)
        return
      }

      const controlledTokens = canvas.tokens.controlled
        .filter((token) => knownCharacters.includes(token.actor?.type))

      // If multiple actors are selected
      for (const token of controlledTokens) {
        const actor = token.actor
        await this.#handleAction(event, actor, token, actionTypeId, actionId)
      }
    }

    /**
     * Handle action hover
     * Called by Token Action HUD Core when an action is hovered on or off
     * @override
     * @param {object} event        The event
     * @param {string} encodedValue The encoded value
     */
    async handleActionHover(event, encodedValue) {
    }

    /**
     * Handle group click
     * Called by Token Action HUD Core when a group is right-clicked while the HUD is locked
     * @override
     * @param {object} event The event
     * @param {object} group The group
     */
    async handleGroupClick(event, group) {
    }

    /**
     * Handle action
     * @private
     * @param {object} event        The event
     * @param {object} actor        The actor
     * @param {object} token        The token
     * @param {string} actionTypeId The action type id
     * @param {string} actionId     The actionId
     */
    async #handleAction(event, actor, token, actionTypeId, actionId) {
      switch (actionTypeId) {
        case 'characteristics':
          await this.#handleCharacteristicsAction(event, actor, actionId)
          break
        case 'skills':
          await this.#handleSkillsAction(event, actor, actionId)
          break
        case 'weapons':
          await this.#handleWeaponsAction(event, actor, actionId)
          break
        case 'damage':
          await this.#handleDamageAction(event, actor, actionId)
          break
        case 'lethality':
          await this.#handleLethalityAction(event, actor, actionId)
          break
        /* case 'rituals':
        await this.#handleRitualsAction(event, actor, actionId)
        break */
        case 'utility':
          await this.#handleUtilityAction(token, actionId)
          break
      }
    }

    /**
     * Handle Characteristic action
     * @private
     * @param {object} event    The event
     * @param {object} actor    The actor
     * @param {string} actionId The action id
     */
    async #handleCharacteristicsAction(event, actor, actionId) {
      if (actionId === 'wp' || actionId === 'hp') return

      if (actionId.includes('_add') || actionId.includes('_subtract')) {
        const attr = actionId.split('_')[0]
        const action = actionId.split('_')[1]
        const update = {}
        update.system = {}
        update.system[attr] = {}
        update.system[attr].value = action === 'add' ? actor.system[attr].value + 1 : actor.system[attr].value - 1
        if (update.system[attr].value > actor.system[attr].max || update.system[attr].value < actor.system[attr].min) return
        return await actor.update(update)
      }
      if (actionId === 'san') {
        let item = foundry.utils.duplicate(actor.system.san)
        item.name = game.i18n.localize("CTHULHUETERNAL.Label.SAN")
        item.targetScore = item.value
        await actor.system.roll('san', item)
      } else if (actionId === 'luck') {
        let item = foundry.utils.duplicate(actor.system.characteristics.int)
        item.name = game.i18n.localize("CTHULHUETERNAL.Label.Luck")
        item.value = 10
        item.targetScore = 50
        await actor.system.roll('luck', item)
      } else {
        let item = foundry.utils.duplicate(actor.system.characteristics[actionId])
        item.name = game.i18n.localize(`CTHULHUETERNAL.Label.${actionId}Long`)
        item.targetScore = item.value * 5
        await actor.system.roll('char', item)
      }
    }

    /**
     * Handle Skill action
     * @private
     * @param {object} event    The event
     * @param {object} actor    The actor
     * @param {string} actionId The action id
     */
    async #handleSkillsAction(event, actor, actionId) {
      const skill = actor.items.find(i => i.type === 'skill' && i.id === actionId)
      if (!skill) return ui.notifications.warn(`Skill not found for action id '${actionId}'`)
      await actor.system.roll('skill', skill)
    }


    /**
     * Handle Weapon action
     * @private
     * @param {object} event    The event
     * @param {object} actor    The actor
     * @param {string} actionId The action id
     */
    async #handleWeaponsAction(event, actor, actionId) {
      const weapon = actor.items.find(i => i.type === 'weapon' && i.id === actionId)
      if (!weapon) return ui.notifications.warn(`Weapon not found for action id '${actionId}'`)
      weapon.damageFormula = weapon.system.damage
      weapon.damageBonus = actor.system.damageBonus
      await actor.system.roll('weapon', weapon)
    }

    /**
     * Handle Damage action
     * @private
     * @param {object} event    The event
     * @param {object} actor    The actor
     * @param {string} actionId The action id
     */
    async #handleDamageAction(event, actor, actionId) {
      const weapon = actor.items.find(i => i.type === 'weapon' && i.id === actionId)
      if (!weapon) return ui.notifications.warn(`Weapon not found for action id '${actionId}'`)
      weapon.damageFormula = weapon.system.damage
      weapon.damageBonus = actor.system.damageBonus
      await actor.system.roll('damage', weapon)
    }

    /**
     * Handle Lethality action
     * @private
     * @param {object} event    The event
     * @param {object} actor    The actor
     * @param {string} actionId The action id
     */
    async #handleLethalityAction(event, actor, actionId) {
      const item = actor.items.get(actionId)
      if (item.system.damage !== '' && event.ctrlKey) {
        const isLethal = !item.system.isLethal
        await item.update({ 'system.isLethal': isLethal })
      } else {
        const options = {
          actor,
          rollType: 'lethality',
          key: item.system.lethality,
          item
        }
        /* TOFIX
        const roll = new DGLethalityRoll(item.system.damage, {}, options)
        await this.actor.sheet.processRoll(event, roll)*/
      }
    }

    /**
     * Handle Ritual action
     * @private
     * @param {object} event    The event
     * @param {object} actor    The actor
     * @param {string} actionId The action id
     */
    async #handleRitualsAction(event, actor, actionId) {
      const options = {
        actor: this.actor,
        rollType: 'ritual',
        key: actionId
      }
      const roll = new DGPercentileRoll('1D100', {}, options)
      await this.actor.sheet.processRoll(event, roll)
    }

    /**
     * Handle utility action
     * @private
     * @param {object} token    The token
     * @param {string} actionId The action id
     */
    async #handleUtilityAction(token, actionId) {
      switch (actionId) {
        case 'endTurn':
          if (game.combat?.current?.tokenId === token.id) {
            await game.combat?.nextTurn()
          }
          break
      }
    }
  }
})
