import { describe, expect, it } from "vitest";
import { AETHER_MAX_ENEMY_SHOTS, AETHER_MAX_PLAYER_SHOTS, AETHER_MAX_SHIPS } from "./aetherAssault";
import { useGameStore } from "./store";

describe("runtime performance budgets", () => {
  it.each([
    { label: "dual-boss", bossIds: ["emberfox", "sandglass-scorpion"] as const, runMode: "encounter" as const, maxElapsedMs: 3_500 },
    { label: "Rogue Trials trio", bossIds: ["emberfox", "sandglass-scorpion", "tempestscale-dragon"] as const, runMode: "encounter" as const, maxElapsedMs: 5_000 },
    { label: "Hockey Healing", bossIds: ["emberfox", "sandglass-scorpion"] as const, runMode: "hockey-healing" as const, maxElapsedMs: 4_000 },
    { label: "Blockbreaker", bossIds: ["emberfox", "sandglass-scorpion"] as const, runMode: "blockbreaker" as const, maxElapsedMs: 5_000 },
    { label: "Aether Assault", bossIds: ["emberfox", "sandglass-scorpion"] as const, runMode: "aether-assault" as const, maxElapsedMs: 6_000 },
  ])("keeps ten minutes of $label simulation bounded", ({ bossIds, runMode, maxElapsedMs }) => {
    const store = useGameStore.getState();
    store.configureHealer("priest", "Perf", [], bossIds, runMode);
    store.startEncounter();
    useGameStore.setState((state) => ({
      boss: { ...state.boss, hp: 1_000_000_000, maxHp: 1_000_000_000 },
      additionalBosses: state.additionalBosses.map((entry) => ({
        ...entry,
        boss: { ...entry.boss, hp: 1_000_000_000, maxHp: 1_000_000_000 },
      })),
      party: state.party.map((member) => ({ ...member, absorb: 1_000_000_000 })),
    }));

    let maxHazards = 0;
    let maxDamageEvents = 0;
    let maxCombatLog = 0;
    let maxAetherShips = 0;
    let maxAetherPlayerShots = 0;
    let maxAetherEnemyShots = 0;
    const startedAt = performance.now();
    for (let step = 0; step < 6_000; step += 1) {
      if (runMode === "hockey-healing") {
        const hockey = useGameStore.getState().hockey;
        useGameStore.setState((state) => ({
          partyPositions: { ...state.partyPositions, aelia: [hockey.puckPosition[0], 8.5] },
        }));
      }
      if (runMode === "blockbreaker") {
        useGameStore.setState((state) => ({
          blockbreaker: { ...state.blockbreaker, bricks: [] },
        }));
      }
      useGameStore.getState().tick(0.1);
      const state = useGameStore.getState();
      const hazards = state.bossMotion.hazards.length
        + state.additionalBosses.reduce((sum, entry) => sum + entry.motion.hazards.length, 0);
      maxHazards = Math.max(maxHazards, hazards);
      maxDamageEvents = Math.max(maxDamageEvents, state.partyDamageEvents.length);
      maxCombatLog = Math.max(maxCombatLog, state.combatLog.length);
      maxAetherShips = Math.max(maxAetherShips, state.aetherAssault.ships.length);
      maxAetherPlayerShots = Math.max(maxAetherPlayerShots, state.aetherAssault.playerShots.length);
      maxAetherEnemyShots = Math.max(maxAetherEnemyShots, state.aetherAssault.enemyShots.length);
    }
    const elapsedMs = performance.now() - startedAt;
    const result = useGameStore.getState();

    expect(result.phase).toBe("combat");
    expect(result.time).toBeCloseTo(600, 5);
    expect(maxHazards).toBeLessThanOrEqual(64);
    expect(maxDamageEvents).toBeLessThanOrEqual(24);
    expect(maxCombatLog).toBeLessThanOrEqual(12);
    expect(maxAetherShips).toBeLessThanOrEqual(AETHER_MAX_SHIPS);
    expect(maxAetherPlayerShots).toBeLessThanOrEqual(AETHER_MAX_PLAYER_SHOTS);
    expect(maxAetherEnemyShots).toBeLessThanOrEqual(AETHER_MAX_ENEMY_SHOTS);
    expect(elapsedMs).toBeLessThan(maxElapsedMs);
  });

  it("keeps ten minutes of Healing Hockey PVP simulation bounded", () => {
    const store = useGameStore.getState();
    store.configureHealer(
      "priest",
      "Perf",
      [],
      ["emberfox"],
      "hockey-healing-pvp",
      undefined,
      "initiate",
      { matchId: null, seed: 17, opponentName: "CPU Perf", role: "cpu" },
    );
    store.startEncounter();
    useGameStore.setState((state) => ({
      boss: { ...state.boss, hp: 1_000_000_000, maxHp: 1_000_000_000 },
      party: state.party.map((member) => ({ ...member, absorb: 1_000_000_000 })),
      hockeyPvpOpponent: {
        ...state.hockeyPvpOpponent,
        boss: { ...state.hockeyPvpOpponent.boss, hp: 1_000_000_000, maxHp: 1_000_000_000 },
        party: state.hockeyPvpOpponent.party.map((member) => ({ ...member, absorb: 1_000_000_000 })),
      },
    }));

    let maxHazards = 0;
    let maxCombatLog = 0;
    const startedAt = performance.now();
    for (let step = 0; step < 6_000; step += 1) {
      useGameStore.getState().tick(0.1);
      const state = useGameStore.getState();
      maxHazards = Math.max(
        maxHazards,
        state.bossMotion.hazards.length + state.hockeyPvpOpponent.bossMotion.hazards.length,
      );
      maxCombatLog = Math.max(maxCombatLog, state.combatLog.length);
    }
    const elapsedMs = performance.now() - startedAt;
    const result = useGameStore.getState();

    expect(result.phase).toBe("combat");
    expect(result.time).toBeCloseTo(600, 5);
    expect(maxHazards).toBeLessThanOrEqual(64);
    expect(maxCombatLog).toBeLessThanOrEqual(12);
    expect(elapsedMs).toBeLessThan(8_000);
  });
});
