// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT

import { DS4 } from "../../../config";
import { createCheckRoll } from "../../../dice/check-factory";
import { notifications } from "../../../ui/notifications";
import { getGame } from "../../../utils/utils";
import { DS4Item } from "../item";

export class DS4Weapon extends DS4Item {
  /** @override */
  prepareDerivedData() {
    const system = this.system;
    system.rollable = system.equipped;
    system.opponentDefenseForAttackType = {};
    if (system.attackType === "melee" || system.attackType === "meleeRanged") {
      system.opponentDefenseForAttackType.melee = system.opponentDefense;
    }
    if (system.attackType === "ranged" || system.attackType === "meleeRanged") {
      system.opponentDefenseForAttackType.ranged = system.opponentDefense;
    }
  }

  /** @override */
  async roll(options = {}) {
    const game = getGame();
    if (!this.system.equipped) {
      return notifications.warn(
        game.i18n.format("DS4.WarningItemMustBeEquippedToBeRolled", {
          name: this.name,
          id: this.id,
          type: this.type,
        }),
      );
    }

    if (!this.actor) {
      throw new Error(game.i18n.format("DS4.ErrorCannotRollUnownedItem", { name: this.name, id: this.id }));
    }

    const ownerSystemData = this.actor.system;
    const weaponBonus = this.system.weaponBonus;
    const attackType = await this.getPerformedAttackType();
    const opponentDefense = this.system.opponentDefenseForAttackType[attackType];
    const combatValue = `${attackType}Attack`;
    const checkTargetNumber = ownerSystemData.combatValues[combatValue].total + weaponBonus;
    const speaker = ChatMessage.getSpeaker({ actor: this.actor, ...options.speaker });
    const flavor =
      opponentDefense !== undefined && opponentDefense !== 0
        ? "DS4.ItemWeaponCheckFlavorWithOpponentDefense"
        : "DS4.ItemWeaponCheckFlavor";
    /** @type {import("../../../dice/check-factory").DS4CheckFactoryOptions["flavorData"]} */
    const flavorData = {
      actor: speaker.alias ?? this.actor.name,
      weapon: this.name,
    };
    if (opponentDefense !== undefined && opponentDefense !== 0) {
      flavorData.opponentDefense = (opponentDefense < 0 ? "" : "+") + opponentDefense;
    }

    await createCheckRoll(checkTargetNumber, {
      rollMode: getGame().settings.get("core", "rollMode"),
      maximumCoupResult: ownerSystemData.rolling.maximumCoupResult,
      minimumFumbleResult: ownerSystemData.rolling.minimumFumbleResult,
      speaker,
      flavor,
      flavorData,
    });

    Hooks.callAll("ds4.rollItem", this);
  }

  /**
   * Get the attack type to perform with this weapon. If there are multiple options prompt the user for a choice.
   * @returns {Promise<"melee" | "ranged">} The attack type to perform
   * @protected
   */
  async getPerformedAttackType() {
    if (this.system.attackType !== "meleeRanged") {
      return this.system.attackType;
    }

    const { melee, ranged } = { ...DS4.i18n.attackTypes };
    const identifier = `attack-type-selection-${foundry.utils.randomID()}`;
    return Dialog.prompt({
      title: getGame().i18n.localize("DS4.DialogAttackTypeSelection"),
      content: await renderTemplate("systems/ds4/templates/dialogs/simple-select-form.hbs", {
        selects: [
          {
            label: getGame().i18n.localize("DS4.AttackType"),
            identifier,
            options: { melee, ranged },
          },
        ],
      }),
      label: getGame().i18n.localize("DS4.GenericOkButton"),
      callback: (html) => {
        const selectedAttackType = html.find(`#${identifier}`).val();
        if (selectedAttackType !== "melee" && selectedAttackType !== "ranged") {
          throw new Error(
            getGame().i18n.format("DS4.ErrorUnexpectedAttackType", {
              actualType: selectedAttackType,
              expectedTypes: "'melee', 'ranged'",
            }),
          );
        }
        return selectedAttackType;
      },
    });
  }
}
