import React from 'react';

/* ────────────────────────────────────────────────────────────────
   Inventory System
   
   A comprehensive inventory management system with:
   - Multiple container types (player, chest, shop, crafting)
   - Equipment slots with stat modifiers
   - Item stacking, splitting, and merging
   - Weight/capacity limits
   - Item categories and rarity
   - Crafting recipes
   - Trade/shop transactions
   - Loot tables and drop rates
   - Item durability and repair
   - Consumables with effects
   - State persistence
──────────────────────────────────────────────────────────────── */
const DEFAULT_CONFIG = {
    defaultSlots: 40,
    enableWeight: true,
    enableDurability: true,
    autoStack: true,
    autoSort: false,
    maxContainersPerEntity: 5,
};
class InventoryManager {
    constructor(config = {}) {
        this.eventBus = null;
        // Registries
        this.itemDefinitions = new Map();
        this.containers = new Map();
        this.equipment = new Map();
        this.recipes = new Map();
        this.lootTables = new Map();
        this.shops = new Map();
        this.learnedRecipes = new Map();
        this.cooldowns = new Map(); // instanceId -> lastUsed
        this.config = { ...DEFAULT_CONFIG, ...config };
    }
    /* ── Initialization ─────────────────────────────────────────── */
    setEventBus(bus) {
        this.eventBus = bus;
    }
    emit(event) {
        var _a;
        (_a = this.eventBus) === null || _a === void 0 ? void 0 : _a.emit(`inventory:${event.type}`, event);
    }
    /* ── Item Definitions ───────────────────────────────────────── */
    registerItem(definition) {
        this.itemDefinitions.set(definition.id, definition);
    }
    registerItems(definitions) {
        definitions.forEach(def => this.registerItem(def));
    }
    getItemDefinition(itemId) {
        return this.itemDefinitions.get(itemId);
    }
    getAllItemDefinitions() {
        return Array.from(this.itemDefinitions.values());
    }
    /* ── Container Management ───────────────────────────────────── */
    createContainer(type, ownerId, options = {}) {
        var _a, _b, _c, _d;
        const id = (_a = options.id) !== null && _a !== void 0 ? _a : `container_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
        const maxSlots = (_b = options.maxSlots) !== null && _b !== void 0 ? _b : this.config.defaultSlots;
        const container = {
            id,
            type,
            name: (_c = options.name) !== null && _c !== void 0 ? _c : `${type} container`,
            ownerId,
            maxSlots,
            maxWeight: options.maxWeight,
            slots: Array.from({ length: maxSlots }, (_, i) => ({ index: i, item: null })),
            currency: (_d = options.currency) !== null && _d !== void 0 ? _d : new Map(),
            allowedCategories: options.allowedCategories,
            disallowedCategories: options.disallowedCategories,
        };
        this.containers.set(id, container);
        this.emit({ type: 'container:created', containerId: id, ownerId, timestamp: Date.now() });
        return container;
    }
    getContainer(containerId) {
        return this.containers.get(containerId);
    }
    getContainersByOwner(ownerId) {
        return Array.from(this.containers.values()).filter(c => c.ownerId === ownerId);
    }
    destroyContainer(containerId) {
        const container = this.containers.get(containerId);
        if (!container)
            return false;
        this.containers.delete(containerId);
        this.emit({ type: 'container:destroyed', containerId, ownerId: container.ownerId, timestamp: Date.now() });
        return true;
    }
    /* ── Item Instance Creation ─────────────────────────────────── */
    createItemInstance(itemId, count = 1, options = {}) {
        var _a;
        const def = this.itemDefinitions.get(itemId);
        if (!def)
            return null;
        // Extract count from options to prevent override
        const { count: _ignoredCount, ...restOptions } = options;
        const instance = {
            instanceId: (_a = restOptions.instanceId) !== null && _a !== void 0 ? _a : `item_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`,
            itemId,
            count: Math.min(count, def.maxStack),
            durability: def.maxDurability,
            createdAt: Date.now(),
            ...restOptions,
        };
        return instance;
    }
    /* ── Basic Operations ───────────────────────────────────────── */
    addItem(containerId, itemId, count = 1, options = {}) {
        var _a, _b, _c;
        const container = this.containers.get(containerId);
        if (!container)
            return null;
        const def = this.itemDefinitions.get(itemId);
        if (!def)
            return null;
        // Check category restrictions
        if (container.allowedCategories && !container.allowedCategories.includes(def.category)) {
            return null;
        }
        if ((_a = container.disallowedCategories) === null || _a === void 0 ? void 0 : _a.includes(def.category)) {
            return null;
        }
        // Check weight
        if (this.config.enableWeight && container.maxWeight !== undefined) {
            const currentWeight = this.getContainerWeight(containerId);
            if (currentWeight + (def.weight * count) > container.maxWeight) {
                return null;
            }
        }
        // Try to stack with existing items first
        if (this.config.autoStack && def.maxStack > 1) {
            for (const slot of container.slots) {
                if (slot.item && slot.item.itemId === itemId && slot.item.count < def.maxStack) {
                    const space = def.maxStack - slot.item.count;
                    const toAdd = Math.min(count, space);
                    slot.item.count += toAdd;
                    count -= toAdd;
                    this.emit({
                        type: 'item:stacked',
                        containerId,
                        ownerId: container.ownerId,
                        item: slot.item,
                        slot: slot.index,
                        count: toAdd,
                        timestamp: Date.now(),
                    });
                    if (count <= 0)
                        return slot.item;
                }
            }
        }
        // Find empty slot for remaining
        while (count > 0) {
            const emptySlot = container.slots.find(s => !s.item && !s.locked);
            if (!emptySlot)
                return null; // No space
            const stackCount = Math.min(count, def.maxStack);
            const instance = this.createItemInstance(itemId, stackCount, options);
            if (!instance)
                return null;
            emptySlot.item = instance;
            count -= stackCount;
            this.emit({
                type: 'item:added',
                containerId,
                ownerId: container.ownerId,
                item: instance,
                slot: emptySlot.index,
                count: stackCount,
                timestamp: Date.now(),
            });
        }
        return (_c = (_b = container.slots.find(s => { var _a; return ((_a = s.item) === null || _a === void 0 ? void 0 : _a.itemId) === itemId; })) === null || _b === void 0 ? void 0 : _b.item) !== null && _c !== void 0 ? _c : null;
    }
    removeItem(containerId, slotIndex, count = 1) {
        const container = this.containers.get(containerId);
        if (!container)
            return null;
        const slot = container.slots[slotIndex];
        if (!(slot === null || slot === void 0 ? void 0 : slot.item))
            return null;
        const removed = { ...slot.item };
        if (slot.item.count <= count) {
            slot.item = null;
            // removed already has the correct count from the spread above
        }
        else {
            slot.item.count -= count;
            removed.count = count;
        }
        this.emit({
            type: 'item:removed',
            containerId,
            ownerId: container.ownerId,
            item: removed,
            slot: slotIndex,
            count: removed.count,
            timestamp: Date.now(),
        });
        return removed;
    }
    moveItem(fromContainerId, fromSlot, toContainerId, toSlot) {
        const fromContainer = this.containers.get(fromContainerId);
        const toContainer = this.containers.get(toContainerId);
        if (!fromContainer || !toContainer)
            return false;
        const sourceSlot = fromContainer.slots[fromSlot];
        const targetSlot = toContainer.slots[toSlot];
        if (!(sourceSlot === null || sourceSlot === void 0 ? void 0 : sourceSlot.item) || !targetSlot)
            return false;
        const def = this.itemDefinitions.get(sourceSlot.item.itemId);
        if (!def)
            return false;
        // Check target container restrictions
        if (toContainer.allowedCategories && !toContainer.allowedCategories.includes(def.category)) {
            return false;
        }
        // Swap or stack
        if (targetSlot.item) {
            if (targetSlot.item.itemId === sourceSlot.item.itemId &&
                targetSlot.item.count < def.maxStack) {
                // Stack
                const space = def.maxStack - targetSlot.item.count;
                const toMove = Math.min(sourceSlot.item.count, space);
                targetSlot.item.count += toMove;
                sourceSlot.item.count -= toMove;
                if (sourceSlot.item.count <= 0)
                    sourceSlot.item = null;
            }
            else {
                // Swap
                const temp = sourceSlot.item;
                sourceSlot.item = targetSlot.item;
                targetSlot.item = temp;
            }
        }
        else {
            // Move to empty slot
            targetSlot.item = sourceSlot.item;
            sourceSlot.item = null;
        }
        this.emit({
            type: 'item:moved',
            containerId: fromContainerId,
            ownerId: fromContainer.ownerId,
            fromSlot,
            toSlot,
            timestamp: Date.now(),
        });
        return true;
    }
    splitStack(containerId, slotIndex, splitCount) {
        const container = this.containers.get(containerId);
        if (!container)
            return false;
        const slot = container.slots[slotIndex];
        if (!(slot === null || slot === void 0 ? void 0 : slot.item) || slot.item.count <= splitCount)
            return false;
        const emptySlot = container.slots.find(s => !s.item && !s.locked);
        if (!emptySlot)
            return false;
        const newInstance = this.createItemInstance(slot.item.itemId, splitCount, { ...slot.item, instanceId: undefined });
        if (!newInstance)
            return false;
        slot.item.count -= splitCount;
        emptySlot.item = newInstance;
        this.emit({
            type: 'item:split',
            containerId,
            ownerId: container.ownerId,
            item: newInstance,
            fromSlot: slotIndex,
            toSlot: emptySlot.index,
            count: splitCount,
            timestamp: Date.now(),
        });
        return true;
    }
    /* ── Weight & Capacity ──────────────────────────────────────── */
    getContainerWeight(containerId) {
        const container = this.containers.get(containerId);
        if (!container)
            return 0;
        let weight = 0;
        for (const slot of container.slots) {
            if (slot.item) {
                const def = this.itemDefinitions.get(slot.item.itemId);
                if (def)
                    weight += def.weight * slot.item.count;
            }
        }
        return weight;
    }
    getContainerFreeSlots(containerId) {
        const container = this.containers.get(containerId);
        if (!container)
            return 0;
        return container.slots.filter(s => !s.item && !s.locked).length;
    }
    /* ── Equipment System ───────────────────────────────────────── */
    initializeEquipment(ownerId) {
        const state = {
            ownerId,
            slots: new Map(),
            totalStats: new Map(),
        };
        // Initialize all slots as empty
        const allSlots = [
            'head', 'chest', 'legs', 'feet', 'hands', 'shoulders', 'back', 'waist',
            'mainHand', 'offHand', 'ring1', 'ring2', 'neck', 'trinket1', 'trinket2',
        ];
        allSlots.forEach(slot => state.slots.set(slot, null));
        this.equipment.set(ownerId, state);
        return state;
    }
    getEquipment(ownerId) {
        return this.equipment.get(ownerId);
    }
    equipItem(ownerId, containerId, slotIndex) {
        let equipState = this.equipment.get(ownerId);
        if (!equipState) {
            equipState = this.initializeEquipment(ownerId);
        }
        const container = this.containers.get(containerId);
        if (!container)
            return false;
        const invSlot = container.slots[slotIndex];
        if (!(invSlot === null || invSlot === void 0 ? void 0 : invSlot.item))
            return false;
        const def = this.itemDefinitions.get(invSlot.item.itemId);
        if (!(def === null || def === void 0 ? void 0 : def.equipSlot))
            return false;
        // Check requirements
        // (In real implementation, would check level, class, stats)
        // Handle two-hand weapons
        let targetSlot = def.equipSlot;
        if (targetSlot === 'twoHand') {
            // Unequip both hands
            const mainHand = equipState.slots.get('mainHand');
            const offHand = equipState.slots.get('offHand');
            if (mainHand)
                this.unequipToContainer(ownerId, 'mainHand', containerId);
            if (offHand)
                this.unequipToContainer(ownerId, 'offHand', containerId);
            targetSlot = 'mainHand';
        }
        // Clone the item to equip BEFORE modifying the slot
        const itemToEquip = { ...invSlot.item };
        // Swap with existing equipped item
        const currentEquipped = equipState.slots.get(targetSlot);
        if (currentEquipped) {
            // Put currently equipped item back in inventory
            invSlot.item = currentEquipped;
        }
        else {
            invSlot.item = null;
        }
        equipState.slots.set(targetSlot, itemToEquip);
        // Apply binding
        if (def.binding === 'onEquip' && !itemToEquip.boundTo) {
            itemToEquip.boundTo = String(ownerId);
        }
        // Recalculate stats
        this.recalculateEquipmentStats(ownerId);
        this.emit({
            type: 'item:equipped',
            ownerId,
            item: itemToEquip,
            slot: slotIndex,
            timestamp: Date.now(),
        });
        return true;
    }
    unequipItem(ownerId, equipSlot, containerId) {
        return this.unequipToContainer(ownerId, equipSlot, containerId);
    }
    unequipToContainer(ownerId, equipSlot, containerId) {
        const equipState = this.equipment.get(ownerId);
        if (!equipState)
            return false;
        const equippedItem = equipState.slots.get(equipSlot);
        if (!equippedItem)
            return false;
        const container = this.containers.get(containerId);
        if (!container)
            return false;
        // Find empty slot in container
        const emptySlot = container.slots.find(s => !s.item && !s.locked);
        if (!emptySlot)
            return false; // Inventory full
        emptySlot.item = equippedItem;
        equipState.slots.set(equipSlot, null);
        this.recalculateEquipmentStats(ownerId);
        this.emit({
            type: 'item:unequipped',
            ownerId,
            item: equippedItem,
            slot: emptySlot.index,
            timestamp: Date.now(),
        });
        return true;
    }
    recalculateEquipmentStats(ownerId) {
        var _a, _b;
        const equipState = this.equipment.get(ownerId);
        if (!equipState)
            return;
        equipState.totalStats.clear();
        for (const [, item] of equipState.slots) {
            if (!item)
                continue;
            const def = this.itemDefinitions.get(item.itemId);
            if (!(def === null || def === void 0 ? void 0 : def.stats))
                continue;
            for (const mod of def.stats) {
                const current = (_a = equipState.totalStats.get(mod.stat)) !== null && _a !== void 0 ? _a : 0;
                equipState.totalStats.set(mod.stat, current + ((_b = mod.flat) !== null && _b !== void 0 ? _b : 0));
                // Percent modifiers would need separate handling
            }
        }
    }
    /* ── Durability & Repair ────────────────────────────────────── */
    damageDurability(instance, damage) {
        if (!this.config.enableDurability)
            return false;
        if (instance.durability === undefined)
            return false;
        instance.durability = Math.max(0, instance.durability - damage);
        if (instance.durability <= 0) {
            this.emit({
                type: 'item:destroyed',
                item: instance,
                timestamp: Date.now(),
            });
            return true; // Item broken
        }
        return false;
    }
    repairItem(instance, amount) {
        const def = this.itemDefinitions.get(instance.itemId);
        if (!(def === null || def === void 0 ? void 0 : def.maxDurability) || instance.durability === undefined)
            return false;
        instance.durability = Math.min(def.maxDurability, amount !== undefined ? instance.durability + amount : def.maxDurability);
        this.emit({
            type: 'item:repaired',
            item: instance,
            timestamp: Date.now(),
        });
        return true;
    }
    /* ── Consumables ────────────────────────────────────────────── */
    useItem(containerId, slotIndex, targetEntityId) {
        var _a;
        const container = this.containers.get(containerId);
        if (!container)
            return false;
        const slot = container.slots[slotIndex];
        if (!(slot === null || slot === void 0 ? void 0 : slot.item))
            return false;
        const def = this.itemDefinitions.get(slot.item.itemId);
        if (!def)
            return false;
        // Check cooldown
        if (def.cooldown) {
            const lastUsed = (_a = this.cooldowns.get(slot.item.instanceId)) !== null && _a !== void 0 ? _a : 0;
            if (Date.now() - lastUsed < def.cooldown) {
                return false; // On cooldown
            }
        }
        // Set cooldown
        if (def.cooldown) {
            this.cooldowns.set(slot.item.instanceId, Date.now());
        }
        this.emit({
            type: 'item:used',
            containerId,
            ownerId: container.ownerId,
            item: slot.item,
            slot: slotIndex,
            customData: { targetEntityId, effectId: def.effectId },
            timestamp: Date.now(),
        });
        // Consume if applicable
        if (def.consumeOnUse) {
            slot.item.count--;
            if (slot.item.count <= 0) {
                slot.item = null;
            }
        }
        return true;
    }
    /* ── Crafting System ────────────────────────────────────────── */
    registerRecipe(recipe) {
        this.recipes.set(recipe.id, recipe);
    }
    learnRecipe(entityId, recipeId) {
        const recipe = this.recipes.get(recipeId);
        if (!recipe || !recipe.requiresLearning)
            return false;
        let learned = this.learnedRecipes.get(entityId);
        if (!learned) {
            learned = new Set();
            this.learnedRecipes.set(entityId, learned);
        }
        learned.add(recipeId);
        return true;
    }
    canCraft(entityId, recipeId, containerId) {
        const recipe = this.recipes.get(recipeId);
        if (!recipe)
            return false;
        // Check if recipe is learned
        if (recipe.requiresLearning) {
            const learned = this.learnedRecipes.get(entityId);
            if (!(learned === null || learned === void 0 ? void 0 : learned.has(recipeId)))
                return false;
        }
        // Check ingredients
        const container = this.containers.get(containerId);
        if (!container)
            return false;
        for (const ingredient of recipe.ingredients) {
            const available = this.countItemsInContainer(containerId, ingredient.itemId);
            if (available < ingredient.count)
                return false;
        }
        return true;
    }
    craft(entityId, recipeId, containerId) {
        if (!this.canCraft(entityId, recipeId, containerId))
            return null;
        const recipe = this.recipes.get(recipeId);
        this.containers.get(containerId);
        // Check success
        if (Math.random() > recipe.successRate) {
            // Failed - consume ingredients anyway if consumed flag set
            for (const ingredient of recipe.ingredients) {
                if (ingredient.consumed) {
                    this.removeItemsByIdFromContainer(containerId, ingredient.itemId, ingredient.count);
                }
            }
            this.emit({
                type: 'craft:failed',
                ownerId: entityId,
                recipeId,
                containerId,
                timestamp: Date.now(),
            });
            return null;
        }
        // Consume ingredients
        for (const ingredient of recipe.ingredients) {
            if (ingredient.consumed) {
                this.removeItemsByIdFromContainer(containerId, ingredient.itemId, ingredient.count);
            }
        }
        // Create output
        const output = this.addItem(containerId, recipe.outputItemId, recipe.outputCount);
        this.emit({
            type: 'craft:completed',
            ownerId: entityId,
            recipeId,
            containerId,
            item: output !== null && output !== void 0 ? output : undefined,
            timestamp: Date.now(),
        });
        return output;
    }
    /* ── Loot Tables ────────────────────────────────────────────── */
    registerLootTable(table) {
        this.lootTables.set(table.id, table);
    }
    generateLoot(tableId, modifiers = {}) {
        var _a;
        const table = this.lootTables.get(tableId);
        if (!table)
            return [];
        const loot = [];
        // Guaranteed drops
        if (table.guaranteedDrops) {
            for (const drop of table.guaranteedDrops) {
                const instance = this.createItemInstance(drop.itemId, drop.count);
                if (instance)
                    loot.push(instance);
            }
        }
        // Roll on table
        const validEntries = table.entries.filter(e => {
            var _a, _b;
            if (((_a = e.conditions) === null || _a === void 0 ? void 0 : _a.minLevel) && modifiers.levelContext && modifiers.levelContext < e.conditions.minLevel)
                return false;
            if (((_b = e.conditions) === null || _b === void 0 ? void 0 : _b.maxLevel) && modifiers.levelContext && modifiers.levelContext > e.conditions.maxLevel)
                return false;
            return true;
        });
        const totalWeight = validEntries.reduce((sum, e) => sum + e.weight, 0);
        for (let roll = 0; roll < table.rolls; roll++) {
            let random = Math.random() * totalWeight;
            for (const entry of validEntries) {
                random -= entry.weight;
                if (random <= 0) {
                    // Apply drop chance with luck modifier
                    const effectiveChance = Math.min(1, entry.dropChance + ((_a = modifiers.luckBonus) !== null && _a !== void 0 ? _a : 0));
                    if (Math.random() <= effectiveChance) {
                        const count = Math.floor(entry.minCount + Math.random() * (entry.maxCount - entry.minCount + 1));
                        const instance = this.createItemInstance(entry.itemId, count);
                        if (instance)
                            loot.push(instance);
                    }
                    break;
                }
            }
        }
        this.emit({
            type: 'loot:generated',
            customData: { tableId, loot },
            timestamp: Date.now(),
        });
        return loot;
    }
    /* ── Shop System ────────────────────────────────────────────── */
    registerShop(shop) {
        this.shops.set(shop.id, shop);
    }
    getShop(shopId) {
        return this.shops.get(shopId);
    }
    buyFromShop(shopId, listingIndex, quantity, buyerContainerId) {
        var _a, _b, _c;
        const shop = this.shops.get(shopId);
        const container = this.containers.get(buyerContainerId);
        if (!shop || !container)
            return false;
        const listing = shop.listings[listingIndex];
        if (!listing)
            return false;
        // Check stock
        if (listing.stock !== -1 && listing.stock < quantity)
            return false;
        // Calculate price
        const def = this.itemDefinitions.get(listing.itemId);
        if (!def)
            return false;
        const unitPrice = (_a = listing.price) !== null && _a !== void 0 ? _a : Math.ceil(def.value * shop.sellRate);
        const totalPrice = unitPrice * quantity;
        // Check buyer currency
        const buyerCurrency = (_c = (_b = container.currency) === null || _b === void 0 ? void 0 : _b.get(listing.currencyId)) !== null && _c !== void 0 ? _c : 0;
        if (buyerCurrency < totalPrice)
            return false;
        // Execute transaction
        container.currency.set(listing.currencyId, buyerCurrency - totalPrice);
        const purchased = this.addItem(buyerContainerId, listing.itemId, quantity);
        if (!purchased) {
            // Refund if couldn't add item
            container.currency.set(listing.currencyId, buyerCurrency);
            return false;
        }
        // Update stock
        if (listing.stock !== -1) {
            listing.stock -= quantity;
        }
        this.emit({
            type: 'shop:bought',
            shopId,
            containerId: buyerContainerId,
            ownerId: container.ownerId,
            itemId: listing.itemId,
            count: quantity,
            currencyId: listing.currencyId,
            amount: totalPrice,
            timestamp: Date.now(),
        });
        return true;
    }
    sellToShop(shopId, sellerContainerId, slotIndex, quantity) {
        var _a, _b;
        const shop = this.shops.get(shopId);
        const container = this.containers.get(sellerContainerId);
        if (!shop || !container)
            return false;
        const slot = container.slots[slotIndex];
        if (!(slot === null || slot === void 0 ? void 0 : slot.item) || slot.item.count < quantity)
            return false;
        const def = this.itemDefinitions.get(slot.item.itemId);
        if (!def || !def.sellable)
            return false;
        // Calculate sell price
        const unitPrice = Math.floor(def.value * shop.buyRate);
        const totalPrice = unitPrice * quantity;
        // Use first accepted currency
        const currencyId = shop.acceptedCurrencies[0];
        if (!currencyId)
            return false;
        // Remove items
        this.removeItem(sellerContainerId, slotIndex, quantity);
        // Add currency
        const currentCurrency = (_b = (_a = container.currency) === null || _a === void 0 ? void 0 : _a.get(currencyId)) !== null && _b !== void 0 ? _b : 0;
        container.currency.set(currencyId, currentCurrency + totalPrice);
        this.emit({
            type: 'shop:sold',
            shopId,
            containerId: sellerContainerId,
            ownerId: container.ownerId,
            itemId: def.id,
            count: quantity,
            currencyId,
            amount: totalPrice,
            timestamp: Date.now(),
        });
        return true;
    }
    /* ── Currency ───────────────────────────────────────────────── */
    addCurrency(containerId, currencyId, amount) {
        var _a;
        const container = this.containers.get(containerId);
        if (!container)
            return false;
        if (!container.currency)
            container.currency = new Map();
        const current = (_a = container.currency.get(currencyId)) !== null && _a !== void 0 ? _a : 0;
        container.currency.set(currencyId, current + amount);
        this.emit({
            type: 'currency:changed',
            containerId,
            ownerId: container.ownerId,
            currencyId,
            amount,
            timestamp: Date.now(),
        });
        return true;
    }
    removeCurrency(containerId, currencyId, amount) {
        var _a;
        const container = this.containers.get(containerId);
        if (!(container === null || container === void 0 ? void 0 : container.currency))
            return false;
        const current = (_a = container.currency.get(currencyId)) !== null && _a !== void 0 ? _a : 0;
        if (current < amount)
            return false;
        container.currency.set(currencyId, current - amount);
        this.emit({
            type: 'currency:changed',
            containerId,
            ownerId: container.ownerId,
            currencyId,
            amount: -amount,
            timestamp: Date.now(),
        });
        return true;
    }
    getCurrency(containerId, currencyId) {
        var _a, _b, _c;
        return (_c = (_b = (_a = this.containers.get(containerId)) === null || _a === void 0 ? void 0 : _a.currency) === null || _b === void 0 ? void 0 : _b.get(currencyId)) !== null && _c !== void 0 ? _c : 0;
    }
    /* ── Sorting ────────────────────────────────────────────────── */
    sortContainer(containerId, criteria = 'category') {
        const container = this.containers.get(containerId);
        if (!container)
            return;
        const items = container.slots
            .filter(s => s.item && !s.locked)
            .map(s => s.item)
            .sort((a, b) => {
            const defA = this.itemDefinitions.get(a.itemId);
            const defB = this.itemDefinitions.get(b.itemId);
            if (!defA || !defB)
                return 0;
            switch (criteria) {
                case 'category':
                    return defA.category.localeCompare(defB.category) || defA.name.localeCompare(defB.name);
                case 'rarity': {
                    const rarityOrder = ['common', 'uncommon', 'rare', 'epic', 'legendary', 'mythic', 'unique'];
                    return rarityOrder.indexOf(defB.rarity) - rarityOrder.indexOf(defA.rarity);
                }
                case 'name':
                    return defA.name.localeCompare(defB.name);
                case 'value':
                    return defB.value - defA.value;
                default:
                    return 0;
            }
        });
        // Clear unlocked slots
        container.slots.forEach(s => {
            if (!s.locked)
                s.item = null;
        });
        // Fill with sorted items
        let itemIndex = 0;
        for (const slot of container.slots) {
            if (!slot.locked && itemIndex < items.length) {
                slot.item = items[itemIndex++];
            }
        }
        container.sorted = true;
        this.emit({
            type: 'container:sorted',
            containerId,
            ownerId: container.ownerId,
            timestamp: Date.now(),
        });
    }
    /* ── Utility Methods ────────────────────────────────────────── */
    countItemsInContainer(containerId, itemId) {
        const container = this.containers.get(containerId);
        if (!container)
            return 0;
        return container.slots.reduce((sum, slot) => {
            var _a;
            if (((_a = slot.item) === null || _a === void 0 ? void 0 : _a.itemId) === itemId)
                return sum + slot.item.count;
            return sum;
        }, 0);
    }
    removeItemsByIdFromContainer(containerId, itemId, count) {
        const container = this.containers.get(containerId);
        if (!container)
            return 0;
        let removed = 0;
        for (const slot of container.slots) {
            if (!slot.item || slot.item.itemId !== itemId)
                continue;
            const toRemove = Math.min(count - removed, slot.item.count);
            slot.item.count -= toRemove;
            removed += toRemove;
            if (slot.item.count <= 0)
                slot.item = null;
            if (removed >= count)
                break;
        }
        return removed;
    }
    findItem(containerId, itemId) {
        var _a;
        const container = this.containers.get(containerId);
        if (!container)
            return null;
        for (const slot of container.slots) {
            if (((_a = slot.item) === null || _a === void 0 ? void 0 : _a.itemId) === itemId) {
                return { slot, instance: slot.item };
            }
        }
        return null;
    }
    /* ── Serialization ──────────────────────────────────────────── */
    serialize() {
        return {
            containers: Array.from(this.containers.entries()).map(([id, c]) => ({
                ...c,
                currency: c.currency ? Array.from(c.currency.entries()) : [],
            })),
            equipment: Array.from(this.equipment.entries()).map(([id, e]) => ({
                ownerId: id,
                slots: Array.from(e.slots.entries()),
                totalStats: Array.from(e.totalStats.entries()),
            })),
            learnedRecipes: Array.from(this.learnedRecipes.entries()).map(([id, recipes]) => ({
                entityId: id,
                recipes: Array.from(recipes),
            })),
        };
    }
    deserialize(snapshot) {
        this.containers.clear();
        this.equipment.clear();
        this.learnedRecipes.clear();
        for (const c of snapshot.containers) {
            this.containers.set(c.id, {
                ...c,
                currency: new Map(c.currency),
            });
        }
        for (const e of snapshot.equipment) {
            this.equipment.set(e.ownerId, {
                ownerId: e.ownerId,
                slots: new Map(e.slots),
                totalStats: new Map(e.totalStats),
            });
        }
        for (const r of snapshot.learnedRecipes) {
            this.learnedRecipes.set(r.entityId, new Set(r.recipes));
        }
    }
}
/* ═══════════════════════════════════════════════════════════════
   REACT INTEGRATION
══════════════════════════════════════════════════════════════════ */
const InventoryContext = React.createContext(null);
const InventoryProvider = ({ manager, children }) => {
    return React.createElement(InventoryContext.Provider, { value: manager }, children);
};
function useInventoryManager() {
    const ctx = React.useContext(InventoryContext);
    if (!ctx)
        throw new Error('useInventoryManager must be used within InventoryProvider');
    return ctx;
}
function useContainer(containerId) {
    const manager = useInventoryManager();
    const [container, setContainer] = React.useState(() => manager.getContainer(containerId));
    React.useEffect(() => {
        setContainer(manager.getContainer(containerId));
    }, [manager, containerId]);
    return container;
}
function useEquipment(ownerId) {
    const manager = useInventoryManager();
    const [equipment, setEquipment] = React.useState(() => manager.getEquipment(ownerId));
    React.useEffect(() => {
        setEquipment(manager.getEquipment(ownerId));
    }, [manager, ownerId]);
    return equipment;
}

export { InventoryManager, InventoryProvider, useContainer, useEquipment, useInventoryManager };
//# sourceMappingURL=InventorySystem.js.map
