import { RUN_BUFFS, RUN_BUFF_ORDER } from "../roguelike";
import type { BossId, RunBuffId } from "../types";
import {
  GEAR_RECIPES,
  GEAR_SLOT_ORDER,
  spendGearCosts,
  type ClassGearProgress,
  type GearOwnerId,
  type GearProgress,
  type GearSlotId,
  type GearUpgradeCost,
} from "./gear";
import { bossGroupDrop, groupDrop, type MaterialStack } from "./loot";

export const ACTIVE_INFUSION_MIN_GEAR_LEVEL = 5;
export const PASSIVE_INFUSION_MIN_GEAR_LEVEL = 10;

export type InfusionEffectKey =
  | "healing-power"
  | "hazard-shield"
  | "max-health"
  | "stun-immune"
  | "cooldown"
  | "move-speed"
  | "damage";

export interface ActiveInfusionDefinition {
  id: string;
  ownerId: GearOwnerId;
  name: string;
  icon: string;
  description: string;
  linkedBossId: BossId;
  effectKey: InfusionEffectKey;
}

type InfusionSeed = Omit<ActiveInfusionDefinition, "ownerId">;

const INFUSION_SEEDS: Record<GearOwnerId, readonly InfusionSeed[]> = {
  priest: [
    { id: "priest-sanctuary", name: "Sanctuary", icon: "✦", description: "15% less hazard damage.", linkedBossId: "broodfang-spider", effectKey: "hazard-shield" },
    { id: "priest-guardian-grace", name: "Guardian Grace", icon: "✚", description: "8% more healing power.", linkedBossId: "tempestscale-dragon", effectKey: "healing-power" },
    { id: "priest-miracle-ward", name: "Miracle Ward", icon: "◇", description: "8% more maximum health.", linkedBossId: "bristlequake-boar", effectKey: "max-health" },
  ],
  druid: [
    { id: "druid-barkskin", name: "Barkskin", icon: "♧", description: "8% more maximum health.", linkedBossId: "bristlequake-boar", effectKey: "max-health" },
    { id: "druid-verdant-pulse", name: "Verdant Pulse", icon: "❈", description: "8% more healing power.", linkedBossId: "warcaller-orc", effectKey: "healing-power" },
    { id: "druid-wildstep", name: "Wildstep", icon: "⌁", description: "8% faster movement.", linkedBossId: "sandglass-scorpion", effectKey: "move-speed" },
  ],
  shaman: [
    { id: "shaman-spirit-ward", name: "Spirit Ward", icon: "◈", description: "15% less hazard damage.", linkedBossId: "broodfang-spider", effectKey: "hazard-shield" },
    { id: "shaman-ancestral-surge", name: "Ancestral Surge", icon: "ϟ", description: "8% more healing power.", linkedBossId: "emberfox", effectKey: "healing-power" },
    { id: "shaman-windwalk", name: "Windwalk", icon: "≋", description: "8% faster movement.", linkedBossId: "sandglass-scorpion", effectKey: "move-speed" },
  ],
  brann: [
    { id: "brann-unbreakable", name: "Unbreakable", icon: "▣", description: "Immune to stuns.", linkedBossId: "bristlequake-boar", effectKey: "stun-immune" },
    { id: "brann-bulwark", name: "Bulwark", icon: "⬡", description: "8% more maximum health.", linkedBossId: "bulldrome", effectKey: "max-health" },
    { id: "brann-vanguard", name: "Vanguard", icon: "➶", description: "8% faster movement.", linkedBossId: "emberfox", effectKey: "move-speed" },
  ],
  nia: [
    { id: "nia-hunters-mark", name: "Hunter's Mark", icon: "◎", description: "8% more damage.", linkedBossId: "emberfox", effectKey: "damage" },
    { id: "nia-quickdraw", name: "Quickdraw", icon: "➳", description: "8% faster attacks.", linkedBossId: "warcaller-orc", effectKey: "cooldown" },
    { id: "nia-decoy", name: "Decoy", icon: "♙", description: "8% more maximum health.", linkedBossId: "broodfang-spider", effectKey: "max-health" },
  ],
  orin: [
    { id: "orin-overcharge", name: "Overcharge", icon: "ϟ", description: "8% more damage.", linkedBossId: "tempestscale-dragon", effectKey: "damage" },
    { id: "orin-temporal-flow", name: "Temporal Flow", icon: "◷", description: "8% faster attacks.", linkedBossId: "sandglass-scorpion", effectKey: "cooldown" },
    { id: "orin-arcane-barrier", name: "Arcane Barrier", icon: "◇", description: "8% more maximum health.", linkedBossId: "broodfang-spider", effectKey: "max-health" },
  ],
  vale: [
    { id: "vale-expose", name: "Expose", icon: "†", description: "8% more damage.", linkedBossId: "warcaller-orc", effectKey: "damage" },
    { id: "vale-shadow-step", name: "Shadow Step", icon: "⌁", description: "8% faster movement.", linkedBossId: "emberfox", effectKey: "move-speed" },
    { id: "vale-vanish", name: "Vanish", icon: "◌", description: "15% less hazard damage.", linkedBossId: "broodfang-spider", effectKey: "hazard-shield" },
  ],
};

