import { expect } from "@esm-bundle/chai";
import { CombatHUD } from "../../src/ui/combat-hud.js";

describe("UI: CombatHUD", () => {
  let element;
  let container;

  beforeEach(() => {
    container = document.createElement("div");
    document.body.appendChild(container);
    element = document.createElement("combat-hud");
    container.appendChild(element);
  });

  afterEach(() => {
    if (container.parentNode) {
      container.parentNode.removeChild(container);
    }
  });

  // Helper to create mock combat state
  function createMockCombatState(overrides = {}) {
    return {
      activeUnit: {
        id: "unit1",
        name: "Test Unit",
        portrait: "/test/portrait.png",
        hp: { current: 80, max: 100 },
        ap: { current: 5, max: 10 },
        charge: 50,
        statuses: [
          {
            id: "buff1",
            icon: "⚡",
            turnsRemaining: 2,
            description: "Energized",
          },
        ],
        skills: [
          {
            id: "skill1",
            name: "Attack",
            icon: "⚔",
            costAP: 3,
            cooldown: 0,
            isAvailable: true,
          },
          {
            id: "skill2",
            name: "Heal",
            icon: "💚",
            costAP: 5,
            cooldown: 0,
            isAvailable: true,
          },
        ],
      },
      turnQueue: [
        {
          unitId: "unit1",
          portrait: "/test/portrait1.png",
          team: "PLAYER",
          initiative: 100,
        },
        {
          unitId: "unit2",
          portrait: "/test/portrait2.png",
          team: "ENEMY",
          initiative: 80,
        },
        {
          unitId: "unit3",
          portrait: "/test/portrait3.png",
          team: "PLAYER",
          initiative: 60,
        },
        {
          unitId: "unit4",
          portrait: "/test/portrait4.png",
          team: "ENEMY",
          initiative: 40,
        },
        {
          unitId: "unit5",
          portrait: "/test/portrait5.png",
          team: "PLAYER",
          initiative: 20,
        },
      ],
      targetingMode: false,
      roundNumber: 1,
      ...overrides,
    };
  }

  // Helper to wait for Lit updates
  async function waitForUpdate() {
    await element.updateComplete;
    // Give DOM a moment to settle
    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: State Hydration", () => {
    it("should re-render when combatState is updated", async () => {
      const initialState = createMockCombatState();
      element.combatState = initialState;
      await waitForUpdate();

      // Verify initial render
      expect(queryShadow(".unit-name")?.textContent.trim()).to.equal(
        "Test Unit"
      );

      // Update combat state
      const updatedState = createMockCombatState({
        activeUnit: {
          ...initialState.activeUnit,
          name: "Updated Unit",
        },
      });
      element.combatState = updatedState;
      await waitForUpdate();

      // Verify re-render
      expect(queryShadow(".unit-name")?.textContent.trim()).to.equal(
        "Updated Unit"
      );
    });

    it("should hide Action Bar when activeUnit is null", async () => {
      const state = createMockCombatState({
        activeUnit: null,
      });
      element.combatState = state;
      await waitForUpdate();

      // Action bar should not be visible or should be empty
      const actionBar = queryShadow(".action-bar");
      const skillButtons = queryShadowAll(".skill-button");

      // Either action bar doesn't exist or has no skill buttons
      expect(skillButtons.length).to.equal(0);
    });

    it("should hide Unit Status when activeUnit is null", async () => {
      const state = createMockCombatState({
        activeUnit: null,
      });
      element.combatState = state;
      await waitForUpdate();

      // Unit status should not be visible
      const unitStatus = queryShadow(".unit-status");
      expect(unitStatus).to.be.null;
    });
  });

  describe("CoA 2: Turn Queue Visualization", () => {
    it("should display at least 5 units in the queue", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      const queuePortraits = queryShadowAll(".queue-portrait");
      expect(queuePortraits.length).to.be.at.least(5);
    });

    it("should make the first unit visually distinct (larger and gold border)", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      const queuePortraits = queryShadowAll(".queue-portrait");
      expect(queuePortraits.length).to.be.greaterThan(0);

      const firstPortrait = queuePortraits[0];
      expect(firstPortrait.classList.contains("active")).to.be.true;

      // Check computed styles for size difference
      const firstRect = firstPortrait.getBoundingClientRect();
      if (queuePortraits.length > 1) {
        const secondRect = queuePortraits[1].getBoundingClientRect();
        // First should be larger
        expect(firstRect.width).to.be.greaterThan(secondRect.width);
        expect(firstRect.height).to.be.greaterThan(secondRect.height);
      }

      // Check for gold border class
      const styles = window.getComputedStyle(firstPortrait);
      // The active class should be present, which applies gold border via CSS
      expect(firstPortrait.classList.contains("active")).to.be.true;
    });

    it("should show enemy intent icon when enemy is active", async () => {
      const state = createMockCombatState({
        turnQueue: [
          {
            unitId: "enemy1",
            portrait: "/test/enemy.png",
            team: "ENEMY",
            initiative: 100,
          },
        ],
      });
      element.combatState = state;
      await waitForUpdate();

      const enemyIntent = queryShadow(".enemy-intent");
      // Enemy intent should be visible when first unit is enemy
      const firstPortrait = queryShadow(".queue-portrait.active");
      if (firstPortrait) {
        const intent = firstPortrait.querySelector(".enemy-intent");
        // Intent icon should exist for enemy active unit
        expect(intent).to.exist;
      }
    });
  });

  describe("CoA 3: Action Bar Logic", () => {
    it("should display AP cost on skill buttons", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      const skillButtons = queryShadowAll(".skill-button");
      expect(skillButtons.length).to.be.greaterThan(0);

      // Check first skill button has AP cost displayed
      const firstButton = skillButtons[0];
      const costElement = firstButton.querySelector(".cost");
      expect(costElement).to.exist;
      expect(costElement.textContent).to.include("AP");
    });

    it("should disable skill button when unit.ap.current < skill.costAP", async () => {
      const state = createMockCombatState({
        activeUnit: {
          id: "unit1",
          name: "Low AP Unit",
          portrait: "/test/portrait.png",
          hp: { current: 100, max: 100 },
          ap: { current: 2, max: 10 }, // Only 2 AP
          charge: 0,
          statuses: [],
          skills: [
            {
              id: "skill1",
              name: "Expensive Skill",
              icon: "⚔",
              costAP: 5, // Costs 5 AP, but unit only has 2
              cooldown: 0,
              isAvailable: false, // Should be false due to insufficient AP
            },
            {
              id: "skill2",
              name: "Cheap Skill",
              icon: "💚",
              costAP: 1, // Costs 1 AP, unit has 2
              cooldown: 0,
              isAvailable: true,
            },
          ],
        },
      });
      element.combatState = state;
      await waitForUpdate();

      const skillButtons = queryShadowAll(".skill-button");
      expect(skillButtons.length).to.equal(2);

      // First skill (expensive) should be disabled
      const expensiveButton = Array.from(skillButtons).find((btn) =>
        btn.textContent.includes("Expensive")
      );
      expect(expensiveButton).to.exist;
      expect(expensiveButton.disabled).to.be.true;
      expect(
        expensiveButton.classList.contains("disabled") ||
          expensiveButton.hasAttribute("disabled")
      ).to.be.true;

      // Second skill (cheap) should be enabled
      const cheapButton = Array.from(skillButtons).find((btn) =>
        btn.textContent.includes("Cheap")
      );
      expect(cheapButton).to.exist;
      expect(cheapButton.disabled).to.be.false;
    });

    it("should dispatch skill-click event with correct ID when skill button is clicked", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      let capturedEvent = null;
      element.addEventListener("skill-click", (e) => {
        capturedEvent = e;
      });

      const skillButtons = queryShadowAll(".skill-button");
      expect(skillButtons.length).to.be.greaterThan(0);

      const firstButton = skillButtons[0];
      firstButton.click();

      await waitForUpdate();

      expect(capturedEvent).to.exist;
      expect(capturedEvent.detail.skillId).to.equal("skill1");
    });

    it("should disable skill button when isAvailable is false", async () => {
      const state = createMockCombatState({
        activeUnit: {
          id: "unit1",
          name: "Test Unit",
          portrait: "/test/portrait.png",
          hp: { current: 100, max: 100 },
          ap: { current: 10, max: 10 },
          charge: 0,
          statuses: [],
          skills: [
            {
              id: "skill1",
              name: "On Cooldown",
              icon: "⚔",
              costAP: 3,
              cooldown: 2, // On cooldown
              isAvailable: false,
            },
          ],
        },
      });
      element.combatState = state;
      await waitForUpdate();

      const skillButtons = queryShadowAll(".skill-button");
      expect(skillButtons.length).to.equal(1);

      const button = skillButtons[0];
      expect(button.disabled).to.be.true;
    });

    it("should display cooldown number when skill is on cooldown", async () => {
      const state = createMockCombatState({
        activeUnit: {
          id: "unit1",
          name: "Test Unit",
          portrait: "/test/portrait.png",
          hp: { current: 100, max: 100 },
          ap: { current: 10, max: 10 },
          charge: 0,
          statuses: [],
          skills: [
            {
              id: "skill1",
              name: "On Cooldown",
              icon: "⚔",
              costAP: 3,
              cooldown: 3,
              isAvailable: false,
            },
          ],
        },
      });
      element.combatState = state;
      await waitForUpdate();

      const skillButton = queryShadow(".skill-button");
      const cooldownElement = skillButton?.querySelector(".cooldown");
      expect(cooldownElement).to.exist;
      expect(cooldownElement.textContent.trim()).to.equal("3");
    });
  });

  describe("CoA 4: Responsive Design", () => {
    it("should stack Unit Status and Action Bar vertically on mobile (< 768px)", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      // Simulate mobile viewport
      const originalWidth = window.innerWidth;
      const originalHeight = window.innerHeight;

      // Mock window.innerWidth to be mobile size
      Object.defineProperty(window, "innerWidth", {
        writable: true,
        configurable: true,
        value: 600,
      });

      // Trigger a resize or re-render
      element.combatState = { ...state };
      await waitForUpdate();

      const bottomBar = queryShadow(".bottom-bar");
      expect(bottomBar).to.exist;

      // Check if flex-direction is column on mobile
      // Note: We can't easily test media queries in unit tests without more setup
      // But we can verify the structure exists and can be styled responsively
      const unitStatus = queryShadow(".unit-status");
      const actionBar = queryShadow(".action-bar");

      expect(unitStatus).to.exist;
      expect(actionBar).to.exist;

      // Restore original width
      Object.defineProperty(window, "innerWidth", {
        writable: true,
        configurable: true,
        value: originalWidth,
      });
    });
  });

  describe("Additional Functionality", () => {
    it("should dispatch end-turn event when End Turn button is clicked", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      let eventDispatched = false;
      element.addEventListener("end-turn", () => {
        eventDispatched = true;
      });

      const endTurnButton = queryShadow(".end-turn-button");
      expect(endTurnButton).to.exist;

      endTurnButton.click();
      await waitForUpdate();

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

    it("should display round number in global info", async () => {
      const state = createMockCombatState({ roundNumber: 5 });
      element.combatState = state;
      await waitForUpdate();

      const roundCounter = queryShadow(".round-counter");
      expect(roundCounter).to.exist;
      expect(roundCounter.textContent).to.include("Round 5");
    });

    it("should display threat level in global info", async () => {
      const state = createMockCombatState({
        turnQueue: [
          {
            unitId: "e1",
            portrait: "/test/e1.png",
            team: "ENEMY",
            initiative: 100,
          },
          {
            unitId: "e2",
            portrait: "/test/e2.png",
            team: "ENEMY",
            initiative: 90,
          },
          {
            unitId: "e3",
            portrait: "/test/e3.png",
            team: "ENEMY",
            initiative: 80,
          },
        ],
      });
      element.combatState = state;
      await waitForUpdate();

      const threatLevel = queryShadow(".threat-level");
      expect(threatLevel).to.exist;
      // With 3+ enemies, should be HIGH
      expect(threatLevel.classList.contains("high")).to.be.true;
    });

    it("should display unit HP, AP, and Charge bars", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      const hpBar = queryShadow(".bar-fill.hp");
      const apBar = queryShadow(".bar-fill.ap");
      const chargeBar = queryShadow(".bar-fill.charge");

      expect(hpBar).to.exist;
      expect(apBar).to.exist;
      expect(chargeBar).to.exist;

      // Check that bars have correct width percentages
      expect(hpBar.style.width).to.include("%");
      expect(apBar.style.width).to.include("%");
      expect(chargeBar.style.width).to.include("%");
    });

    it("should display status icons with tooltips", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      const statusIcons = queryShadowAll(".status-icon");
      expect(statusIcons.length).to.equal(1);

      const statusIcon = statusIcons[0];
      expect(statusIcon.getAttribute("data-description")).to.exist;
      expect(statusIcon.textContent).to.include("⚡");
    });

    it("should display hotkeys (1-5) on skill buttons", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      const skillButtons = queryShadowAll(".skill-button");
      expect(skillButtons.length).to.be.greaterThan(0);

      skillButtons.forEach((button, index) => {
        const hotkey = button.querySelector(".hotkey");
        expect(hotkey).to.exist;
        expect(hotkey.textContent.trim()).to.equal(String(index + 1));
      });
    });

    it("should dispatch hover-skill event when hovering over skill", async () => {
      const state = createMockCombatState();
      element.combatState = state;
      await waitForUpdate();

      let capturedEvent = null;
      element.addEventListener("hover-skill", (e) => {
        capturedEvent = e;
      });

      const skillButton = queryShadow(".skill-button");
      expect(skillButton).to.exist;

      // Simulate mouseenter event
      skillButton.dispatchEvent(
        new MouseEvent("mouseenter", { bubbles: true })
      );
      await waitForUpdate();

      expect(capturedEvent).to.exist;
      expect(capturedEvent.detail.skillId).to.equal("skill1");
    });
  });
});
