/**
 * CraftingSystem — recipe lookup + craft execution with inventory checks.
 * GDD §11: Crafting
 */
class CraftingSystem {
    constructor(contentLoader) {
        this.loader         = contentLoader;
        this.playerCrafting = new Map();
    }

    getAllRecipes()          { return this.loader.getAllRecipes(); }
    getRecipe(id)            { return this.loader.getRecipe(id); }
    getRecipesByType(type)   { return this.loader.getRecipesByType(type); }
    getCraftingTabs()        { return this.loader.getCraftingTabs(); }

    initializePlayerData(userId) {
        if (this.playerCrafting.has(userId)) return this.playerCrafting.get(userId);
        const data = { skill: 1, experience: 0, knownRecipes: new Set(), totalCrafted: 0 };
        this.playerCrafting.set(userId, data);
        return data;
    }

    getPlayerCrafting(userId) { return this.initializePlayerData(userId); }

    /**
     * Check if player has all required materials in inventory.
     * Returns { canCraft: bool, missing: [{itemId, need, have}] }
     */
    checkMaterials(recipeId, playerInventory) {
        const recipe = this.getRecipe(recipeId);
        if (!recipe) return { canCraft: false, missing: [{ itemId: 'unknown', need: 1, have: 0 }] };

        const inputs = recipe.recipe?.inputs || recipe.inputs || {};
        const missing = [];

        for (const [itemId, qty] of Object.entries(inputs)) {
            const have = this._countItem(playerInventory, itemId);
            if (have < qty) {
                missing.push({ itemId, need: qty, have });
            }
        }

        return { canCraft: missing.length === 0, missing };
    }

    /**
     * Execute a craft: consume materials, add output item, return result.
     * Returns { success, output, xpGained, error? }
     */
    executeCraft(recipeId, playerData, userId) {
        const recipe = this.getRecipe(recipeId);
        if (!recipe) return { success: false, error: 'Recipe not found' };

        const inputs  = recipe.recipe?.inputs  || recipe.inputs  || {};
        const outputs = recipe.recipe?.output   || recipe.output  || {};
        const xpGain  = recipe.craft?.xp || recipe.xp || 10;

        const inventory = playerData.inventory || { items: [] };

        // Re-check materials server-side
        const check = this.checkMaterials(recipeId, inventory);
        if (!check.canCraft) {
            return { success: false, error: 'Missing materials', missing: check.missing };
        }

        // Consume inputs
        for (const [itemId, qty] of Object.entries(inputs)) {
            this._removeItems(inventory, itemId, qty);
        }

        // Add outputs
        const outputItems = [];
        for (const [itemId, qty] of Object.entries(outputs)) {
            const item = this._makeItem(itemId, qty);
            inventory.items.push(item);
            outputItems.push(item);
        }

        // Update crafting stats
        const pd = this.initializePlayerData(userId);
        pd.totalCrafted++;
        pd.experience += xpGain;
        const newSkill = this._calcSkillLevel(pd.experience);
        if (newSkill > pd.skill) pd.skill = newSkill;
        pd.knownRecipes.add(recipeId);

        // Persist crafting data back into playerData
        playerData.crafting = {
            ...(playerData.crafting || {}),
            skill: pd.skill,
            experience: pd.experience,
            totalCrafted: pd.totalCrafted,
        };

        this.recordCraft(userId, recipeId);

        return {
            success: true,
            output: outputItems,
            xpGained: xpGain,
            craftingLevel: pd.skill,
            craftingXp: pd.experience,
        };
    }

    recordCraft(userId, recipeId) {
        const pd = this.initializePlayerData(userId);
        pd.totalCrafted++;
        pd.knownRecipes.add(recipeId);
    }

    // ── Private helpers ──────────────────────────────────────────────────

    _countItem(inventory, itemId) {
        const items = (inventory && inventory.items) ? inventory.items : inventory || [];
        let total = 0;
        for (const it of items) {
            if (it && (it.id === itemId || it.itemId === itemId)) {
                total += (it.quantity || it.qty || 1);
            }
        }
        return total;
    }

    _removeItems(inventory, itemId, qty) {
        let remaining = qty;
        const items = inventory.items || [];
        for (let i = items.length - 1; i >= 0 && remaining > 0; i--) {
            const it = items[i];
            if (!it) continue;
            if (it.id === itemId || it.itemId === itemId) {
                const have = it.quantity || it.qty || 1;
                if (have <= remaining) {
                    remaining -= have;
                    items.splice(i, 1);
                } else {
                    it.quantity = have - remaining;
                    remaining = 0;
                }
            }
        }
    }

    _makeItem(itemId, qty) {
        return {
            id: itemId,
            itemId,
            quantity: qty,
            obtainedAt: Date.now(),
            source: 'crafting',
        };
    }

    _calcSkillLevel(xp) {
        // Every 200 XP = 1 crafting level, cap at 50
        return Math.min(50, Math.floor(xp / 200) + 1);
    }
}

module.exports = CraftingSystem;
