import { VermineUtils } from "../roll.mjs";
import { VermineExchange } from "../exchange.mjs";
import { VermineTraits } from "../traits.mjs";

const { HandlebarsApplicationMixin } = foundry.applications.api;

/**
 * Dialogue d'attaque pour les échanges de coups.
 * Prépare le pool, la difficulté (contact / distance) et le contexte
 * d'échange (cibles, dégâts de base) selon le type d'acteur :
 * - Personnage : capacité + compétence de l'arme.
 * - PNJ : pool d'attaque du niveau de menace + réserves de rôle.
 * - Créature : pool d'attaque calculé, difficulté du statut de combat.
 */
export default class CombatDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {

  static DEFAULT_OPTIONS = {
    classes: ["vermine-roll"],
    tag: "form",
    window: {
      icon: "fas fa-crosshairs",
      resizable: false
    },
    position: {
      width: 520,
      height: 600
    },
    actions: {
      roll: CombatDialog.#onRoll,
      cancel: CombatDialog.#onCancel
    }
  };

  static PARTS = {
    main: { template: "systems/vermine2047/templates/dialogs/combat-dialog.hbs" }
  };

  static async create({ actorId, weapon = null }) {
    const actor = await game.actors.get(actorId);
    if (!actor) {
      ui.notifications.warn(game.i18n.localize("VERMINE.error_no_actor_selected"));
      return null;
    }
    const mode = actor.type === "creature" ? "contact" : VermineExchange.modeForWeapon(weapon);
    return new CombatDialog({ actor, weapon, mode });
  }

  constructor(options = {}) {
    super(options);
    this.actor = options.actor;
    this.weapon = options.weapon ?? null;
    this.mode = options.mode ?? "contact";
    this.abilityKey = VermineExchange.attackAbility(this.mode);
    // Une arme sans compétence définie est traitée comme une attaque
    // improvisée au contact : Corps-à-corps (Vigueur + pool Corps-à-corps).
    this.skillKey = this.weapon?.system?.skill || 'close';
    this.skillValue = this.skillKey ? (this.actor.system?.skills?.[this.skillKey]?.value || 0) : 0;
    this.skillPool = this.skillValue ? (CONFIG.VERMINE.SkillLevels?.[this.skillValue]?.dicePool || 0) : 0;
    this.skillReroll = this.skillValue ? (CONFIG.VERMINE.SkillLevels?.[this.skillValue]?.reroll || 0) : 0;
    this.basePool = VermineExchange.baseAttackPool(this.actor, this.weapon, this.mode);
    this.baseDamage = VermineExchange.baseDamage(this.actor, this.weapon);
    this.rafaleValue = this.mode === "ranged" ? VermineTraits.traitValue(this.weapon, "rafale") : 0;
    this.rapideHandicap = VermineTraits.traitValue(this.weapon, "rapide");
    this.zoneValue = VermineTraits.traitValue(this.weapon, "zone");
    const portee = VermineTraits.traitValue(this.weapon, "portee");
    this.effectiveRange = this.mode === "ranged" && portee > 0 ? portee * VermineTraits.vigor(this.actor) : null;
  }

  get title() {
    return game.i18n.localize("VERMINE.attack");
  }

