import type {
  AbilityDefinition,
  AbilityLoadout,
  AbilitySlotId,
  HealerAbilityId,
  HealerClassDefinition,
  HealerClassId,
  HealerPulseKind,
  InventoryItem,
} from "./types";
import { ABILITY_CONTROLLER_BINDINGS } from "./controllerBindings";

const slotBindings: Record<AbilitySlotId, Pick<AbilityDefinition, "slot" | "key" | "gamepad">> = {
  ability1: { slot: "ability1", key: "1", gamepad: ABILITY_CONTROLLER_BINDINGS.ability1.glyph },
  ability2: { slot: "ability2", key: "2", gamepad: ABILITY_CONTROLLER_BINDINGS.ability2.glyph },
  ability3: { slot: "ability3", key: "3", gamepad: ABILITY_CONTROLLER_BINDINGS.ability3.glyph },
  ability4: { slot: "ability4", key: "4", gamepad: ABILITY_CONTROLLER_BINDINGS.ability4.glyph },
  ability5: { slot: "ability5", key: "5", gamepad: ABILITY_CONTROLLER_BINDINGS.ability5.glyph },
  ability6: { slot: "ability6", key: "6", gamepad: ABILITY_CONTROLLER_BINDINGS.ability6.glyph },
};

function ability(
  slot: AbilitySlotId,
  id: HealerAbilityId,
  pulseKind: HealerPulseKind,
  targeting: AbilityDefinition["targeting"],
  definition: Omit<AbilityDefinition, "slot" | "id" | "pulseKind" | "key" | "gamepad" | "targeting">,
): AbilityDefinition {
  return { ...slotBindings[slot], id, pulseKind, targeting, ...definition };
}

export const HEALER_CLASS_ORDER: HealerClassId[] = ["priest", "druid", "shaman", "paladin", "chronomancer"];

export function isHealerClassId(value: string): value is HealerClassId {
  return HEALER_CLASS_ORDER.includes(value as HealerClassId);
}

