import { expect } from "@esm-bundle/chai";
import sinon from "sinon";
import {
  gameStateManager,
  GameStateManager,
} from "../../../src/core/GameStateManager.js";

describe("Core: GameStateManager - Inventory Integration", () => {
  let mockPersistence;
  let mockGameLoop;
  let mockInventoryManager;
  let mockRunStash;

  beforeEach(() => {
    // Reset Singleton State
    gameStateManager.reset();

    // Mock InventoryManager
    mockRunStash = {
      id: "RUN_LOOT",
      getAllItems: sinon.stub().returns([
        {
          uid: "ITEM_001",
          defId: "ITEM_RUSTY_BLADE",
          isNew: false,
          quantity: 1,
        },
        {
          uid: "ITEM_002",
          defId: "ITEM_SCRAP_PLATE",
          isNew: true,
          quantity: 1,
        },
      ]),
      currency: {
        aetherShards: 150,
        ancientCores: 2,
      },
    };

    mockInventoryManager = {
      runStash: mockRunStash,
      hubStash: {
        id: "HUB_VAULT",
        getAllItems: sinon.stub().returns([]),
        currency: {
          aetherShards: 0,
          ancientCores: 0,
        },
      },
    };

    // Mock Persistence
    mockPersistence = {
      init: sinon.stub().resolves(),
      saveRun: sinon.stub().resolves(),
      loadRun: sinon.stub().resolves(null),
      loadRoster: sinon.stub().resolves(null),
      saveRoster: sinon.stub().resolves(),
      loadHubStash: sinon.stub().resolves(null),
      saveHubStash: sinon.stub().resolves(),
      loadUnlocks: sinon.stub().resolves([]),
      saveUnlocks: sinon.stub().resolves(),
    };
    gameStateManager.persistence = mockPersistence;

    // Mock GameLoop with inventoryManager
    mockGameLoop = {
      init: sinon.spy(),
      startLevel: sinon.stub().resolves(),
      stop: sinon.spy(),
      inventoryManager: mockInventoryManager,
    };
    gameStateManager.gameLoop = mockGameLoop;

    // Mock MissionManager
    gameStateManager.missionManager = {
      setupActiveMission: sinon.stub(),
      getActiveMission: sinon.stub().returns({
        id: "MISSION_TUTORIAL_01",
        config: { title: "Test Mission" },
        biome: {
          generator_config: {
            seed_type: "RANDOM",
            seed: 12345,
          },
        },
        objectives: [],
      }),
      playIntro: sinon.stub().resolves(),
    };

    // Set gameLoop so gameLoopInitialized promise can resolve
    gameStateManager.gameLoop = mockGameLoop;
    // Call the internal method that resolves the promise (simulating init completion)
    // We need to trigger the resolution - check if there's a method or we need to call init
  });

  it("CoA 1: _initializeRun should include inventory data in runData", async () => {
    // Initialize gameStateManager first
    await gameStateManager.init();
    // Use setGameLoop to properly resolve the promise
    gameStateManager.setGameLoop(mockGameLoop);

    const squadManifest = [
      {
        id: "UNIT_001",
        classId: "CLASS_VANGUARD",
        name: "Test Vanguard",
      },
    ];

    await gameStateManager._initializeRun(squadManifest);

    // Verify saveRun was called
    expect(mockPersistence.saveRun.calledOnce).to.be.true;

    // Get the saved run data
    const savedData = mockPersistence.saveRun.firstCall.args[0];

    // Verify inventory data is included
    expect(savedData.inventory).to.exist;
    expect(savedData.inventory.runStash).to.exist;
    expect(savedData.inventory.runStash.id).to.equal("RUN_LOOT");
    expect(savedData.inventory.runStash.items).to.be.an("array");
    expect(savedData.inventory.runStash.items.length).to.equal(2);
    expect(savedData.inventory.runStash.currency).to.exist;
    expect(savedData.inventory.runStash.currency.aetherShards).to.equal(150);
    expect(savedData.inventory.runStash.currency.ancientCores).to.equal(2);
  });

  it("CoA 2: _initializeRun should handle missing inventoryManager gracefully", async () => {
    await gameStateManager.init();
    // Remove inventoryManager
    mockGameLoop.inventoryManager = null;
    gameStateManager.setGameLoop(mockGameLoop);

    const squadManifest = [
      {
        id: "UNIT_001",
        classId: "CLASS_VANGUARD",
        name: "Test Vanguard",
      },
    ];

    await gameStateManager._initializeRun(squadManifest);

    // Should still save without error
    expect(mockPersistence.saveRun.calledOnce).to.be.true;

    const savedData = mockPersistence.saveRun.firstCall.args[0];
    // Inventory should be undefined if manager doesn't exist
    expect(savedData.inventory).to.be.undefined;
  });

  it("CoA 3: saved inventory should include item instances with uid", async () => {
    await gameStateManager.init();
    gameStateManager.setGameLoop(mockGameLoop);

    const squadManifest = [
      {
        id: "UNIT_001",
        classId: "CLASS_VANGUARD",
        name: "Test Vanguard",
      },
    ];

    await gameStateManager._initializeRun(squadManifest);

    const savedData = mockPersistence.saveRun.firstCall.args[0];

    // Verify items have uid (not just defId)
    expect(savedData.inventory.runStash.items[0].uid).to.equal("ITEM_001");
    expect(savedData.inventory.runStash.items[0].defId).to.equal("ITEM_RUSTY_BLADE");
    expect(savedData.inventory.runStash.items[0].quantity).to.equal(1);
  });

  it("CoA 4: saved inventory should preserve currency values", async () => {
    await gameStateManager.init();
    gameStateManager.setGameLoop(mockGameLoop);

    const squadManifest = [
      {
        id: "UNIT_001",
        classId: "CLASS_VANGUARD",
        name: "Test Vanguard",
      },
    ];

    await gameStateManager._initializeRun(squadManifest);

    const savedData = mockPersistence.saveRun.firstCall.args[0];

    // Verify currency is saved correctly
    expect(savedData.inventory.runStash.currency.aetherShards).to.equal(150);
    expect(savedData.inventory.runStash.currency.ancientCores).to.equal(2);
  });
});