export const ACTIVE_INFUSIONS = Object.fromEntries(Object.entries(INFUSION_SEEDS).flatMap(([ownerId, choices]) =>
  choices.map((choice) => [choice.id, { ...choice, ownerId: ownerId as GearOwnerId }]),
)) as Record<string, ActiveInfusionDefinition>;

const ACTIVE_INFUSIONS_BY_OWNER = Object.fromEntries(Object.entries(INFUSION_SEEDS).map(([ownerId, choices]) => [
  ownerId,
  choices.map((choice) => ACTIVE_INFUSIONS[choice.id]),
])) as unknown as Record<GearOwnerId, readonly ActiveInfusionDefinition[]>;

export const PASSIVE_INFUSIONS = RUN_BUFF_ORDER.map((id) => RUN_BUFFS[id]);

export function infusionsForOwner(ownerId: GearOwnerId): readonly ActiveInfusionDefinition[] {
  return ACTIVE_INFUSIONS_BY_OWNER[ownerId];
}

export function activeInfusionUnlocked(progress: ClassGearProgress): boolean {
  return GEAR_SLOT_ORDER.some((slotId) => progress.slots[slotId].level >= ACTIVE_INFUSION_MIN_GEAR_LEVEL);
}

export function passiveInfusionUnlocked(progress: GearProgress): boolean {
  return Object.values(progress).some((owner) => GEAR_SLOT_ORDER.some((slotId) => owner.slots[slotId].level >= PASSIVE_INFUSION_MIN_GEAR_LEVEL));
}

export function infusionCosts(ownerId: GearOwnerId, slotId: GearSlotId, infusionId: string): GearUpgradeCost[] {
  const definition = ACTIVE_INFUSIONS[infusionId];
  if (!definition || definition.ownerId !== ownerId) return [];
  const ascendant = bossGroupDrop(definition.linkedBossId, "ascendant");
  const mythic = groupDrop(GEAR_RECIPES[ownerId][slotId].primaryGroupId, "mythic");
  return [
    { itemId: ascendant.id, itemName: ascendant.name, quantity: 5 },
    { itemId: mythic.id, itemName: mythic.name, quantity: 5 },
  ];
}

export function equipActiveInfusion(
  progress: GearProgress,
  inventory: readonly MaterialStack[],
  ownerId: GearOwnerId,
  slotId: GearSlotId,
  infusionId: string,
): { gearProgress: GearProgress; inventory: MaterialStack[] } {
  const definition = ACTIVE_INFUSIONS[infusionId];
  if (!definition || definition.ownerId !== ownerId) throw new Error("Infusion does not belong to selected hero.");
  if (!activeInfusionUnlocked(progress[ownerId])) throw new Error(`Raise any ${ownerId} gear slot to +${ACTIVE_INFUSION_MIN_GEAR_LEVEL}.`);
  if (progress[ownerId].slots[slotId].level < ACTIVE_INFUSION_MIN_GEAR_LEVEL) throw new Error(`Selected anchor must be +${ACTIVE_INFUSION_MIN_GEAR_LEVEL}.`);
  if (progress[ownerId].infusionAbilityId === infusionId) return { gearProgress: progress, inventory: [...inventory] };
  return {
    inventory: spendGearCosts(inventory, infusionCosts(ownerId, slotId, infusionId)),
    gearProgress: {
      ...progress,
      [ownerId]: { ...progress[ownerId], infusionAbilityId: infusionId },
    },
  };
}

export function equipPassiveInfusion(progress: GearProgress, ownerId: GearOwnerId, passiveId: RunBuffId): GearProgress {
  if (ownerId !== "priest" && ownerId !== "druid" && ownerId !== "shaman") throw new Error("Passive infusions belong to healer gear.");
  if (!RUN_BUFF_ORDER.includes(passiveId)) throw new Error("Unknown passive infusion.");
  if (!passiveInfusionUnlocked(progress)) throw new Error(`Raise any gear slot to +${PASSIVE_INFUSION_MIN_GEAR_LEVEL}.`);
  return { ...progress, [ownerId]: { ...progress[ownerId], passiveInfusionId: passiveId } };
}

export function normalizeActiveInfusionId(ownerId: GearOwnerId, value: unknown): string | null {
  return typeof value === "string" && ACTIVE_INFUSIONS[value]?.ownerId === ownerId ? value : null;
}

export function normalizePassiveInfusionId(ownerId: GearOwnerId, value: unknown): RunBuffId | null {
  if (ownerId !== "priest" && ownerId !== "druid" && ownerId !== "shaman") return null;
  return typeof value === "string" && RUN_BUFF_ORDER.includes(value as RunBuffId) ? value as RunBuffId : null;
}
