/**
 * Galaxy Strike Online - Client Crafting System
 * Recipe definitions are loaded from the server; this file handles
 * local crafting logic, requirement checking, and UI rendering.
 */

class CraftingSystem extends BaseSystem {
    constructor(gameEngine) {
        super(gameEngine);

        this.recipes = new Map();        // recipeId -> recipe object
        this.currentCategory = 'weapons';
        this.selectedRecipe  = null;

        this._loaded  = false;
        this._loading = false;
    }

    // ------------------------------------------------------------------ //
    // Initialisation — request recipes from the server
    // ------------------------------------------------------------------ //
    async initialize() {
        if (this._loaded || this._loading) return;
        this._loading = true;

        console.log('[CRAFTING SYSTEM] Requesting recipes from server');

        if (!window.game?.socket) {
            console.warn('[CRAFTING SYSTEM] No socket — recipes will load when connected');
            this._loading = false;
            return;
        }

        try {
            const recipes = await this._fetchRecipesFromServer();
            this._applyServerRecipes(recipes);
            this._loaded = true;
            console.log(`[CRAFTING SYSTEM] Loaded ${this.recipes.size} recipes from server`);
        } catch (err) {
            console.error('[CRAFTING SYSTEM] Failed to load recipes from server:', err);
        } finally {
            this._loading = false;
        }
    }

    _fetchRecipesFromServer() {
        return new Promise((resolve, reject) => {
            const socket = window.game.socket;

            const timeout = setTimeout(() => {
                socket.off('recipes_data', handler);
                reject(new Error('Recipe data request timed out'));
            }, 10000);

            const handler = (data) => {
                clearTimeout(timeout);
                socket.off('recipes_data', handler);
                if (data && (Array.isArray(data) || typeof data === 'object')) {
                    resolve(data);
                } else {
                    reject(new Error('Invalid recipe data from server'));
                }
            };

            socket.on('recipes_data', handler);
            socket.emit('get_recipes');
        });
    }

    _applyServerRecipes(serverRecipes) {
        this.recipes.clear();

        // Server may return array or object keyed by id
        const asList = Array.isArray(serverRecipes)
            ? serverRecipes
            : Object.values(serverRecipes);

        for (const recipe of asList) {
            if (!recipe.id) continue;

            // Normalise materials: server uses { itemId: qty } objects, client expects array
            let materials = recipe.materials;
            if (materials && !Array.isArray(materials)) {
                materials = Object.entries(materials).map(([id, quantity]) => ({ id, quantity }));
            }

            // Normalise results similarly
            let results = recipe.results;
            if (results && !Array.isArray(results)) {
                results = Object.entries(results)
                    .filter(([k]) => k !== 'experience')
                    .map(([id, quantity]) => ({ id, quantity }));
            }

            this.recipes.set(recipe.id, {
                ...recipe,
                materials: materials || [],
                results:   results   || [],
                category:  recipe.type || recipe.category || 'items',
                unlocked:  false  // will be resolved by checkRecipeUnlocks()
            });
        }
    }

    // ------------------------------------------------------------------ //
    // Runtime
    // ------------------------------------------------------------------ //
    addRecipe(id, recipe) {
        recipe.id = id;
        recipe.unlocked = false;
        this.recipes.set(id, recipe);
    }

    update(deltaTime) {
        this.checkRecipeUnlocks();
    }

    checkRecipeUnlocks() {
        const skillSystem = this.game.systems.skillSystem;
        if (!skillSystem) return;

        for (const [id, recipe] of this.recipes) {
            if (recipe.unlocked) continue;

            let canUnlock = true;
            if (recipe.requirements) {
                for (const [skillName, requiredLevel] of Object.entries(recipe.requirements)) {
                    if (skillSystem.getSkillLevel(skillName) < requiredLevel) {
                        canUnlock = false;
                        break;
                    }
                }
            }

            if (canUnlock) {
                recipe.unlocked = true;
                console.log(`[CRAFTING] Recipe unlocked: ${recipe.name}`);
            }
        }
    }

    getRecipesByCategory(category) {
        return Array.from(this.recipes.values())
            .filter(r => r.category === category || r.type === category);
    }

