import { expect } from "@esm-bundle/chai";
import { InventoryManager } from "../../src/managers/InventoryManager.js";
import { InventoryContainer } from "../../src/models/InventoryContainer.js";
import { Item } from "../../src/items/Item.js";

describe("Manager: InventoryManager", () => {
  let manager;
  let mockItemRegistry;
  let mockUnit;
  let runStash;
  let hubStash;

  beforeEach(() => {
    // Mock Item Registry
    mockItemRegistry = {
      get: (defId) => {
        const items = {
          "ITEM_RUSTY_BLADE": new Item({
            id: "ITEM_RUSTY_BLADE",
            name: "Rusty Blade",
            type: "WEAPON",
            stats: { attack: 3 },
            requirements: {},
          }),
          "ITEM_SCRAP_PLATE": new Item({
            id: "ITEM_SCRAP_PLATE",
            name: "Scrap Plate",
            type: "ARMOR",
            stats: { defense: 3 },
            requirements: {},
          }),
          "ITEM_TINKER_GUN": new Item({
            id: "ITEM_TINKER_GUN",
            name: "Tinker Gun",
            type: "WEAPON",
            stats: { attack: 5 },
            requirements: { class_lock: ["CLASS_TINKER"] },
          }),
          "ITEM_TWO_HANDED_SWORD": new Item({
            id: "ITEM_TWO_HANDED_SWORD",
            name: "Greatsword",
            type: "WEAPON",
            stats: { attack: 10 },
            requirements: {},
            tags: ["TWO_HANDED"],
          }),
          "ITEM_SHIELD": new Item({
            id: "ITEM_SHIELD",
            name: "Shield",
            type: "UTILITY",
            stats: { defense: 2 },
            requirements: {},
          }),
          "ITEM_HEALTH_POTION": new Item({
            id: "ITEM_HEALTH_POTION",
            name: "Health Potion",
            type: "CONSUMABLE",
            stats: {},
            requirements: {},
          }),
        };
        return items[defId] || null;
      },
    };

    // Mock Unit (Explorer)
    mockUnit = {
      id: "UNIT_001",
      activeClassId: "CLASS_VANGUARD",
      baseStats: {
        health: 100,
        attack: 10,
        defense: 5,
        magic: 0,
        speed: 10,
        willpower: 5,
        movement: 4,
        tech: 0,
      },
      loadout: {
        mainHand: null,
        offHand: null,
        body: null,
        accessory: null,
        belt: [null, null],
      },
      recalculateStats: () => {
        // Mock stat recalculation
      },
    };

    runStash = new InventoryContainer("RUN_LOOT");
    hubStash = new InventoryContainer("HUB_VAULT");

    manager = new InventoryManager(mockItemRegistry, runStash, hubStash);
  });

  describe("canEquip", () => {
    it("should return true if unit meets requirements", () => {
      const itemInstance = {
        uid: "ITEM_001",
        defId: "ITEM_RUSTY_BLADE",
        isNew: false,
        quantity: 1,
      };

      const canEquip = manager.canEquip(mockUnit, itemInstance);
      expect(canEquip).to.be.true;
    });

    it("should return false if unit does not meet class requirements", () => {
      const itemInstance = {
        uid: "ITEM_002",
        defId: "ITEM_TINKER_GUN",
        isNew: false,
        quantity: 1,
      };

      const canEquip = manager.canEquip(mockUnit, itemInstance);
      expect(canEquip).to.be.false;
    });

    it("should return false if item definition not found", () => {
      const itemInstance = {
        uid: "ITEM_003",
        defId: "ITEM_NONEXISTENT",
        isNew: false,
        quantity: 1,
      };

      const canEquip = manager.canEquip(mockUnit, itemInstance);
      expect(canEquip).to.be.false;
    });
  });

  describe("equipItem", () => {
    it("should equip item to mainHand slot", () => {
      const itemInstance = {
        uid: "ITEM_001",
        defId: "ITEM_RUSTY_BLADE",
        isNew: false,
        quantity: 1,
      };

      hubStash.addItem(itemInstance);
      const result = manager.equipItem(mockUnit, itemInstance, "MAIN_HAND");

      expect(result).to.be.true;
      expect(mockUnit.loadout.mainHand).to.deep.equal(itemInstance);
      expect(hubStash.findItem("ITEM_001")).to.be.null; // Removed from stash
    });

    it("should swap item if slot is occupied", () => {
      const existingItem = {
        uid: "ITEM_002",
        defId: "ITEM_SCRAP_PLATE",
        isNew: false,
        quantity: 1,
      };

      const newItem = {
        uid: "ITEM_001",
        defId: "ITEM_RUSTY_BLADE",
        isNew: false,
        quantity: 1,
      };

      mockUnit.loadout.mainHand = existingItem;
      hubStash.addItem(newItem);

      const result = manager.equipItem(mockUnit, newItem, "MAIN_HAND");

      expect(result).to.be.true;
      expect(mockUnit.loadout.mainHand).to.deep.equal(newItem);
      expect(hubStash.findItem("ITEM_002")).to.deep.equal(existingItem); // Old item in stash
    });

    it("should automatically unequip offHand when equipping two-handed weapon", () => {
      const twoHandedItem = {
        uid: "ITEM_003",
        defId: "ITEM_TWO_HANDED_SWORD",
        isNew: false,
        quantity: 1,
      };

      const shieldItem = {
        uid: "ITEM_004",
        defId: "ITEM_SHIELD",
        isNew: false,
        quantity: 1,
      };

      mockUnit.loadout.offHand = shieldItem;
      hubStash.addItem(twoHandedItem);

      const result = manager.equipItem(mockUnit, twoHandedItem, "MAIN_HAND");

      expect(result).to.be.true;
      expect(mockUnit.loadout.mainHand).to.deep.equal(twoHandedItem);
      expect(mockUnit.loadout.offHand).to.be.null; // Off-hand unequipped
      expect(hubStash.findItem("ITEM_004")).to.deep.equal(shieldItem); // Shield in stash
    });

    it("should return false if item cannot be equipped", () => {
      const itemInstance = {
        uid: "ITEM_002",
        defId: "ITEM_TINKER_GUN",
        isNew: false,
        quantity: 1,
      };

      hubStash.addItem(itemInstance);
      const result = manager.equipItem(mockUnit, itemInstance, "MAIN_HAND");

      expect(result).to.be.false;
      expect(mockUnit.loadout.mainHand).to.be.null;
      expect(hubStash.findItem("ITEM_002")).to.exist; // Still in stash
    });

    it("should equip item to belt slot", () => {
      const potion = {
        uid: "ITEM_005",
        defId: "ITEM_HEALTH_POTION",
        isNew: false,
        quantity: 1,
      };

      hubStash.addItem(potion);
      const result = manager.equipItem(mockUnit, potion, "BELT", 0);

      expect(result).to.be.true;
      expect(mockUnit.loadout.belt[0]).to.deep.equal(potion);
    });
  });

  describe("unequipItem", () => {
    it("should unequip item from slot and move to stash", () => {
      const itemInstance = {
        uid: "ITEM_001",
        defId: "ITEM_RUSTY_BLADE",
        isNew: false,
        quantity: 1,
      };

      mockUnit.loadout.mainHand = itemInstance;
      const result = manager.unequipItem(mockUnit, "MAIN_HAND");

      expect(result).to.be.true;
      expect(mockUnit.loadout.mainHand).to.be.null;
      expect(hubStash.findItem("ITEM_001")).to.deep.equal(itemInstance);
    });

    it("should return false if slot is empty", () => {
      const result = manager.unequipItem(mockUnit, "MAIN_HAND");
      expect(result).to.be.false;
    });

    it("should unequip from belt slot", () => {
      const potion = {
        uid: "ITEM_005",
        defId: "ITEM_HEALTH_POTION",
        isNew: false,
        quantity: 1,
      };

      mockUnit.loadout.belt[0] = potion;
      const result = manager.unequipItem(mockUnit, "BELT", 0);

      expect(result).to.be.true;
      expect(mockUnit.loadout.belt[0]).to.be.null;
      expect(hubStash.findItem("ITEM_005")).to.deep.equal(potion);
    });
  });

  describe("transferToStash", () => {
    it("should move item from unit loadout to stash", () => {
      const itemInstance = {
        uid: "ITEM_001",
        defId: "ITEM_RUSTY_BLADE",
        isNew: false,
        quantity: 1,
      };

      mockUnit.loadout.mainHand = itemInstance;
      const result = manager.transferToStash(mockUnit, "MAIN_HAND");

      expect(result).to.be.true;
      expect(mockUnit.loadout.mainHand).to.be.null;
      expect(hubStash.findItem("ITEM_001")).to.deep.equal(itemInstance);
    });

    it("should return false if slot is empty", () => {
      const result = manager.transferToStash(mockUnit, "MAIN_HAND");
      expect(result).to.be.false;
    });
  });
});