export const HEALER_CLASSES: Record<HealerClassId, HealerClassDefinition> = {
  priest: {
    id: "priest",
    name: "Priest",
    specialization: "Discipline Priest",
    icon: "✦",
    color: "#e8c872",
    resourceName: "Grace",
    description: "Direct healing, protective shields, cleansing, and a damage-reducing sanctuary.",
    abilities: {
      ability1: ability("ability1", "priest-mend", "direct-heal", "ally", { name: "Mend", shortName: "Mend", cooldown: 0, castTime: 0.5, mana: 5, icon: "+", description: "Cast for 0.5 seconds to heal the selected ally for 38 health. No cooldown.", color: "#fff0bd" }),
      ability2: ability("ability2", "priest-renew", "periodic-heal", "ally", { name: "Renew", shortName: "Renew", cooldown: 0, mana: 7, icon: "✣", description: "Heal selected ally for 7 health every second for 8 seconds. No cooldown.", color: "#71df9c" }),
      ability3: ability("ability3", "priest-aegis-shield", "protective", "ally", { name: "Aegis Shield", shortName: "Shield", cooldown: 10, mana: 8, icon: "◇", description: "Give selected ally a 36-point damage shield.", color: "#6fc6ff" }),
      ability4: ability("ability4", "priest-purify", "cleanse", "ally", { name: "Purify", shortName: "Purify", cooldown: 3, mana: 5, icon: "✧", description: "Dispel all harmful magic from the selected ally.", color: "#b58cff" }),
      ability5: ability("ability5", "priest-radiance", "group-heal", "party", { name: "Radiance", shortName: "Radiance", cooldown: 14, mana: 12, icon: "☀", description: "Heal every party member for 22 health.", color: "#ffd66b" }),
      ability6: ability("ability6", "priest-barrier", "field", "party", { name: "Barrier", shortName: "Barrier", cooldown: 60, mana: 10, icon: "◉", description: "Place a 4m field at your feet for 8 seconds. Allies inside take 30% less damage.", color: "#f2cf55" }),
    },
  },
  druid: {
    id: "druid",
    name: "Druid",
    specialization: "Restoration Druid",
    icon: "❧",
    color: "#79d36f",
    resourceName: "Mana",
    secondaryResourceName: "Verdancy",
    description: "Proactive regeneration, layered growth effects, and well-timed blooms.",
    abilities: {
      ability1: ability("ability1", "druid-regrowth", "direct-heal", "ally", { name: "Regrowth", shortName: "Regrowth", cooldown: 0, castTime: 0.5, mana: 5, icon: "❦", description: "Heal for 24, then 4 each second for 6 seconds. Consumes up to 3 Verdancy for 7 more healing each.", color: "#b8ef8b" }),
      ability2: ability("ability2", "druid-rejuvenation", "periodic-heal", "ally", { name: "Rejuvenation", shortName: "Rejuvenate", cooldown: 0, mana: 6, icon: "☘", description: "Restore 6 health each second for 8 seconds. Each tick generates Verdancy.", color: "#63d77e" }),
      ability3: ability("ability3", "druid-lifebloom", "periodic-heal", "ally", { name: "Lifebloom", shortName: "Lifebloom", cooldown: 0, mana: 5, icon: "♧", description: "Stack up to 3 times for 7 seconds. Heals over time, then blooms for 10 per stack. At 3 stacks, spend 2 Verdancy to bloom now.", color: "#a6c76b" }),
      ability4: ability("ability4", "druid-natures-cure", "cleanse", "ally", { name: "Nature's Cure", shortName: "Nature Cure", cooldown: 3, mana: 5, icon: "✤", description: "Dispel all harmful magic and immediately trigger every healing-over-time effect on the target.", color: "#8de2b2" }),
      ability5: ability("ability5", "druid-wild-growth", "group-heal", "party", { name: "Wild Growth", shortName: "Wild Growth", cooldown: 14, mana: 12, icon: "✾", description: "Heal the three most injured allies for 5 health each second for 6 seconds.", color: "#d1ed73" }),
      ability6: ability("ability6", "druid-flourish", "field", "party", { name: "Flourish", shortName: "Flourish", cooldown: 60, mana: 10, icon: "◌", description: "Extend active Druid healing effects by 5 seconds and make them tick twice as fast for 6 seconds.", color: "#70bc72" }),
    },
  },
  shaman: {
    id: "shaman",
    name: "Shaman",
    specialization: "Restoration Shaman",
    icon: "ϟ",
    color: "#65b9ed",
    resourceName: "Mana",
    secondaryResourceName: "Tidal Surge",
    description: "Reactive burst healing through chain positioning, earth wards, and spirit links.",
    abilities: {
      ability1: ability("ability1", "shaman-healing-wave", "direct-heal", "ally", { name: "Healing Wave", shortName: "Heal Wave", cooldown: 0, castTime: 0.65, mana: 5, icon: "≈", description: "Heal for 34, increased by 35% below half health. Tidal Surge makes the cast faster and adds 10 healing.", color: "#8fdcf2" }),
      ability2: ability("ability2", "shaman-riptide", "periodic-heal", "ally", { name: "Riptide", shortName: "Riptide", cooldown: 6, mana: 6, icon: "≋", description: "Heal for 12, then 5 each second for 6 seconds. Marks a Chain Heal anchor and grants Tidal Surge.", color: "#54c9c5" }),
      ability3: ability("ability3", "shaman-earth-shield", "protective", "ally", { name: "Earth Shield", shortName: "Earth Shield", cooldown: 10, mana: 8, icon: "⬡", description: "Give an ally 6 charges for 30 seconds. Taking damage consumes a charge to heal for 9 and grants Tidal Surge.", color: "#d2b66c" }),
      ability4: ability("ability4", "shaman-cleanse-spirit", "cleanse", "ally", { name: "Cleanse Spirit", shortName: "Cleanse", cooldown: 3, mana: 5, icon: "✧", description: "Dispel all harmful magic from an ally. A successful cleanse grants Tidal Surge.", color: "#9aaef5" }),
      ability5: ability("ability5", "shaman-chain-heal", "group-heal", "ally", { name: "Chain Heal", shortName: "Chain Heal", cooldown: 12, mana: 12, icon: "⌁", description: "Heal the target, then jump through nearby injured allies with diminishing power. Tidal Surge adds jumps; Riptide strengthens the first heal.", color: "#6ee2db" }),
      ability6: ability("ability6", "shaman-spirit-link", "field", "party", { name: "Spirit Link Totem", shortName: "Spirit Link", cooldown: 60, mana: 10, icon: "◎", description: "Place an 8-second, 4m spirit field that equalizes nearby allies' health percentages each second.", color: "#9d8cf2" }),
    },
  },
  paladin: {
    id: "paladin",
    name: "Paladin",
    specialization: "Dawnforged Paladin",
    icon: "☼",
    color: "#f2a65a",
    resourceName: "Mana",
    secondaryResourceName: "Conviction",
    description: "Fight beside the party, turn offense into healing, and funnel light through a chosen beacon.",
    abilities: {
      ability1: ability("ability1", "paladin-holy-light", "direct-heal", "ally", { name: "Holy Light", shortName: "Holy Light", cooldown: 0, castTime: 0.55, mana: 5, icon: "✚", description: "Cast for 0.55 seconds to heal an ally for 34. Beacon of Light echoes 40% to its marked ally.", color: "#ffe29a" }),
      ability2: ability("ability2", "paladin-crusader-strike", "direct-heal", "enemy", { name: "Crusader Strike", shortName: "Crusader", cooldown: 4, mana: 3, icon: "⚔", description: "Strike the boss for 18 damage, heal the most injured ally for 18, and gain 1 Conviction.", color: "#f6b35f" }),
      ability3: ability("ability3", "paladin-beacon-of-light", "protective", "ally", { name: "Beacon of Light", shortName: "Beacon", cooldown: 8, mana: 7, icon: "♢", description: "Mark an ally for 30 seconds. Your single-target Paladin heals on others echo to the beacon for 40%.", color: "#ffd86b" }),
      ability4: ability("ability4", "paladin-cleanse-light", "cleanse", "ally", { name: "Cleanse Light", shortName: "Cleanse", cooldown: 3, mana: 5, icon: "✧", description: "Dispel all harmful magic from the selected ally and heal them for 10.", color: "#fff0bd" }),
      ability5: ability("ability5", "paladin-word-of-glory", "group-heal", "ally", { name: "Word of Glory", shortName: "Word Glory", cooldown: 0, mana: 6, icon: "✹", description: "Spend all Conviction to heal an ally for 18 plus 14 per point. At 3 Conviction, also heal the party for 8.", color: "#ffc857" }),
      ability6: ability("ability6", "paladin-avenging-crusader", "field", "party", { name: "Avenging Crusader", shortName: "Avenging", cooldown: 60, mana: 10, icon: "⚜", description: "For 10 seconds, 20% of party attack damage heals the most injured living ally.", color: "#ff9f43" }),
    },
  },
  chronomancer: {
    id: "chronomancer",
    name: "Chronomancer",
    specialization: "Continuum Chronomancer",
    icon: "◷",
    color: "#62d4d9",
    resourceName: "Mana",
    secondaryResourceName: "Chronoshards",
    description: "Prepare health snapshots, schedule healing echoes, and reverse damage after it happens.",
    abilities: {
      ability1: ability("ability1", "chronomancer-mend-timeline", "direct-heal", "ally", { name: "Mend Timeline", shortName: "Mend Time", cooldown: 0, castTime: 0.5, mana: 5, icon: "⌛", description: "Cast for 0.5 seconds to heal the selected ally for 30.", color: "#b5f4ef" }),
      ability2: ability("ability2", "chronomancer-time-anchor", "protective", "ally", { name: "Time Anchor", shortName: "Anchor", cooldown: 0, mana: 4, icon: "⌖", description: "Record an ally's health for 6 seconds. Recast on that ally to restore damage taken since and gain 1 Chronoshard.", color: "#6ce5df" }),
      ability3: ability("ability3", "chronomancer-echo-of-tomorrow", "periodic-heal", "ally", { name: "Echo of Tomorrow", shortName: "Tomorrow", cooldown: 6, mana: 7, icon: "◌", description: "Heal an ally for 10 now, then echo 28 healing after 3 seconds.", color: "#84cfff" }),
      ability4: ability("ability4", "chronomancer-erase-affliction", "cleanse", "ally", { name: "Erase Affliction", shortName: "Erase", cooldown: 3, mana: 5, icon: "⌫", description: "Dispel all harmful magic and gain 1 Chronoshard.", color: "#a99cff" }),
      ability5: ability("ability5", "chronomancer-accelerate", "group-heal", "party", { name: "Accelerate", shortName: "Accelerate", cooldown: 14, mana: 11, icon: "≫", description: "Spend all Chronoshards. Heal the party for 10 plus 8 per shard and reduce active cooldowns by 1 second per shard.", color: "#52c7e8" }),
      ability6: ability("ability6", "chronomancer-time-loop", "field", "party", { name: "Time Loop", shortName: "Time Loop", cooldown: 60, mana: 10, icon: "∞", description: "Record every living ally's health. After 6 seconds, restore any health lost since the loop began.", color: "#7d8cff" }),
    },
  },
};

