import { describe, expect, it } from "vitest";
import { AVAILABLE_BOSS_IDS, BOSS_DEFINITIONS, BOSS_GROUPS } from "./bossCatalog";
import { createBossMotionState, createBossState } from "./bossMechanics";
import { BOSS_MECHANIC_POOL, BOSS_MECHANIC_REGISTRY, bossMechanicName } from "./bosses/mechanicPool";
import { ALTERNATE_BOSS_CONFIG } from "./bossVisuals";

describe("boss catalog", () => {
  it("derives the available roster from every catalog definition", () => {
    expect(AVAILABLE_BOSS_IDS).toEqual(Object.keys(BOSS_DEFINITIONS));
    expect(new Set(AVAILABLE_BOSS_IDS)).toHaveLength(28);
  });

  it("assigns every boss to one compatible mechanic group", () => {
    const groupedBosses = BOSS_GROUPS.flatMap((group) => group.bossIds);
    expect(new Set(groupedBosses)).toHaveLength(AVAILABLE_BOSS_IDS.length);
    expect([...groupedBosses].sort()).toEqual([...AVAILABLE_BOSS_IDS].sort());
    expect(BOSS_GROUPS.find((group) => group.letter === "A")?.bossIds).toEqual([
      "bulldrome", "stormwool-alpaca", "thorncrown-stag", "bristlequake-boar",
    ]);
    for (const group of BOSS_GROUPS) {
      for (const bossId of group.bossIds) expect(group.archetypes).toContain(BOSS_DEFINITIONS[bossId].archetype);
    }
  });

  it("removes the retired licensed bosses from the playable roster", () => {
    expect(AVAILABLE_BOSS_IDS).not.toContain("vexa");
    expect(AVAILABLE_BOSS_IDS).not.toContain("ember-mantis-duelist");
    expect(AVAILABLE_BOSS_IDS).not.toContain("obsidian-ram-golem");
    expect(Object.values(BOSS_DEFINITIONS).map((boss) => boss.name)).not.toEqual(expect.arrayContaining([
      "Insect Queen",
      "Gate Guardian",
      "Gandora the Dragon of Destruction",
      "Blue-Eyes White Dragon",
      "Red-Eyes Black Dragon",
      "Pumpking the King of Ghosts",
      "Blue-Eyes Ultimate Dragon",
    ]));
  });

  it.each(AVAILABLE_BOSS_IDS)("creates typed state and modular motion for %s", (bossId) => {
    const state = createBossState(bossId);
    const motion = createBossMotionState(bossId);
    expect(state).toMatchObject({ id: bossId, name: BOSS_DEFINITIONS[bossId].name, maxHp: BOSS_DEFINITIONS[bossId].maxHp });
    expect(state.hp).toBe(state.maxHp);
    expect(motion.bossId).toBe(bossId);
  });

  it("resolves every boss loadout through the canonical mechanic registry", () => {
    const assigned = new Set(Object.values(BOSS_DEFINITIONS).flatMap((boss) => boss.mechanicIds));
    expect(assigned).toEqual(new Set(Object.keys(BOSS_MECHANIC_REGISTRY)));
    expect(Object.keys(BOSS_MECHANIC_REGISTRY)).toEqual(BOSS_MECHANIC_POOL.map((mechanic) => mechanic.id));
    for (const boss of Object.values(BOSS_DEFINITIONS)) {
      expect(boss.mechanicIds).toContain("basic-melee");
      for (const mechanicId of boss.mechanicIds) {
        expect(BOSS_MECHANIC_REGISTRY[mechanicId].name).toBe(bossMechanicName(mechanicId));
      }
    }
  });

  it("gives every boss a distinct mechanic kit", () => {
    const kits = Object.values(BOSS_DEFINITIONS).map((boss) => boss.mechanicIds.join(","));
    expect(new Set(kits)).toHaveLength(AVAILABLE_BOSS_IDS.length);
  });

  it("uses the boar model's full authored death performance", () => {
    expect(ALTERNATE_BOSS_CONFIG["bristlequake-boar"].death).toBe("Dying");
  });

  it("assigns Gravehorn to the underfilled burrow group with its optimized animation set", () => {
    expect(BOSS_GROUPS.find((group) => group.id === "burrow-eruption")?.bossIds).toContain("gravehorn-triceratops");
    expect(ALTERNATE_BOSS_CONFIG["gravehorn-triceratops"]).toMatchObject({
      idle: "Gravehorn|Idle",
      move: "Armature|Walk",
      attack: "Armature|Roar",
      special: "Armature|RiseUp",
      death: "Armature|Fall",
    });
    expect(ALTERNATE_BOSS_CONFIG["gravehorn-triceratops"].optimizedUrl).toContain("gravehorn-triceratops-uastc");
  });

  it("uses original animated creatures instead of the retired chicken and frog visuals", () => {
    expect(ALTERNATE_BOSS_CONFIG["cluckhorn-colossus"]).toMatchObject({
      idle: "Idle", move: "Scuttle", attack: "BeakRend", special: "FurnaceBurst", death: "Death",
    });
    expect(ALTERNATE_BOSS_CONFIG["cluckhorn-colossus"].url).toContain("brassbeak-basilisk");
    expect(ALTERNATE_BOSS_CONFIG["mirelord-frog"]).toMatchObject({
      idle: "Idle", move: "BurrowRush", attack: "RootPummel", special: "SporeEruption", death: "Death",
    });
    expect(ALTERNATE_BOSS_CONFIG["mirelord-frog"].url).toContain("bogbell-myconid");
  });
});
