import { ROLL_TYPES, rollSkill, skillCheckDialog } from "./rolls.mjs";

/**
 * Custom Actor document class for UA2e characters.
 */
export class UA2eActor extends Actor {

  /** Roll an Initiative value for the combat tracker. */
  async rollInitiative(options = {}) {
    if (this.type !== "character") return super.rollInitiative(options);

    const initValue = Math.floor(this.system.stats.speed.value / 2);

    // Player can choose to roll (hoping to roll under Speed for the actual value)
    // or just use their fixed Initiative score.
    const roll = await Dialog.confirm({
      title:   game.i18n.localize("UA2E.Initiative.Title"),
      content: `<p>${game.i18n.format("UA2E.Initiative.Prompt", { score: initValue })}</p>`
    });

    let finalInit;
    if (roll) {
      // Roll d100 under Speed; if success, use the roll result
      const r = new Roll("1d100");
      await r.evaluate();
      const rolled = r.total === 100 ? 0 : r.total;
      const speed  = this.system.stats.speed.value;
      finalInit = (rolled !== 0 && rolled <= speed) ? rolled : initValue;
    } else {
      finalInit = initValue;
    }

    // Set initiative on the connected combatant
    const combatants = this.isToken
      ? [game.combat?.combatants.find(c => c.tokenId === this.token?.id)]
      : game.combat?.combatants.filter(c => c.actorId === this.id) ?? [];
    for (const combatant of combatants.filter(Boolean)) {
      await combatant.update({ initiative: finalInit });
    }
    return finalInit;
  }

  /**
   * Roll against a skill item.
   * @param {string} skillId - Item ID of the skill to roll
   */
  async rollSkill(skillId) {
    const skill = this.items.get(skillId);
    if (!skill || !["skill", "strangeness"].includes(skill.type)) return;

    const statKey     = skill.type === "strangeness" ? "soul" : skill.system.stat;
    const skillValue  = skill.system.value;
    const statValue   = this.system.stats[statKey]?.value ?? 50;
    const canFlipFlop = skill.id === this.system.obsessionSkillId;

    return skillCheckDialog({
      actorId:     this.id,
      label:       skill.name,
      skill:       skillValue,
      stat:        statValue,
      canFlipFlop
    });
  }

  /**
   * Roll directly against a stat (unskilled check).
   * @param {string} statKey - "body" | "speed" | "mind" | "soul"
   */
  async rollStat(statKey) {
    const statValue = this.system.stats[statKey]?.value ?? 50;
    const label = game.i18n.localize(`UA2E.Stats.${statKey.capitalize()}`);

    return skillCheckDialog({
      actorId: this.id,
      label,
      skill:   0,
      stat:    statValue
    });
  }

  /**
   * Roll a simple Mind check for a stress meter and apply the result.
   * @param {string} meter - "violence"|"unnatural"|"helplessness"|"isolation"|"self"
   */
  async rollStressCheck(meter) {
    const stat = this.system.stats.mind?.value ?? 50;
    const label = `${game.i18n.localize(`UA2E.Stress.${meter.capitalize()}`)} ${game.i18n.localize("UA2E.Roll.Simple")}`;
    const result = await rollSkill({
      actorId: this.id,
      label,
      skill: 0,
      stat,
      checkType: ROLL_TYPES.SIMPLE
    });

    if (!result) return null;
    if (result.success) await this.addHardenedNotch(meter);
    else await this.addFailedNotch(meter);
    return result;
  }

  /**
   * Apply damage to wound points.
   * @param {number} damage
   */
  async applyDamage(damage) {
    damage = Math.round(Math.max(1, damage));
    const hp = this.system.woundPoints;
    await this.update({ "system.woundPoints.value": Math.max(0, hp.value - damage) });

    let msg;
    if (hp.value - damage <= 0)
      msg = game.i18n.format("UA2E.Damage.Dead", { name: this.name });
    else if (hp.value - damage <= 5)
      msg = game.i18n.format("UA2E.Damage.Unconscious", { name: this.name, dmg: damage });
    else
      msg = game.i18n.format("UA2E.Damage.Taken", { name: this.name, dmg: damage });

    await ChatMessage.implementation.create({
      speaker: ChatMessage.getSpeaker({ actor: this }),
      content: msg
    });
  }

  /**
   * Add a failed notch to a stress meter.
   * @param {string} meter - "violence"|"unnatural"|"helplessness"|"isolation"|"self"
   */
  async addFailedNotch(meter) {
    const current = this.system.stressMeters[meter]?.failed ?? 0;
    await this.update({ [`system.stressMeters.${meter}.failed`]: Math.min(5, current + 1) });
  }

  /**
   * Add a hardened notch to a stress meter.
   * @param {string} meter
   */
  async addHardenedNotch(meter) {
    const current = this.system.stressMeters[meter]?.hardened ?? 0;
    await this.update({ [`system.stressMeters.${meter}.hardened`]: Math.min(10, current + 1) });
  }
}

/**
 * Custom Item document class.
 */
export class UA2eItem extends Item {
  /** Roll a skill check for this item (if it is a skill). */
  async roll() {
    if (this.type === "skill" && this.actor) {
      return this.actor.rollSkill(this.id);
    }
  }
}
