import { expect } from "@esm-bundle/chai";
import { UnitManager } from "../../src/managers/UnitManager.js";

// Note: These tests rely on the existence of src/units/Explorer.js and src/units/Enemy.js
// If running in isolation without those files, mocks would be required.

describe("Manager: UnitManager", () => {
  let manager;
  let mockRegistry;

  beforeEach(() => {
    // Setup a mock registry to simulate loading definitions from JSON
    mockRegistry = {
      get: (id) => {
        if (id === "CLASS_VANGUARD") {
          return {
            name: "Vanguard",
            type: "EXPLORER",
            stats: { health: 100, speed: 10 },
          };
        }
        if (id === "ENEMY_GOBLIN") {
          return {
            name: "Goblin",
            type: "ENEMY",
            stats: { health: 30, attack: 5 },
            ai_archetype: "BRUISER",
          };
        }
        if (id === "STRUCT_WALL") {
          return {
            name: "Wall",
            type: "STRUCTURE",
            model: "wall.glb",
            stats: { health: 50 },
          };
        }
        return null;
      },
    };

    manager = new UnitManager(mockRegistry);
  });

  it("CoA 1: createUnit should instantiate an Explorer for CLASS_ IDs", () => {
    const unit = manager.createUnit("CLASS_VANGUARD", "PLAYER");

    expect(unit).to.exist;
    // Verify it behaves like an Explorer (has class logic)
    expect(unit.type).to.equal("EXPLORER");
    expect(unit.team).to.equal("PLAYER");
    expect(unit.name).to.equal("Vanguard");

    // Verify it was added to the active list
    expect(manager.getUnitById(unit.id)).to.equal(unit);
  });

  it("CoA 2: createUnit should instantiate an Enemy for ENEMY_ IDs", () => {
    const unit = manager.createUnit("ENEMY_GOBLIN", "ENEMY");

    expect(unit).to.exist;
    expect(unit.type).to.equal("ENEMY");
    expect(unit.team).to.equal("ENEMY");
    // Enemies should have AI props
    expect(unit.archetypeId).to.equal("BRUISER");
  });

  it("CoA 3: createUnit should handle generic structures", () => {
    const unit = manager.createUnit("STRUCT_WALL", "NEUTRAL");

    expect(unit).to.exist;
    expect(unit.type).to.equal("STRUCTURE");
    expect(unit.team).to.equal("NEUTRAL");
  });

  it("CoA 4: removeUnit should remove the unit from the active map", () => {
    const unit = manager.createUnit("CLASS_VANGUARD", "PLAYER");
    const id = unit.id;

    expect(manager.getUnitById(id)).to.exist;

    const removed = manager.removeUnit(id);

    expect(removed).to.be.true;
    expect(manager.getUnitById(id)).to.be.undefined;
    expect(manager.getAllUnits()).to.have.lengthOf(0);
  });

  it("CoA 5: getUnitsInRange should return units within Manhattan distance", () => {
    const u1 = manager.createUnit("CLASS_VANGUARD", "PLAYER");
    // Manually set position since we aren't using the Grid's moveUnit here
    u1.position = { x: 0, y: 0, z: 0 };

    const u2 = manager.createUnit("ENEMY_GOBLIN", "ENEMY");
    u2.position = { x: 2, y: 0, z: 0 }; // Distance 2

    const u3 = manager.createUnit("ENEMY_GOBLIN", "ENEMY");
    u3.position = { x: 5, y: 0, z: 0 }; // Distance 5

    // Check range 3
    const results = manager.getUnitsInRange({ x: 0, y: 0, z: 0 }, 3);

    expect(results).to.include(u1); // Distance 0 (Self)
    expect(results).to.include(u2); // Distance 2
    expect(results).to.not.include(u3); // Distance 5
  });

  it("CoA 6: getUnitsInRange should filter by team if provided", () => {
    const u1 = manager.createUnit("CLASS_VANGUARD", "PLAYER");
    u1.position = { x: 0, y: 0, z: 0 };

    const u2 = manager.createUnit("ENEMY_GOBLIN", "ENEMY");
    u2.position = { x: 1, y: 0, z: 0 };

    // Filter for ENEMY only
    const results = manager.getUnitsInRange({ x: 0, y: 0, z: 0 }, 5, "ENEMY");

    expect(results).to.include(u2);
    expect(results).to.not.include(u1);
  });

  it("CoA 7: tickAll should trigger cooldown updates on units", () => {
    const unit = manager.createUnit("CLASS_VANGUARD", "PLAYER");

    // Mock the skill manager on the unit instance
    let ticked = false;
    unit.skillManager = {
      tickCooldowns: () => {
        ticked = true;
      },
    };

    manager.tickAll();

    expect(ticked).to.be.true;
  });
});
