import Module from './Module.js';

/**
 * GameLoader - Discovers and manages game modules
 * Handles dynamic loading, compatibility scoring, and game lifecycle
 */
class GameLoader extends Module {
    constructor(name, dependencies, config = {}) {
        super(name, ['eventBus']);

        // Validate dependencies
        if (!dependencies.eventBus) {
            throw new Error('GameLoader requires EventBus dependency');
        }

        this._eventBus = dependencies.eventBus;
        this._config = config;

        // Game management
        this._games = new Map(); // gameId -> game info
        this._gameInstances = new Map(); // instanceId -> game instance
        this._currentContent = null;

        // Game discovery paths
        this._gamePaths = [
            '../games/FlashcardLearning.js',
            '../games/StoryReader.js',
            '../games/LetterDiscovery.js',
            '../games/QuizGame.js',
            '../games/ThematicQuestions.js',
            '../games/AdventureReader.js',
            '../games/WizardSpellCaster.js',
            '../games/TeamWizardBattle.js',
            '../games/WordStorm.js',
            '../games/WhackAMole.js',
            '../games/WordDiscovery.js',
            '../games/GrammarDiscovery.js',
            '../games/FillTheBlank.js',
            '../games/RiverRun.js',
            '../games/ChineseStudy.js',
            '../games/WhackAMoleHard.js',
            '../games/MarioEducational.js',
            '../games/SentenceInvaders.js'
            // All current games with Module architecture
        ];

        Object.seal(this);
    }

    async init() {
        this._validateNotDestroyed();

        // Set up event listeners
        this._eventBus.on('content:loaded', this._handleContentUpdate.bind(this), this.name);
        this._eventBus.on('game:launch-request', this._handleLaunchRequest.bind(this), this.name);
        this._eventBus.on('game:exit-request', this._handleExitRequest.bind(this), this.name);

        // Discover available games
        await this._discoverGames();

        this._setInitialized();
    }

    async destroy() {
        this._validateNotDestroyed();

        // Destroy all active game instances
        for (const [instanceId, gameInstance] of this._gameInstances) {
            try {
                await gameInstance.destroy();
            } catch (error) {
                console.warn(`Error destroying game instance ${instanceId}:`, error);
            }
        }

        this._gameInstances.clear();
        this._games.clear();

        this._setDestroyed();
    }

    /**
     * Get all discovered games with compatibility scores
     * @returns {Array} Array of game info objects
     */
    getAvailableGames() {
        this._validateInitialized();
        return Array.from(this._games.values());
    }

    /**
     * Get games compatible with current content
     * @param {number} minScore - Minimum compatibility score (0-1)
     * @returns {Array} Array of compatible games sorted by score
     */
    getCompatibleGames(minScore = 0.3) {
        this._validateInitialized();

        return this.getAvailableGames()
            .filter(game => game.compatibility.score >= minScore)
            .sort((a, b) => b.compatibility.score - a.compatibility.score);
    }

    /**
     * Launch a game instance
     * @param {string} gameId - ID of the game to launch
     * @param {Object} options - Launch options
     * @returns {Promise<string>} Instance ID
     */
    async launchGame(gameId, options = {}) {
        this._validateInitialized();

        const gameInfo = this._games.get(gameId);
        if (!gameInfo) {
            throw new Error(`Game not found: ${gameId}`);
        }

        // Check compatibility
        if (gameInfo.compatibility.score < 0.1) {
            throw new Error(`Game ${gameId} is not compatible with current content`);
        }

        try {
            // Create unique instance ID
            const instanceId = `${gameId}-${Date.now()}`;

            // Prepare game dependencies
            const gameDependencies = {
                eventBus: this._eventBus,
                content: this._currentContent,
                ...options.dependencies
            };

            // Register the game instance as a module with EventBus
            this._eventBus.registerModule({ name: instanceId });

            // Create game instance
            const gameInstance = new gameInfo.GameClass(instanceId, gameDependencies, {
                container: options.container,
                ...options.config
            });

            // Initialize the game
            await gameInstance.init();

            // Track the instance
            this._gameInstances.set(instanceId, gameInstance);

            // Emit game launched event
            this._eventBus.emit('game:launched', {
                gameId,
                instanceId,
                compatibility: gameInfo.compatibility
            }, this.name);

            return instanceId;

        } catch (error) {
            console.error(`Error launching game ${gameId}:`, error);
            throw error;
        }
    }

