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

describe("UI: HubScreen", () => {
  let element;
  let container;
  let mockPersistence;
  let mockRosterManager;
  let mockMissionManager;

  beforeEach(() => {
    container = document.createElement("div");
    document.body.appendChild(container);
    element = document.createElement("hub-screen");
    container.appendChild(element);

    // Mock gameStateManager dependencies
    mockPersistence = {
      loadRun: sinon.stub().resolves(null),
    };

    mockRosterManager = {
      roster: [],
      getDeployableUnits: sinon.stub().returns([]),
    };

    mockMissionManager = {
      completedMissions: new Set(),
    };

    // Replace gameStateManager properties with mocks
    gameStateManager.persistence = mockPersistence;
    gameStateManager.rosterManager = mockRosterManager;
    gameStateManager.missionManager = mockMissionManager;
  });

  afterEach(() => {
    if (container && container.parentNode) {
      container.parentNode.removeChild(container);
    }
    // Clean up event listeners (element handles its own cleanup in disconnectedCallback)
  });

  // Helper to wait for LitElement update
  async function waitForUpdate() {
    await element.updateComplete;
    await new Promise((resolve) => setTimeout(resolve, 10));
  }

  // Helper to query shadow DOM
  function queryShadow(selector) {
    return element.shadowRoot?.querySelector(selector);
  }

  function queryShadowAll(selector) {
    return element.shadowRoot?.querySelectorAll(selector) || [];
  }

  describe("CoA 1: Live Data Binding", () => {
    it("should fetch wallet and roster data on mount", async () => {
      const runData = {
        inventory: {
          runStash: {
            currency: {
              aetherShards: 450,
              ancientCores: 12,
            },
          },
        },
      };
      mockPersistence.loadRun.resolves(runData);
      mockRosterManager.roster = [
        { id: "u1", status: "READY" },
        { id: "u2", status: "READY" },
        { id: "u3", status: "INJURED" },
      ];
      mockRosterManager.getDeployableUnits.returns([
        { id: "u1", status: "READY" },
        { id: "u2", status: "READY" },
      ]);

      await waitForUpdate();

      expect(mockPersistence.loadRun.called).to.be.true;
      expect(element.wallet.aetherShards).to.equal(450);
      expect(element.wallet.ancientCores).to.equal(12);
      expect(element.rosterSummary.total).to.equal(3);
      expect(element.rosterSummary.ready).to.equal(2);
      expect(element.rosterSummary.injured).to.equal(1);
    });

    it("should display correct currency values in top bar", async () => {
      const runData = {
        inventory: {
          runStash: {
            currency: {
              aetherShards: 450,
              ancientCores: 12,
            },
          },
        },
      };
      mockPersistence.loadRun.resolves(runData);
      await waitForUpdate();

      const resourceStrip = queryShadow(".resource-strip");
      expect(resourceStrip).to.exist;
      expect(resourceStrip.textContent).to.include("450");
      expect(resourceStrip.textContent).to.include("12");
    });

    it("should handle missing wallet data gracefully", async () => {
      mockPersistence.loadRun.resolves(null);
      await waitForUpdate();

      expect(element.wallet.aetherShards).to.equal(0);
      expect(element.wallet.ancientCores).to.equal(0);
    });
  });

  describe("CoA 2: Hotspot & Dock Sync", () => {
    it("should open MISSIONS overlay when clicking missions hotspot", async () => {
      await waitForUpdate();

      const missionsHotspot = queryShadow(".hotspot.missions");
      expect(missionsHotspot).to.exist;

      missionsHotspot.click();
      await waitForUpdate();

      expect(element.activeOverlay).to.equal("MISSIONS");
    });

    it("should open MISSIONS overlay when clicking missions dock button", async () => {
      await waitForUpdate();

      const missionsButton = queryShadowAll(".dock-button")[1]; // Second button is MISSIONS
      expect(missionsButton).to.exist;

      missionsButton.click();
      await waitForUpdate();

      expect(element.activeOverlay).to.equal("MISSIONS");
    });

    it("should open BARRACKS overlay from both hotspot and button", async () => {
      await waitForUpdate();

      // Test hotspot
      const barracksHotspot = queryShadow(".hotspot.barracks");
      barracksHotspot.click();
      await waitForUpdate();
      expect(element.activeOverlay).to.equal("BARRACKS");

      // Close and test button
      element.activeOverlay = "NONE";
      await waitForUpdate();

      const barracksButton = queryShadowAll(".dock-button")[0]; // First button is BARRACKS
      barracksButton.click();
      await waitForUpdate();
      expect(element.activeOverlay).to.equal("BARRACKS");
    });
  });

  describe("CoA 3: Overlay Management", () => {
    it("should render mission-board component when activeOverlay is MISSIONS", async () => {
      element.activeOverlay = "MISSIONS";
      await waitForUpdate();

      // Import MissionBoard dynamically
      await import("../../src/ui/components/MissionBoard.js");
      await waitForUpdate();

      const overlayContainer = queryShadow(".overlay-container.active");
      expect(overlayContainer).to.exist;

      const missionBoard = queryShadow("mission-board");
      expect(missionBoard).to.exist;
    });

    it("should close overlay when close event is dispatched", async () => {
      element.activeOverlay = "MISSIONS";
      await waitForUpdate();

      // Simulate close event
      const closeEvent = new CustomEvent("close", { bubbles: true, composed: true });
      element.dispatchEvent(closeEvent);
      await waitForUpdate();

      expect(element.activeOverlay).to.equal("NONE");
    });

    it("should close overlay when backdrop is clicked", async () => {
      element.activeOverlay = "BARRACKS";
      await waitForUpdate();

      const backdrop = queryShadow(".overlay-backdrop");
      expect(backdrop).to.exist;

      backdrop.click();
      await waitForUpdate();

      expect(element.activeOverlay).to.equal("NONE");
    });

    it("should show different overlays for different types", async () => {
      const overlayTypes = ["BARRACKS", "MISSIONS", "MARKET", "RESEARCH", "SYSTEM"];

      for (const type of overlayTypes) {
        element.activeOverlay = type;
        await waitForUpdate();

        const overlayContainer = queryShadow(".overlay-container.active");
        expect(overlayContainer).to.exist;
        expect(element.activeOverlay).to.equal(type);
      }
    });
  });

  describe("CoA 4: Mission Handoff", () => {
    it("should dispatch request-team-builder event when mission is selected", async () => {
      let eventDispatched = false;
      let eventData = null;

      window.addEventListener("request-team-builder", (e) => {
        eventDispatched = true;
        eventData = e.detail;
      });

      element.activeOverlay = "MISSIONS";
      await waitForUpdate();

      // Import MissionBoard
      await import("../../src/ui/components/MissionBoard.js");
      await waitForUpdate();

      const missionBoard = queryShadow("mission-board");
      expect(missionBoard).to.exist;

      // Simulate mission selection
      const missionEvent = new CustomEvent("mission-selected", {
        detail: { missionId: "MISSION_TUTORIAL_01" },
        bubbles: true,
        composed: true,
      });
      missionBoard.dispatchEvent(missionEvent);
      await waitForUpdate();

      expect(eventDispatched).to.be.true;
      expect(eventData.missionId).to.equal("MISSION_TUTORIAL_01");
      expect(element.activeOverlay).to.equal("NONE");
    });
  });

  describe("Unlock System", () => {
    it("should unlock market after first mission", async () => {
      mockMissionManager.completedMissions = new Set(["MISSION_TUTORIAL_01"]);
      await waitForUpdate();

      expect(element.unlocks.market).to.be.true;
      expect(element.unlocks.research).to.be.false;
    });

    it("should unlock research after 3 missions", async () => {
      mockMissionManager.completedMissions = new Set([
        "MISSION_1",
        "MISSION_2",
        "MISSION_3",
      ]);
      await waitForUpdate();

      expect(element.unlocks.research).to.be.true;
    });

    it("should disable locked facilities in dock", async () => {
      mockMissionManager.completedMissions = new Set(); // No missions completed
      await waitForUpdate();

      const marketButton = queryShadowAll(".dock-button")[2]; // MARKET is third button
      expect(marketButton.hasAttribute("disabled")).to.be.true;

      const researchButton = queryShadowAll(".dock-button")[3]; // RESEARCH is fourth button
      expect(researchButton.hasAttribute("disabled")).to.be.true;
    });

    it("should hide market hotspot when locked", async () => {
      mockMissionManager.completedMissions = new Set(); // No missions completed
      await waitForUpdate();

      const marketHotspot = queryShadow(".hotspot.market");
      expect(marketHotspot.hasAttribute("hidden")).to.be.true;
    });
  });

  describe("Roster Summary Display", () => {
    it("should calculate roster summary correctly", async () => {
      mockRosterManager.roster = [
        { id: "u1", status: "READY" },
        { id: "u2", status: "READY" },
        { id: "u3", status: "INJURED" },
        { id: "u4", status: "READY" },
      ];
      mockRosterManager.getDeployableUnits.returns([
        { id: "u1", status: "READY" },
        { id: "u2", status: "READY" },
        { id: "u4", status: "READY" },
      ]);

      await waitForUpdate();

      expect(element.rosterSummary.total).to.equal(4);
      expect(element.rosterSummary.ready).to.equal(3);
      expect(element.rosterSummary.injured).to.equal(1);
    });
  });

  describe("State Change Handling", () => {
    it("should reload data when gamestate-changed event fires", async () => {
      const initialShards = 100;
      const runData1 = {
        inventory: {
          runStash: {
            currency: { aetherShards: initialShards, ancientCores: 0 },
          },
        },
      };
      mockPersistence.loadRun.resolves(runData1);
      await waitForUpdate();

      expect(element.wallet.aetherShards).to.equal(initialShards);

      // Change the data
      const newShards = 200;
      const runData2 = {
        inventory: {
          runStash: {
            currency: { aetherShards: newShards, ancientCores: 0 },
          },
        },
      };
      mockPersistence.loadRun.resolves(runData2);

      // Simulate state change
      window.dispatchEvent(
        new CustomEvent("gamestate-changed", {
          detail: { oldState: "STATE_COMBAT", newState: "STATE_MAIN_MENU" },
        })
      );
      await waitForUpdate();

      expect(element.wallet.aetherShards).to.equal(newShards);
    });
  });
});