/**
 * Flat spell registry used by run modes that compose abilities across healer
 * classes. Class screens remain projections of the same canonical definitions.
 */
const HEALER_ABILITY_ENTRIES = HEALER_CLASS_ORDER.flatMap((classId) =>
  Object.values(HEALER_CLASSES[classId].abilities).map((entry) => [entry.id, entry] as const),
);

/** Canonical deterministic order for every registered healer ability. */
export const HEALER_ABILITY_IDS: readonly HealerAbilityId[] = Object.freeze(
  HEALER_ABILITY_ENTRIES.map(([abilityId]) => abilityId),
);

export const HEALER_ABILITIES = Object.fromEntries(HEALER_ABILITY_ENTRIES) as Record<HealerAbilityId, AbilityDefinition>;

export const DEFAULT_ABILITY_LOADOUTS = Object.fromEntries(
  HEALER_CLASS_ORDER.map((classId) => [
    classId,
    Object.fromEntries(Object.entries(HEALER_CLASSES[classId].abilities).map(([slotId, entry]) => [slotId, entry.id])),
  ]),
) as Record<HealerClassId, Record<AbilitySlotId, HealerAbilityId>>;

export function createClassAbilityLoadout(classId: HealerClassId): Record<AbilitySlotId, HealerAbilityId> {
  return { ...DEFAULT_ABILITY_LOADOUTS[classId] };
}