    /**
     * Exit a game instance
     * @param {string} instanceId - Instance ID to exit
     */
    async exitGame(instanceId) {
        this._validateInitialized();

        const gameInstance = this._gameInstances.get(instanceId);
        if (!gameInstance) {
            console.warn(`Game instance not found: ${instanceId}`);
            return;
        }

        try {
            await gameInstance.destroy();
            this._gameInstances.delete(instanceId);

            // Unregister the game instance from EventBus
            this._eventBus.unregisterModule(instanceId);

            this._eventBus.emit('game:exited', { instanceId }, this.name);

        } catch (error) {
            console.error(`Error exiting game ${instanceId}:`, error);
        }
    }

    // Private methods
    async _discoverGames() {
        console.log('🎮 Discovering available games...');

        for (const gamePath of this._gamePaths) {
            try {
                // Dynamically import the game module (resolve relative to current module)
                const gameModule = await import(gamePath);
                const GameClass = gameModule.default;

                if (!GameClass) {
                    console.warn(`No default export found in ${gamePath}`);
                    continue;
                }

                // Get game metadata
                const metadata = GameClass.getMetadata?.() || {
                    name: GameClass.name,
                    description: 'No description available',
                    difficulty: 'unknown'
                };

                // Calculate compatibility score
                const compatibility = this._calculateCompatibility(GameClass);

                // Store game info
                const gameInfo = {
                    id: GameClass.name.toLowerCase().replace(/game$/, ''),
                    GameClass,
                    metadata,
                    compatibility,
                    path: gamePath
                };

                this._games.set(gameInfo.id, gameInfo);
                console.log(`✅ Discovered game: ${metadata.name} (compatibility: ${compatibility.score.toFixed(2)})`);

            } catch (error) {
                console.warn(`Failed to load game from ${gamePath}:`, error.message);
            }
        }

        console.log(`🎮 Game discovery complete: ${this._games.size} games found`);
    }

    _calculateCompatibility(GameClass) {
        if (!this._currentContent) {
            return { score: 0, reason: 'No content loaded' };
        }

        // Use game's own compatibility function if available
        if (typeof GameClass.getCompatibilityScore === 'function') {
            const result = GameClass.getCompatibilityScore(this._currentContent);

            // Normalize different return formats
            if (typeof result === 'number') {
                // Format 2: Direct integer (0-100) -> Convert to decimal object
                return {
                    score: result / 100,
                    reason: `Compatibility score: ${result}%`,
                    requirements: ['content']
                };
            } else if (result && typeof result === 'object' && typeof result.score === 'number') {
                // Format 1: Object with decimal score (0-1) -> Use as-is
                return result;
            } else {
                // Invalid format -> Default to 0
                return { score: 0, reason: 'Invalid compatibility format' };
            }
        }

        // Default compatibility calculation
        const vocab = this._currentContent.vocabulary || {};
        const vocabCount = Object.keys(vocab).length;

        if (vocabCount < 5) {
            return { score: 0, reason: 'Insufficient vocabulary (need at least 5 words)' };
        }

        // Basic scoring based on vocabulary count
        const score = Math.min(vocabCount / 20, 1); // Full score at 20+ words

        return {
            score,
            reason: `${vocabCount} vocabulary words available`,
            requirements: ['vocabulary'],
            minWords: 5,
            optimalWords: 20
        };
    }

    _handleContentUpdate(event) {
        console.log('🔄 GameLoader: Content updated, recalculating compatibility scores');
        const structure = {
            hasContent: !!event.data.content,
            contentKeys: Object.keys(event.data.content || {}),
            hasVocabulary: !!event.data.content?.vocabulary,
            vocabularyCount: event.data.content?.vocabulary ? Object.keys(event.data.content.vocabulary).length : 0,
            hasTexts: !!event.data.content?.texts,
            hasSentences: !!event.data.content?.sentences
        };
        console.log('📦 GameLoader: event.data structure:', JSON.stringify(structure, null, 2));
        this._currentContent = event.data.content;

        // Recalculate compatibility scores for all games
        for (const [gameId, gameInfo] of this._games) {
            const oldScore = gameInfo.compatibility?.score || 0;
            gameInfo.compatibility = this._calculateCompatibility(gameInfo.GameClass);
            const newScore = gameInfo.compatibility?.score || 0;
            console.log(`🎯 ${gameId}: ${oldScore.toFixed(2)} → ${newScore.toFixed(2)}`);
        }

        this._eventBus.emit('games:compatibility-updated', {
            gamesCount: this._games.size,
            compatibleCount: this.getCompatibleGames().length
        }, this.name);

        console.log('✅ Compatibility scores updated');
    }

    _handleLaunchRequest(event) {
        const { gameId, options } = event.data;
        this.launchGame(gameId, options).catch(error => {
            this._eventBus.emit('game:launch-error', { gameId, error: error.message }, this.name);
        });
    }

    _handleExitRequest(event) {
        const { instanceId } = event.data;
        this.exitGame(instanceId);
    }
}

export default GameLoader;