    canCraftRecipe(recipeId) {
        const recipe      = this.recipes.get(recipeId);
        const skillSystem = this.game.systems.skillSystem;
        const inventory   = this.game.systems.inventory;
        if (!recipe) return false;

        if (recipe.requirements && skillSystem) {
            for (const [skillName, requiredLevel] of Object.entries(recipe.requirements)) {
                if (skillSystem.getSkillLevel(skillName) < requiredLevel) return false;
            }
        }

        if (recipe.materials && inventory) {
            for (const mat of recipe.materials) {
                if (!inventory.hasItem(mat.id, mat.quantity)) return false;
            }
        }

        return true;
    }

    getMissingMaterials(recipeId) {
        const recipe    = this.recipes.get(recipeId);
        const inventory = this.game.systems.inventory;
        if (!recipe?.materials) return [];

        const missing = [];
        for (const mat of recipe.materials) {
            let current = 0;
            if (inventory?.getItemCount) {
                try { current = inventory.getItemCount(mat.id) || 0; } catch (_) {}
            }
            const required = mat.quantity || 0;
            if (current < required) {
                missing.push({ id: mat.id, required, current, missing: required - current });
            }
        }
        return missing;
    }

    async craftRecipe(recipeId) {
        const recipe = this.recipes.get(recipeId);
        if (!recipe || !this.canCraftRecipe(recipeId)) return false;

        console.log(`[CRAFTING] Crafting: ${recipe.name}`);

        if (recipe.materials) {
            for (const mat of recipe.materials) {
                this.game.systems.inventory.removeItem(mat.id, mat.quantity);
            }
        }

        if (recipe.experience && this.game.systems.skillSystem) {
            this.game.systems.skillSystem.awardCraftingExperience(recipe.experience);
        }

        await new Promise(resolve => setTimeout(resolve, recipe.craftingTime || 3000));

        if (recipe.results) {
            for (const result of recipe.results) {
                this.game.systems.inventory.addItem(result.id, result.quantity);
            }
        }

        if (this.game.systems.questSystem) {
            this.game.systems.questSystem.onItemCrafted?.();
        }

        console.log(`[CRAFTING] Done: ${recipe.name}`);
        return true;
    }

    selectRecipe(recipeId) {
        this.selectedRecipe = this.recipes.get(recipeId);
        return this.selectedRecipe;
    }

    getSelectedRecipe() { return this.selectedRecipe; }

    // ------------------------------------------------------------------ //
    // UI
    // ------------------------------------------------------------------ //
    updateUI() {
        this.updateRecipeList();
        this.updateCraftingDetails();
        this.updateCraftingInfo();
    }

    updateRecipeList() {
        const listEl = document.getElementById('recipeList');
        if (!listEl) return;

        if (!this._loaded) {
            listEl.innerHTML = '<div style="text-align:center;padding:2rem;color:var(--text-secondary)"><i class="fas fa-spinner fa-spin"></i><p>Loading recipes from server...</p></div>';
            return;
        }

        const recipes = this.getRecipesByCategory(this.currentCategory);
        listEl.innerHTML = '';

        if (recipes.length === 0) {
            listEl.innerHTML = '<p class="no-recipes">No recipes available in this category</p>';
            return;
        }

        recipes.forEach(recipe => {
            const el = document.createElement('div');
            el.className = 'recipe-item';
            el.dataset.recipeId = recipe.id;

            const canCraft       = this.canCraftRecipe(recipe.id);
            const missingMats    = this.getMissingMaterials(recipe.id);
            const skillSystem    = this.game.systems.skillSystem;
            let skillsMet = true;

            if (recipe.requirements && skillSystem) {
                for (const [skill, level] of Object.entries(recipe.requirements)) {
                    if (skillSystem.getSkillLevel(skill) < level) { skillsMet = false; break; }
                }
            }

            if (!skillsMet)         el.classList.add('locked');
            else if (!canCraft)     el.classList.add('missing-materials');
            else                    el.classList.add('can-craft');

            const reqText = recipe.requirements
                ? Object.entries(recipe.requirements).map(([s, l]) => `${s}: ${l}`).join(', ')
                : 'None';

            const matsHtml = recipe.materials.map(mat => {
                const mis   = missingMats.find(m => m.id === mat.id);
                const cur   = mis ? mis.current : (this.game.systems.inventory?.getItemCount(mat.id) || 0);
                const cls   = mis ? 'material-item missing' : 'material-item';
                return `<div class="${cls}">
                    <span class="material-name">${mat.id}</span>
                    <span class="material-quantity">${cur}/${mat.quantity}</span>
                </div>`;
            }).join('');

            el.innerHTML = `
                <div class="recipe-header">
                    <h4>${recipe.name}</h4>
                    <span class="recipe-level">Level ${reqText}</span>
                </div>
                <div class="recipe-description">${recipe.description || ''}</div>
                <div class="recipe-materials">${matsHtml}</div>
                ${missingMats.length > 0 ? `
                    <div class="missing-materials-text">
                        <i class="fas fa-exclamation-triangle"></i>
                        Missing: ${missingMats.map(m => `${m.missing}x ${m.id}`).join(', ')}
                    </div>` : ''}
                <div class="recipe-time">
                    <i class="fas fa-clock"></i>
                    <span>${(recipe.craftingTime || 0) / 1000}s</span>
                </div>
            `;

            el.addEventListener('click', () => {
                this.selectRecipe(recipe.id);
                this.updateCraftingDetails();
            });

            listEl.appendChild(el);
        });
    }

