import { expect } from "@esm-bundle/chai";
import { GameLoop } from "../../../src/core/GameLoop.js";
import {
  createGameLoopSetup,
  cleanupGameLoop,
  createRunData,
  createMockGameStateManagerForCombat,
  setupCombatUnits,
  cleanupTurnSystem,
} from "./helpers.js";

describe("Core: GameLoop - Combat Turn System", function () {
  this.timeout(30000);

  let gameLoop;
  let container;
  let mockGameStateManager;
  let playerUnit;
  let enemyUnit;

  beforeEach(async () => {
    const setup = createGameLoopSetup();
    gameLoop = setup.gameLoop;
    container = setup.container;

    gameLoop.stop();
    if (
      gameLoop.turnSystem &&
      typeof gameLoop.turnSystem.reset === "function"
    ) {
      gameLoop.turnSystem.reset();
    }

    gameLoop.init(container);
    mockGameStateManager = createMockGameStateManagerForCombat();
    gameLoop.gameStateManager = mockGameStateManager;

    const runData = createRunData({
      squad: [{ id: "u1", classId: "CLASS_VANGUARD" }],
    });
    await gameLoop.startLevel(runData, { startAnimation: false });

    const units = setupCombatUnits(gameLoop);
    playerUnit = units.playerUnit;
    enemyUnit = units.enemyUnit;
  });

  afterEach(() => {
    gameLoop.clearMovementHighlights();
    gameLoop.clearSpawnZoneHighlights();
    cleanupTurnSystem(gameLoop);
    cleanupGameLoop(gameLoop, container);
  });

  it("CoA 12: should end turn and advance turn queue", () => {
    const allUnits = [playerUnit, enemyUnit];
    gameLoop.turnSystem.startCombat(allUnits);

    const activeUnit = gameLoop.turnSystem.getActiveUnit();
    expect(activeUnit).to.exist;

    const initialCharge = activeUnit.chargeMeter;
    expect(initialCharge).to.be.greaterThanOrEqual(100);

    gameLoop.endTurn();

    expect(activeUnit.chargeMeter).to.be.a("number");
    expect(activeUnit.chargeMeter).to.be.at.least(0);
    const minExpectedAfterSubtraction = Math.max(0, initialCharge - 100);
    expect(activeUnit.chargeMeter).to.be.at.least(minExpectedAfterSubtraction);

    const nextUnit = gameLoop.turnSystem?.getActiveUnit();
    expect(nextUnit).to.exist;
    expect(nextUnit.chargeMeter).to.be.greaterThanOrEqual(100);
  });

  it("CoA 13: should restore AP for units when their turn starts (via TurnSystem)", () => {
    enemyUnit.currentAP = 0;
    playerUnit.baseStats.speed = 10;
    enemyUnit.baseStats.speed = 10;

    const allUnits = [playerUnit, enemyUnit];
    gameLoop.turnSystem.startCombat(allUnits);

    let attempts = 0;
    while (
      gameLoop.turnSystem.getActiveUnit() !== playerUnit &&
      attempts < 10
    ) {
      const current = gameLoop.turnSystem.getActiveUnit();
      if (current) {
        gameLoop.turnSystem.endTurn(current);
      } else {
        break;
      }
      attempts++;
    }

    expect(gameLoop.turnSystem.getActiveUnit()).to.equal(playerUnit);
    gameLoop.endTurn();

    attempts = 0;
    while (gameLoop.turnSystem.getActiveUnit() !== enemyUnit && attempts < 10) {
      const current = gameLoop.turnSystem.getActiveUnit();
      if (current && current !== enemyUnit) {
        gameLoop.endTurn();
      } else {
        break;
      }
      attempts++;
    }

    const activeUnit = gameLoop.turnSystem.getActiveUnit();
    expect(activeUnit).to.equal(enemyUnit);
    expect(enemyUnit.currentAP).to.equal(5);
  });

  it("CoA 16: should initialize all units with full AP when combat starts", () => {
    const fastUnit = gameLoop.unitManager.createUnit(
      "CLASS_VANGUARD",
      "PLAYER"
    );
    fastUnit.baseStats.speed = 20;
    fastUnit.position = { x: 3, y: 1, z: 3 };
    gameLoop.grid.placeUnit(fastUnit, fastUnit.position);

    const slowUnit = gameLoop.unitManager.createUnit(
      "CLASS_VANGUARD",
      "PLAYER"
    );
    slowUnit.baseStats.speed = 5;
    slowUnit.position = { x: 4, y: 1, z: 4 };
    gameLoop.grid.placeUnit(slowUnit, slowUnit.position);

    const enemyUnit2 = gameLoop.unitManager.createUnit(
      "ENEMY_DEFAULT",
      "ENEMY"
    );
    enemyUnit2.baseStats.speed = 8;
    enemyUnit2.position = { x: 10, y: 1, z: 10 };
    gameLoop.grid.placeUnit(enemyUnit2, enemyUnit2.position);

    gameLoop.initializeCombatUnits();

    expect(fastUnit.currentAP).to.equal(10);
    expect(slowUnit.currentAP).to.equal(10);
    expect(enemyUnit2.currentAP).to.equal(10);
    expect(fastUnit.chargeMeter).to.be.greaterThan(slowUnit.chargeMeter);
  });
});
