import { expect } from "@esm-bundle/chai";
import sinon from "sinon";
// Import to register custom element
import "../../src/ui/screens/marketplace-screen.js";

describe("UI: MarketplaceScreen", () => {
  let element;
  let container;
  let mockMarketManager;
  let mockInventoryManager;
  let mockHubStash;

  beforeEach(async () => {
    container = document.createElement("div");
    document.body.appendChild(container);
    element = document.createElement("marketplace-screen");
    container.appendChild(element);
    
    // Wait for element to be defined
    await element.updateComplete;

    // Create mock hub stash
    mockHubStash = {
      currency: {
        aetherShards: 1000,
        ancientCores: 0,
      },
    };

    // Create mock inventory manager
    mockInventoryManager = {
      hubStash: mockHubStash,
    };

    // Create mock item registry
    const mockItemRegistry = {
      get: (defId) => {
        const items = {
          "ITEM_RUSTY_BLADE": {
            id: "ITEM_RUSTY_BLADE",
            name: "Rusty Infantry Blade",
            type: "WEAPON",
            rarity: "COMMON",
          },
          "ITEM_SCRAP_PLATE": {
            id: "ITEM_SCRAP_PLATE",
            name: "Scrap Plate Armor",
            type: "ARMOR",
            rarity: "COMMON",
          },
        };
        return items[defId] || null;
      },
    };

    // Create mock market manager
    mockMarketManager = {
      inventoryManager: mockInventoryManager,
      itemRegistry: mockItemRegistry,
      getStockForMerchant: sinon.stub().returns([]),
      buyItem: sinon.stub().resolves(true),
      getState: sinon.stub().returns({
        generationId: "TEST_123",
        stock: [],
        buyback: [],
      }),
    };
  });

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

  // 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: Basic Rendering", () => {
    it("should render marketplace screen with header", async () => {
      await waitForUpdate();

      const header = queryShadow(".header");
      expect(header).to.exist;
      expect(header.textContent).to.include("The Gilded Bazaar");
    });

    it("should display wallet currency", async () => {
      element.marketManager = mockMarketManager;
      await waitForUpdate();

      const walletDisplay = queryShadow(".wallet-display");
      expect(walletDisplay).to.exist;
      expect(walletDisplay.textContent).to.include("1000");
      expect(walletDisplay.textContent).to.include("Shards");
    });

    it("should render merchant tabs", async () => {
      await waitForUpdate();

      const merchantTabs = queryShadowAll(".merchant-tab");
      expect(merchantTabs.length).to.equal(4); // Smith, Tailor, Alchemist, Buyback
    });

    it("should render filter buttons", async () => {
      await waitForUpdate();

      const filterButtons = queryShadowAll(".filter-button");
      expect(filterButtons.length).to.be.greaterThan(0);
    });
  });

  describe("CoA 2: Merchant Tab Switching", () => {
    it("should switch active merchant when tab is clicked", async () => {
      await waitForUpdate();

      const tailorTab = queryShadowAll(".merchant-tab")[1]; // Tailor
      tailorTab.click();
      await waitForUpdate();

      expect(element.activeMerchant).to.equal("TAILOR");
      expect(tailorTab.classList.contains("active")).to.be.true;
    });

    it("should call getStockForMerchant with correct merchant type", async () => {
      element.marketManager = mockMarketManager;
      mockMarketManager.getStockForMerchant.reset();
      mockMarketManager.getStockForMerchant.returns([]);
      await waitForUpdate();

      const smithTab = queryShadowAll(".merchant-tab")[0];
      smithTab.click();
      await waitForUpdate();

      expect(mockMarketManager.getStockForMerchant.calledWith("SMITH")).to.be
        .true;
    });

    it("should reset filter to ALL when switching merchants", async () => {
      element.activeFilter = "WEAPON";
      await waitForUpdate();

      const tailorTab = queryShadowAll(".merchant-tab")[1];
      tailorTab.click();
      await waitForUpdate();

      expect(element.activeFilter).to.equal("ALL");
    });
  });

  describe("CoA 3: Item Display", () => {
    beforeEach(async () => {
      // Reset stub
      mockMarketManager.getStockForMerchant.reset();
      // Set up mock to return items
      mockMarketManager.getStockForMerchant.returns([
        {
          id: "STOCK_001",
          defId: "ITEM_RUSTY_BLADE",
          type: "WEAPON",
          rarity: "COMMON",
          price: 50,
          purchased: false,
        },
        {
          id: "STOCK_002",
          defId: "ITEM_SCRAP_PLATE",
          type: "ARMOR",
          rarity: "COMMON",
          price: 75,
          purchased: false,
        },
      ]);
      element.marketManager = mockMarketManager;
      await waitForUpdate();
      await waitForUpdate(); // Extra update to ensure render completes
    });

    it("should display items in grid", async () => {
      await waitForUpdate();

      const itemCards = queryShadowAll(".item-card");
      expect(itemCards.length).to.equal(2);
    });

    it("should display item names", async () => {
      const itemNames = queryShadowAll(".item-name");
      expect(itemNames.length).to.equal(2);
      expect(itemNames[0].textContent).to.include("Rusty Infantry Blade");
    });

    it("should display item prices", async () => {
      const prices = queryShadowAll(".item-price");
      expect(prices.length).to.equal(2);
      expect(prices[0].textContent).to.include("50");
    });

    it("should apply rarity classes to item cards", async () => {
      await waitForUpdate();

      const itemCards = queryShadowAll(".item-card");
      itemCards.forEach((card) => {
        expect(card.classList.contains("rarity-common")).to.be.true;
      });
    });
  });

  describe("CoA 4: Purchase Flow", () => {
    beforeEach(async () => {
      // Reset stub
      mockMarketManager.getStockForMerchant.reset();
      // Set up mock to return items
      mockMarketManager.getStockForMerchant.returns([
        {
          id: "STOCK_001",
          defId: "ITEM_RUSTY_BLADE",
          type: "WEAPON",
          rarity: "COMMON",
          price: 50,
          purchased: false,
        },
      ]);
      element.marketManager = mockMarketManager;
      await waitForUpdate();
      await waitForUpdate(); // Extra update to ensure render completes
    });

    it("should open modal when item is clicked", async () => {

      const itemCard = queryShadow(".item-card");
      itemCard.click();
      await waitForUpdate();

      const modal = queryShadow(".modal");
      expect(modal).to.exist;
      expect(element.showModal).to.be.true;
    });

    it("should display purchase confirmation in modal", async () => {
      const itemCard = queryShadow(".item-card");
      expect(itemCard).to.exist;
      itemCard.click();
      await waitForUpdate();

      const modalTitle = queryShadow(".modal-title");
      expect(modalTitle).to.exist;
      expect(modalTitle.textContent).to.include("Confirm Purchase");
    });

    it("should call buyItem when confirmed", async () => {
      await waitForUpdate();

      const itemCard = queryShadow(".item-card");
      itemCard.click();
      await waitForUpdate();

      const confirmButton = queryShadow(".btn-primary");
      confirmButton.click();
      await waitForUpdate();

      expect(mockMarketManager.buyItem.calledWith("STOCK_001")).to.be.true;
    });

    it("should close modal after successful purchase", async () => {
      const itemCard = queryShadow(".item-card");
      expect(itemCard).to.exist;
      itemCard.click();
      await waitForUpdate();

      const confirmButton = queryShadow(".btn-primary");
      expect(confirmButton).to.exist;
      confirmButton.click();
      await waitForUpdate();
      await new Promise((resolve) => setTimeout(resolve, 50)); // Wait for async

      expect(element.showModal).to.be.false;
    });

    it("should close modal when cancel is clicked", async () => {
      const itemCard = queryShadow(".item-card");
      expect(itemCard).to.exist;
      itemCard.click();
      await waitForUpdate();

      const cancelButton = queryShadowAll(".btn")[1]; // Cancel button
      expect(cancelButton).to.exist;
      cancelButton.click();
      await waitForUpdate();
      await new Promise((resolve) => setTimeout(resolve, 10)); // Wait for async

      expect(element.showModal).to.be.false;
    });
  });

  describe("CoA 5: Affordability States", () => {
    beforeEach(async () => {
      // Reset stub
      mockMarketManager.getStockForMerchant.reset();
      // Set up mock to return items
      mockMarketManager.getStockForMerchant.returns([
        {
          id: "STOCK_AFFORDABLE",
          defId: "ITEM_RUSTY_BLADE",
          type: "WEAPON",
          rarity: "COMMON",
          price: 50,
          purchased: false,
        },
        {
          id: "STOCK_UNAFFORDABLE",
          defId: "ITEM_SCRAP_PLATE",
          type: "ARMOR",
          rarity: "COMMON",
          price: 2000,
          purchased: false,
        },
      ]);
      element.marketManager = mockMarketManager;
      await waitForUpdate();
      await waitForUpdate(); // Extra update to ensure render completes
    });

    it("should mark affordable items correctly", async () => {
      element.marketManager = mockMarketManager;
      mockHubStash.currency.aetherShards = 1000;
      await waitForUpdate();

      const itemCards = queryShadowAll(".item-card");
      const affordableCard = Array.from(itemCards).find((card) =>
        card.textContent.includes("Rusty Infantry Blade")
      );

      expect(affordableCard).to.exist;
      expect(affordableCard.classList.contains("unaffordable")).to.be.false;
    });

    it("should mark unaffordable items correctly", async () => {
      mockHubStash.currency.aetherShards = 100;
      element._updateWallet();
      await waitForUpdate();

      const itemCards = queryShadowAll(".item-card");
      expect(itemCards.length).to.be.greaterThan(0);
      const unaffordableCard = Array.from(itemCards).find((card) =>
        card.textContent.includes("Scrap Plate")
      );

      expect(unaffordableCard).to.exist;
      expect(unaffordableCard.classList.contains("unaffordable")).to.be.true;
    });

    it("should disable buy button for unaffordable items", async () => {
      mockHubStash.currency.aetherShards = 100;
      element._updateWallet();
      await waitForUpdate();

      const itemCards = queryShadowAll(".item-card");
      expect(itemCards.length).to.be.greaterThan(0);
      const itemCard = itemCards[1]; // Unaffordable item
      expect(itemCard).to.exist;
      itemCard.click();
      await waitForUpdate();

      const confirmButton = queryShadow(".btn-primary");
      expect(confirmButton).to.exist;
      expect(confirmButton.disabled).to.be.true;
    });
  });

  describe("CoA 6: Sold Out State", () => {
    beforeEach(async () => {
      // Reset stub
      mockMarketManager.getStockForMerchant.reset();
      // Set up mock to return sold item
      mockMarketManager.getStockForMerchant.returns([
        {
          id: "STOCK_SOLD",
          defId: "ITEM_RUSTY_BLADE",
          type: "WEAPON",
          rarity: "COMMON",
          price: 50,
          purchased: true,
        },
      ]);
      element.marketManager = mockMarketManager;
      await waitForUpdate();
      await waitForUpdate(); // Extra update to ensure render completes
    });

    it("should display sold out overlay", async () => {
      const itemCards = queryShadowAll(".item-card");
      expect(itemCards.length).to.be.greaterThan(0);
      
      const soldOverlay = queryShadow(".sold-overlay");
      expect(soldOverlay).to.exist;
      expect(soldOverlay.textContent).to.include("SOLD");
    });

    it("should apply sold-out class to card", async () => {
      const itemCard = queryShadow(".item-card");
      expect(itemCard).to.exist;
      expect(itemCard.classList.contains("sold-out")).to.be.true;
    });

    it("should not open modal when sold item is clicked", async () => {
      const itemCard = queryShadow(".item-card");
      expect(itemCard).to.exist;
      itemCard.click();
      await waitForUpdate();

      const modal = queryShadow(".modal");
      expect(modal).to.be.null;
    });
  });

  describe("CoA 7: Filter Functionality", () => {
    beforeEach(async () => {
      // Reset stub
      mockMarketManager.getStockForMerchant.reset();
      // Set up mock to return items
      mockMarketManager.getStockForMerchant.returns([
        {
          id: "STOCK_WEAPON",
          defId: "ITEM_RUSTY_BLADE",
          type: "WEAPON",
          rarity: "COMMON",
          price: 50,
          purchased: false,
        },
        {
          id: "STOCK_ARMOR",
          defId: "ITEM_SCRAP_PLATE",
          type: "ARMOR",
          rarity: "COMMON",
          price: 75,
          purchased: false,
        },
      ]);
      element.marketManager = mockMarketManager;
      await waitForUpdate();
      await waitForUpdate(); // Extra update to ensure render completes
    });

    it("should filter items by type", async () => {
      await waitForUpdate();

      const weaponFilter = Array.from(queryShadowAll(".filter-button")).find(
        (btn) => btn.textContent.includes("Weapons")
      );
      weaponFilter.click();
      await waitForUpdate();

      expect(element.activeFilter).to.equal("WEAPON");
      const itemCards = queryShadowAll(".item-card");
      expect(itemCards.length).to.equal(1);
    });

    it("should show all items when ALL filter is selected", async () => {
      element.activeFilter = "WEAPON";
      await waitForUpdate();

      const allFilter = Array.from(queryShadowAll(".filter-button")).find(
        (btn) => btn.textContent.includes("All")
      );
      allFilter.click();
      await waitForUpdate();

      expect(element.activeFilter).to.equal("ALL");
      const itemCards = queryShadowAll(".item-card");
      expect(itemCards.length).to.equal(2);
    });
  });

  describe("CoA 8: Event Dispatching", () => {
    it("should dispatch market-closed event when close button is clicked", async () => {
      const closeSpy = sinon.spy();
      element.addEventListener("market-closed", closeSpy);

      await waitForUpdate();

      const closeButton = queryShadow(".btn-close");
      closeButton.click();
      await waitForUpdate();

      expect(closeSpy.called).to.be.true;
    });
  });

  describe("Empty State", () => {
    it("should display empty state when no items available", async () => {
      mockMarketManager.getStockForMerchant.returns([]);
      await waitForUpdate();

      const emptyState = queryShadow(".empty-state");
      expect(emptyState).to.exist;
      expect(emptyState.textContent).to.include("No items available");
    });
  });

  describe("Wallet Updates", () => {
    it("should update wallet display after purchase", async () => {
      element.marketManager = mockMarketManager;
      mockMarketManager.getStockForMerchant.returns([
        {
          id: "STOCK_001",
          defId: "ITEM_RUSTY_BLADE",
          type: "WEAPON",
          rarity: "COMMON",
          price: 50,
          purchased: false,
        },
      ]);

      mockHubStash.currency.aetherShards = 1000;
      await waitForUpdate();
      await new Promise((resolve) => setTimeout(resolve, 10)); // Extra wait for wallet update

      const itemCard = queryShadow(".item-card");
      expect(itemCard).to.exist;
      itemCard.click();
      await waitForUpdate();

      // Simulate purchase - update currency before clicking
      mockHubStash.currency.aetherShards = 950;
      const confirmButton = queryShadow(".btn-primary");
      expect(confirmButton).to.exist;
      confirmButton.click();
      await waitForUpdate();
      await new Promise((resolve) => setTimeout(resolve, 50)); // Wait for async

      // Wallet should be updated (component calls _updateWallet after purchase)
      expect(element.wallet.aetherShards).to.equal(950);
    });
  });
});