  async _prepareContext() {
    const actor = this.actor;
    const isCharacter = actor.type === "character";
    const isNpc = actor.type === "npc";
    const isCreature = actor.type === "creature";

    const targets = [...game.user.targets].map(t => ({
      id: t.actor?.id ?? null,
      uuid: t.actor?.uuid ?? null,
      name: t.name,
      canDefend: t.actor?.type !== "creature"
    }));

    let difficultyOptions = [];
    let lockedDifficulty = null;
    let defaultDifficulty = null;

    if (isCreature) {
      const d = parseInt(actor.system?.combatStatus?.difficulty, 10) || 9;
      lockedDifficulty = d;
      difficultyOptions = [{ difficulty: d, label: "", locked: true }];
      defaultDifficulty = d;
    } else if (this.mode === "ranged") {
      difficultyOptions = VermineExchange.rangeDifficultyOptions().map(o => ({
        difficulty: o.difficulty,
        label: game.i18n.localize(o.label),
        rangeKey: o.key
      }));
      defaultDifficulty = difficultyOptions[0]?.difficulty ?? 7;
    } else if (isNpc) {
      difficultyOptions = VermineExchange.npcDifficultyOptions(actor).map(d => ({
        difficulty: d,
        label: String(d)
      }));
      defaultDifficulty = difficultyOptions[0]?.difficulty ?? 7;
    } else {
      difficultyOptions = VermineExchange.contactDifficultyOptions(this.skillValue).map(d => ({
        difficulty: d,
        label: String(d)
      }));
      defaultDifficulty = difficultyOptions[0]?.difficulty ?? 7;
    }

    // Cible de type créature : défense passive, la difficulté d'attaque est
    // forcée au statut de combat de la créature (toute réussite ≥1 touche).
    const creatureTargets = targets.filter(t => t.id && !t.canDefend);
    const creatureLocked = !isCreature && creatureTargets.length && creatureTargets.length === targets.length;
    if (creatureLocked) {
      const ref = creatureTargets[0];
      // uuid d'abord : un token non lié ne doit pas résoudre vers l'acteur
      // monde dont il est issu (même principe que VermineExchange).
      const creature = await VermineExchange.resolveDefender({ id: ref.id, uuid: ref.uuid });
      const d = parseInt(creature?.system?.combatStatus?.difficulty, 10) || 7;
      lockedDifficulty = d;
      difficultyOptions = [{ difficulty: d, label: "", locked: true }];
      defaultDifficulty = d;
    }

    const threat = actor.system?.threat?.value || 1;
    const role = actor.system?.role?.value || 1;

    return {
      actor,
      system: actor.system,
      config: CONFIG.VERMINE,
      actorType: actor.type,
      mode: this.mode,
      weapon: this.weapon,
      abilityKey: this.abilityKey,
      abilityValue: actor.system?.abilities?.[this.abilityKey]?.value || 0,
      skillKey: this.skillKey,
      skillValue: this.skillValue,
      basePool: this.basePool,
      baseDamage: this.baseDamage,
      isCharacter,
      isNpc,
      isCreature,
      creatureLocked,
      npcThreatPool: isNpc ? (CONFIG.VERMINE.npcThreatLevels?.[threat]?.attack || 0) : 0,
      npcPoolMax: isNpc ? (CONFIG.VERMINE.npcRoleLevels?.[role]?.pools || 0) : 0,
      difficultyOptions,
      lockedDifficulty,
      defaultDifficulty,
      hasAmmo: this.mode === "ranged" && (this.weapon?.system?.ammo ?? 0) > 0,
      // Specialties are only usable when they match the attack skill.
      availableSpecialties: actor.items.filter(i => i.type === "specialty" && i.system?.skill === this.skillKey),
      availableItems: actor.items.filter(i => i.type === "item"),
      targets,
      lourdMalus: VermineTraits.lourdMalus(actor),
      mobilityNote: VermineTraits.mobilityNote(actor),
      hasRafale: this.rafaleValue > 0,
      rafaleValue: this.rafaleValue,
      effectiveRange: this.effectiveRange
    };
  }