export function resolveSlottedAbility(loadout: AbilityLoadout, slotId: AbilitySlotId): AbilityDefinition | undefined {
  const abilityId = loadout[slotId];
  return abilityId ? HEALER_ABILITIES[abilityId] : undefined;
}

const CLASS_INVENTORIES: Record<HealerClassId, InventoryItem[]> = {
  priest: [
    { id: "priest-censer", name: "Censer of First Light", slot: "Main Hand", rarity: "Rare", icon: "♰", stats: ["+12 Grace", "+8% Mend healing"], effect: "Mend restores 2 mana when it lands on an ally below 50% health.", equipped: true },
    { id: "priest-vestment", name: "Ashwoven Vestment", slot: "Chest", rarity: "Uncommon", icon: "♜", stats: ["+18 Armor", "+6 Spirit"], effect: "Renew ticks have a 10% chance to extend Aegis Shield by 4 absorption.", equipped: true },
    { id: "priest-phial", name: "Moonwater Phial", slot: "Consumable", rarity: "Common", icon: "⚗", stats: ["Restores 40 mana"], effect: "Single use. Cannot be used during this encounter.", equipped: false },
    { id: "priest-sigil", name: "Sigil of Quiet Resolve", slot: "Trinket", rarity: "Rare", icon: "◈", stats: ["+10% Purify range", "+5 Haste"], effect: "Purify grants its target 8 absorption when it removes Ember Brand.", equipped: false },
  ],
  druid: [
    { id: "druid-branch", name: "Verdant Branch", slot: "Main Hand", rarity: "Common", icon: "❧", stats: ["+5 Spirit"], effect: "A living focus shaped for layered restoration magic.", equipped: true },
    { id: "druid-hide", name: "Mossbound Hide", slot: "Chest", rarity: "Common", icon: "♧", stats: ["+10 Armor"], effect: "Flexible living armor that protects without slowing spellwork.", equipped: true },
    { id: "druid-seed", name: "Dreamseed", slot: "Trinket", rarity: "Uncommon", icon: "•", stats: ["+3 Haste"], effect: "A dormant seed that stirs near active growth magic.", equipped: false },
  ],
  shaman: [
    { id: "shaman-totem", name: "Raincall Totem", slot: "Main Hand", rarity: "Common", icon: "ϟ", stats: ["+5 Spirit"], effect: "A compact focus carrying water and earth sigils.", equipped: true },
    { id: "shaman-mail", name: "Tideworn Mail", slot: "Chest", rarity: "Common", icon: "▧", stats: ["+12 Armor"], effect: "Salt-tempered mail built for close formation healing.", equipped: true },
    { id: "shaman-stone", name: "Whispering Stone", slot: "Trinket", rarity: "Uncommon", icon: "◇", stats: ["+3 Haste"], effect: "An ancestral stone that hums beside active totems.", equipped: false },
  ],
  paladin: [
    { id: "paladin-mace", name: "Sunward Mace", slot: "Main Hand", rarity: "Common", icon: "⚒", stats: ["+5 Spirit"], effect: "A balanced war-mace that channels each impact into restorative light.", equipped: true },
    { id: "paladin-plate", name: "Dawnforged Plate", slot: "Chest", rarity: "Common", icon: "▣", stats: ["+14 Armor"], effect: "Warm plate built for fighting close to the party.", equipped: true },
    { id: "paladin-reliquary", name: "Reliquary of Oaths", slot: "Trinket", rarity: "Uncommon", icon: "♢", stats: ["+3 Haste"], effect: "A tiny reliquary that brightens as Conviction grows.", equipped: false },
  ],
  chronomancer: [
    { id: "chronomancer-focus", name: "Continuum Focus", slot: "Main Hand", rarity: "Common", icon: "◷", stats: ["+5 Spirit"], effect: "A clockwork focus calibrated to preserve living timelines.", equipped: true },
    { id: "chronomancer-mantle", name: "Secondhand Mantle", slot: "Chest", rarity: "Common", icon: "⌛", stats: ["+10 Armor"], effect: "Threaded with moments recovered from failed futures.", equipped: true },
    { id: "chronomancer-hourglass", name: "Unspent Hourglass", slot: "Trinket", rarity: "Uncommon", icon: "∞", stats: ["+3 Haste"], effect: "Its sand falls upward near a damaged timeline.", equipped: false },
  ],
};

export function createClassInventory(classId: HealerClassId): InventoryItem[] {
  return structuredClone(CLASS_INVENTORIES[classId]);
}

export function healerClass(classId: HealerClassId): HealerClassDefinition {
  return HEALER_CLASSES[classId];
}