    updateCraftingDetails() {
        const detailsEl = document.getElementById('craftingDetails');
        if (!detailsEl) return;

        if (!this.selectedRecipe) {
            detailsEl.innerHTML = `
                <div class="selected-recipe">
                    <h3>Select a Recipe</h3>
                    <p>Choose a recipe from the list to see details and craft items.</p>
                </div>`;
            return;
        }

        const recipe   = this.selectedRecipe;
        const canCraft = this.canCraftRecipe(recipe.id);

        detailsEl.innerHTML = `
            <div class="selected-recipe">
                <h3>${recipe.name}</h3>
                <p class="recipe-description">${recipe.description || ''}</p>
                <div class="recipe-requirements">
                    <h4>Requirements:</h4>
                    ${recipe.requirements
                        ? Object.entries(recipe.requirements).map(([s, l]) =>
                            `<div class="requirement-item">
                                <span class="skill-name">${s}</span>
                                <span class="skill-level">Level ${l}</span>
                            </div>`).join('')
                        : '<p>No special requirements</p>'}
                </div>
                <div class="recipe-materials-needed">
                    <h4>Materials Needed:</h4>
                    ${recipe.materials.map(mat =>
                        `<div class="material-needed">
                            <span class="material-name">${mat.id}</span>
                            <span class="material-needed">x${mat.quantity}</span>
                            <span class="material-have">Have: ${this.game.systems.inventory?.getItemCount(mat.id) || 0}</span>
                        </div>`).join('')}
                </div>
                <div class="recipe-results">
                    <h4>Results:</h4>
                    ${recipe.results.map(r =>
                        `<div class="result-item">
                            <span class="result-name">${r.id}</span>
                            <span class="result-quantity">x${r.quantity}</span>
                        </div>`).join('')}
                </div>
                <div class="recipe-info">
                    <div class="experience-reward">
                        <i class="fas fa-star"></i>
                        <span>${recipe.experience || 0} XP</span>
                    </div>
                    <div class="crafting-time">
                        <i class="fas fa-clock"></i>
                        <span>${(recipe.craftingTime || 0) / 1000} seconds</span>
                    </div>
                </div>
                <button class="btn btn-primary craft-btn ${canCraft ? '' : 'disabled'}"
                        ${canCraft ? `onclick="window.game.systems.crafting.craftRecipe('${recipe.id}')"` : 'disabled'}>
                    ${canCraft ? 'Craft Item' : 'Cannot Craft'}
                </button>
            </div>`;
    }

    updateCraftingInfo() {
        const skillSystem = this.game.systems.skillSystem;
        if (!skillSystem) return;

        const craftingLevel = skillSystem.getSkillLevel('crafting');
        const craftingExp   = skillSystem.getSkillExperience('crafting');
        const expNeeded     = skillSystem.getExperienceNeeded('crafting');

        const levelEl = document.getElementById('craftingLevel');
        const expEl   = document.getElementById('craftingExp');
        if (levelEl) levelEl.textContent = craftingLevel;
        if (expEl)   expEl.textContent   = `${craftingExp}/${expNeeded}`;
    }

    switchCategory(category) {
        this.currentCategory = category;
        this.selectedRecipe  = null;
        if (window.smartSaveManager?.isMultiplayer || this.game?.isRunning) {
            this.updateUI();
        }
    }
}

// Export for use in GameEngine
if (typeof module !== 'undefined' && module.exports) {
    module.exports = CraftingSystem;
}