  async _onRender(context, options) {
    this.element.dataset.actorId = this.actor.id;
    this.element.dataset.weaponId = this.weapon?.id ?? "";
    this.element.dataset.mode = this.mode;

    for (const inp of this.element.querySelectorAll("[data-roll]")) {
      inp.addEventListener("change", this.#onInputChange.bind(this));
    }

    const selfControl = this.element.querySelector("#self_control");
    if (selfControl) {
      selfControl.addEventListener("change", this.#onChangeSelfControl.bind(this));
    }

    this.element.querySelector("#second-action")?.addEventListener("change", () => this.#updateUI());
    this.element.querySelector("#handicap")?.addEventListener("change", () => this.#updateUI());
    this.element.querySelector("#rafale")?.addEventListener("change", () => this.#updateUI());
    this.element.querySelector("#human-totem")?.addEventListener("change", () => this.#updateUI());
    this.element.querySelector("#adapted-totem")?.addEventListener("change", () => this.#updateUI());
    this.element.querySelector("#pools-spent")?.addEventListener("change", () => this.#updateUI());

    const ability = this.element.querySelector("#ability");
    if (ability && this.actor.type === "character") {
      const sc = this.element.querySelector("#self_control");
      if (sc) sc.max = ability.value;
    }

    this.#updateUI();
  }

  // ── Getters ──────────────────────────────────────────────────────────

  get #el() { return this.element; }

  #getDifficultyBase() {
    const el = this.#el.querySelector('input[name="combat-difficulty"]:checked');
    return parseInt(el?.value, 10) || 7;
  }

  #getSecondAction() {
    return this.#el.querySelector("#second-action")?.checked ?? false;
  }

  #getHandicap() {
    const sel = this.#el.querySelector("#handicap");
    return Math.max(0, (parseInt(sel?.value, 10) || 1) - 1);
  }

  #getSelfCtrl() {
    return parseInt(this.#el.querySelector("#self_control")?.value, 10) || 0;
  }

  #getPoolsSpent() {
    return parseInt(this.#el.querySelector("#pools-spent")?.value, 10) || 0;
  }

  #getTemporaryMalus() {
    return parseInt(this.#el.querySelector("#temporary-malus")?.value, 10) || 0;
  }

  #getUseAmmo() {
    return this.#el.querySelector("#use-ammo")?.checked ?? false;
  }

  #getRafale() {
    return this.#el.querySelector("#rafale")?.checked ?? false;
  }

  #getTotems() {
    return {
      human: this.#el.querySelector("#human-totem")?.checked ?? false,
      adapted: this.#el.querySelector("#adapted-totem")?.checked ?? false
    };
  }

  #getKeepTotem() {
    return this.#el.querySelector("#keep-totem-select")?.value ?? null;
  }

  getDifficultySelect() {
    return this.#getDifficultyBase() + (this.#getSecondAction() ? 2 : 0) + (this.#getRafale() ? 2 : 0);
  }

  getSkillCategory() {
    if (this.actor.type !== "character" || !this.skillKey) return null;
    return this.actor.system.skills[this.skillKey]?.category ?? null;
  }

  getSkillLevel() {
    return this.actor.type === "character" && this.skillValue ? this.skillValue : null;
  }

  getReroll() {
    if (this.actor.type === "npc") {
      const exp = this.actor.system?.experience?.value || 1;
      return CONFIG.VERMINE.npcExperienceLevels?.[exp]?.rerolls || 0;
    }
    if (this.actor.type === "creature") return 0;
    return this.skillReroll;
  }

  getMaxEffort() {
    if (this.actor.type !== "character") return 0;
    const ability = this.actor.system?.abilities?.[this.abilityKey]?.value || 0;
    const effort = this.actor.system?.attributes?.effort?.value || 0;
    return Math.min(ability, effort);
  }

  getPoolBreakdown() {
    const ability = this.actor.type === "character"
      ? (this.actor.system?.abilities?.[this.abilityKey]?.value || 0)
      : 0;
    const skill = this.actor.type === "character" ? this.skillPool : 0;
    const selfControl = this.#getSelfCtrl();
    const pools = this.actor.type === "npc" ? this.#getPoolsSpent() : 0;
    const specialty = this.#hasSpecialtySelected() ? 1 : 0;
    const help = this.#el.querySelector("#helped")?.checked ? 1 : 0;
    const toolsChecked = this.#el.querySelector("input[name='usingTools']:checked");
    const tooling = toolsChecked && toolsChecked.value !== "0" ? 1 : 0;
    const group = parseInt(this.#el.querySelector("#group")?.value, 10) || 0;
    const wound = VermineExchange.woundMalus(this.actor);
    const lourd = VermineTraits.lourdMalus(this.actor);
    const tempMalus = this.#getTemporaryMalus();
    const malus = wound + lourd + tempMalus;
    const total = Math.max(0, this.basePool + selfControl + pools + specialty + help + tooling + group - malus);
    return { ability, skill, selfControl, pools, specialty, help, tooling, group, wound, lourd, tempMalus, malus, total };
  }

  getDicePool() {
    return this.getPoolBreakdown().total;
  }

  #hasSpecialtySelected() {
    const checked = this.#el.querySelector("input[name='usingSpecialization']:checked");
    return Boolean(checked && checked.value !== "aucune");
  }

  getSpecialtyName() {
    const checked = this.#el.querySelector("input[name='usingSpecialization']:checked");
    return checked && checked.value !== "aucune" ? checked.value : null;
  }

  getLabel() {
    const base = this.mode === "ranged"
      ? game.i18n.localize("VERMINE.attack_ranged")
      : game.i18n.localize("VERMINE.attack_contact");
    return this.weapon ? `${base} (${this.weapon.name})` : base;
  }

  // ── UI ───────────────────────────────────────────────────────────────

  #updateUI() {
    const total = this.getDicePool();
    const totalEl = this.#el.querySelector("#dice-pool-total");
    if (totalEl) totalEl.textContent = `${total}D`;

    const finalEls = this.#el.querySelectorAll("#final-difficulty");
    for (const el of finalEls) el.textContent = this.getDifficultySelect();

    const b = this.getPoolBreakdown();
    const bonusEl = this.#el.querySelector("#total-bonus");
    if (bonusEl) bonusEl.textContent = b.selfControl + b.pools + b.specialty + b.help + b.tooling + b.group - b.malus;

    const handSel = this.#el.querySelector("#handicap");
    const handEl = this.#el.querySelector("#current-handicap");
    if (handSel && handEl) {
      handEl.textContent = handSel.options[handSel.selectedIndex]?.text ?? "";
    }

    const specChecked = this.#el.querySelector("input[name='usingSpecialization']:checked");
    const specEl = this.#el.querySelector(".current-specialty");
    if (specEl && specChecked) {
      specEl.textContent = specChecked.value === "aucune"
        ? game.i18n.localize("VERMINE.none")
        : specChecked.value;
    }
  }

  #onInputChange() {
    this.#updateUI();
  }

  #onChangeSelfControl(ev) {
    const valEl = this.#el.querySelector("#self_control_value");
    if (valEl) valEl.textContent = ev.currentTarget.value;
    this.#updateUI();
  }

  static async #onCancel(event, target) {
    this.close();
  }

  static async #onRoll(event, target) {
    const selfCtrl = this.getPoolBreakdown().selfControl;
    if (selfCtrl > 0) {
      const current = this.actor?.system?.attributes?.self_control?.value ?? 0;
      if (current < selfCtrl) {
        ui.notifications.warn(game.i18n.localize("VERMINE.error_not_enough_self_control"));
        return;
      }
    }

    const finalDifficulty = this.getDifficultySelect();

    // Consommation de munitions (armes à distance)
    if (this.mode === "ranged" && this.#getUseAmmo() && this.weapon) {
      const ammo = this.weapon.system.ammo || 0;
      if (ammo > 0) {
        await this.weapon.update({ "system.ammo": ammo - 1 });
      }
    }

    if (selfCtrl > 0) {
      const newVal = this.actor.system.attributes.self_control.value - selfCtrl;
      await this.actor.update({ "system.attributes.self_control.value": newVal });
    }

    const targets = [...game.user.targets].map(t => ({
      id: t.actor?.id ?? null,
      uuid: t.actor?.uuid ?? null,
      name: t.name,
      canDefend: t.actor?.type !== "creature"
    }));

    const attack = {
      id: foundry.utils.randomID(),
      attackerId: this.actor.id,
      attackerName: this.actor.name,
      mode: this.mode,
      difficulty: finalDifficulty,
      range: this.mode === "ranged" ? this.#getRangeKey() : null,
      secondAction: this.#getSecondAction(),
      baseDamage: this.baseDamage,
      targets,
      weapon: this.weapon
        ? { name: this.weapon.name, img: this.weapon.img, damage: foundry.utils.duplicate(this.weapon.system.damage) }
        : null,
      rapideHandicap: this.rapideHandicap || null,
      zoneValue: this.zoneValue || null
    };

    const rafale = this.#getRafale();

    const rollParams = {
      actor: this.actor,
      NoD: this.getDicePool(),
      Reroll: this.getReroll(),
      difficulty: finalDifficulty,
      handicap: this.#getHandicap(),
      rollLabel: this.getLabel(),
      totems: this.#getTotems(),
      self_control: selfCtrl,
      max_effort: this.getMaxEffort(),
      keepTotem: this.#getKeepTotem(),
      skillCategory: this.getSkillCategory(),
      skillLevel: this.getSkillLevel(),
      hasSpecialty: this.#hasSpecialtySelected(),
      poolBreakdown: this.getPoolBreakdown(),
      specialtyName: this.getSpecialtyName(),
      weapon: this.weapon?.toObject() ?? null,
      targets: targets.map(t => t.name),
      attack,
      messageFlags: { "vermine-exchange": attack }
    };
    if (rafale && this.rafaleValue > 0) {
      rollParams.bonusSuccesses = this.rafaleValue;
      rollParams.bonusOnSuccess = true;
    }
    if (this.effectiveRange !== null) rollParams.effectiveRange = this.effectiveRange;
    const mobilityHandicap = VermineTraits.mobilityHandicap(this.actor);
    if (mobilityHandicap > 0) rollParams.mobilityHandicap = mobilityHandicap;

    // Fermeture immédiate du dialogue : le jet (et l'animation 3D) continue
    // en arrière-plan sans bloquer la fermeture.
    this.close();

    await VermineUtils.roll(rollParams);
  }

  #getRangeKey() {
    const el = this.#el.querySelector('input[name="combat-difficulty"]:checked');
    return el?.dataset?.rangeKey ?? null;
  }
}
