/**
 * IntelligentSequencer - Smart exercise sequencing with performance tracking
 * Creates intelligent, non-repetitive exercise proposals based on user performance
 */

import Module from './Module.js';

class IntelligentSequencer extends Module {
    constructor(name, dependencies, config = {}) {
        super(name, ['eventBus']);

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

        this._eventBus = dependencies.eventBus;

        // Performance tracking
        this._performanceHistory = new Map(); // type -> performance data
        this._exerciseHistory = []; // chronological exercise history
        this._sessionStats = {
            startTime: null,
            exerciseCount: 0,
            totalTime: 0,
            averageAccuracy: 0,
            currentStreak: 0
        };

        // Algorithm configuration
        this._config = {
            maxHistorySize: config.maxHistorySize || 50,
            repetitionAvoidanceWindow: config.repetitionAvoidanceWindow || 5,
            difficultyAdaptationThreshold: config.difficultyAdaptationThreshold || 0.8,
            varietyWeight: config.varietyWeight || 0.3,
            performanceWeight: config.performanceWeight || 0.4,
            freshnessWeight: config.freshnessWeight || 0.3,
            minSessionLength: config.minSessionLength || 3,
            maxSessionLength: config.maxSessionLength || 15,
            ...config
        };

        // Available exercise types and difficulties
        this._exerciseTypes = ['text', 'reading', 'phrase', 'audio', 'grammar'];
        this._difficulties = ['easy', 'medium', 'hard'];

        // Current session state
        this._currentSession = null;
        this._isGuiding = false;

        Object.seal(this);
    }

    async init() {
        this._validateNotDestroyed();

        // Listen for exercise completion events
        this._eventBus.on('drs:completed', this._handleExerciseCompleted.bind(this), this.name);
        this._eventBus.on('drs:step-completed', this._handleStepCompleted.bind(this), this.name);

        // Load saved performance data if available
        this._loadPerformanceData();

        this._setInitialized();
        console.log('🧠 IntelligentSequencer initialized with smart algorithm');
    }

    async destroy() {
        this._validateNotDestroyed();

        // Save performance data before destruction
        this._savePerformanceData();

        this._setDestroyed();
    }

    /**
     * Start intelligent guided session
     */
    startGuidedSession(options = {}) {
        this._validateInitialized();

        const session = {
            id: `session_${Date.now()}`,
            startTime: Date.now(),
            bookId: options.bookId || 'sbs',
            chapterId: options.chapterId || 'level-1-2',
            targetLength: Math.min(
                Math.max(options.targetLength || 8, this._config.minSessionLength),
                this._config.maxSessionLength
            ),
            completed: 0,
            exercises: [],
            currentExercise: null
        };

        this._currentSession = session;
        this._isGuiding = true;

        console.log('🚀 Starting guided session:', session.id);

        // Emit session start event
        this._eventBus.emit('sequencer:session-started', {
            sessionId: session.id,
            targetLength: session.targetLength
        }, this.name);

        return session;
    }

    /**
     * Get next intelligent exercise recommendation
     */
    async getNextExercise() {
        this._validateInitialized();

        if (!this._isGuiding || !this._currentSession) {
            return null;
        }

        const session = this._currentSession;

        // Check if session is complete
        if (session.completed >= session.targetLength) {
            this._completeSession();
            return null;
        }

        try {
            // Calculate scores for each exercise type/difficulty combination
            const candidates = await this._generateCandidates();

            if (candidates.length === 0) {
                console.warn('⚠️ No available exercise candidates found', {
                    sessionProgress: `${session.completed}/${session.targetLength}`,
                    exerciseTypes: this._exerciseTypes,
                    bookId: session.bookId,
                    chapterId: session.chapterId
                });
                this._completeSession();
                return null;
            }

            // Calculate scores for all candidates (async)
            const scoredCandidates = await Promise.all(
                candidates.map(async candidate => ({
                    ...candidate,
                    score: await this._calculateExerciseScore(candidate)
                }))
            );

            // Sort by score (higher is better)
            scoredCandidates.sort((a, b) => b.score - a.score);

            // Select the best candidate with some randomness for variety
            const topCandidates = scoredCandidates.slice(0, Math.min(3, scoredCandidates.length));
            const selectedCandidate = topCandidates[Math.floor(Math.random() * topCandidates.length)];

            // Create exercise recommendation
            const exercise = {
                type: selectedCandidate.type,
                difficulty: selectedCandidate.difficulty,
                bookId: session.bookId,
                chapterId: session.chapterId,
                sessionPosition: session.completed + 1,
                totalInSession: session.targetLength,
                reasoning: selectedCandidate.reasoning || 'Intelligent selection based on performance and variety'
            };

            session.currentExercise = exercise;

            console.log('🎯 Next exercise recommendation:', {
                type: exercise.type,
                difficulty: exercise.difficulty,
                position: `${exercise.sessionPosition}/${exercise.totalInSession}`,
                score: selectedCandidate.score.toFixed(2),
                reasoning: exercise.reasoning,
                availableCandidates: candidates.length
            });

            return exercise;

        } catch (error) {
            console.error('❌ Error generating next exercise:', error);
            return null;
        }
    }

    /**
     * Record exercise completion and update performance
     */
    recordExerciseCompletion(exerciseData, performanceData) {
        this._validateInitialized();

        const completionRecord = {
            timestamp: Date.now(),
            type: exerciseData.type,
            difficulty: exerciseData.difficulty,
            bookId: exerciseData.bookId,
            chapterId: exerciseData.chapterId,
            performance: {
                timeSpent: performanceData.timeSpent || 0,
                accuracy: performanceData.accuracy || 0,
                hintsUsed: performanceData.hintsUsed || 0,
                attempts: performanceData.attempts || 1,
                completed: performanceData.completed !== false
            }
        };

        // Update exercise history
        this._exerciseHistory.push(completionRecord);
        if (this._exerciseHistory.length > this._config.maxHistorySize) {
            this._exerciseHistory.shift();
        }

        // Update performance tracking
        this._updatePerformanceTracking(completionRecord);

        // Update current session
        if (this._currentSession && this._isGuiding) {
            this._currentSession.exercises.push(completionRecord);
            this._currentSession.completed++;
        }

        console.log('📊 Exercise recorded:', {
            type: completionRecord.type,
            difficulty: completionRecord.difficulty,
            accuracy: completionRecord.performance.accuracy,
            timeSpent: Math.round(completionRecord.performance.timeSpent / 1000) + 's'
        });
    }

    /**
     * Get performance insights and recommendations
     */
    getPerformanceInsights() {
        this._validateInitialized();

        const insights = {
            overallStats: this._calculateOverallStats(),
            typePerformance: this._getTypePerformance(),
            difficultyProgress: this._getDifficultyProgress(),
            recommendations: this._generateRecommendations(),
            recentTrends: this._getRecentTrends()
        };

        return insights;
    }

    /**
     * Check if currently in guided session
     */
    isGuiding() {
        return this._isGuiding && this._currentSession !== null;
    }

    /**
     * Stop current guided session
     */
    stopGuidedSession() {
        if (!this._isGuiding || !this._currentSession) {
            return;
        }

        this._completeSession();
    }

    // Private methods

    async _generateCandidates() {
        const candidates = [];

        // Check resource availability for current session
        const session = this._currentSession;
        if (!session) return candidates;

        const { bookId, chapterId } = session;

        for (const type of this._exerciseTypes) {
            for (const difficulty of this._difficulties) {
                // Check if this type/difficulty combination has available content
                const hasContent = await this._checkContentAvailability(type, bookId, chapterId);

                if (hasContent) {
                    candidates.push({
                        type,
                        difficulty,
                        reasoning: `${type} exercise at ${difficulty} level using real content from ${chapterId}`
                    });
                } else {
                    console.log(`⚠️ Skipping ${type}/${difficulty} - no content available for ${chapterId}`);
                }
            }
        }

        console.log('📊 Generated candidates:', {
            total: candidates.length,
            types: candidates.map(c => `${c.type}/${c.difficulty}`).join(', ')
        });

        return candidates;
    }

    /**
     * Check if content is available for a specific exercise type
     */
    async _checkContentAvailability(exerciseType, bookId, chapterId) {
        try {
            const contentPath = `/content/chapters/${chapterId || bookId}.json`;
            const response = await fetch(contentPath);

            if (!response.ok) {
                console.warn(`❌ Content not available: ${contentPath}`);
                return false;
            }

            const content = await response.json();

            // Check based on exercise type requirements
            switch (exerciseType) {
                case 'text':
                case 'audio':
                    // Text and audio need vocabulary
                    return content.vocabulary && Object.keys(content.vocabulary).length > 3;

                case 'image':
                    // For now, disable image exercises as we don't have real images
                    console.log('⚠️ Image exercises disabled - no image resources available');
                    return false;

                case 'reading':
                    // Reading needs predefined exercises or content with questions
                    return this._hasReadingContent(content);

                case 'phrase':
                    // Phrase comprehension needs phrases object with content
                    return content.phrases && Object.keys(content.phrases).length > 0;

                case 'grammar':
                    // Grammar needs varied word types
                    if (!content.vocabulary) return false;
                    const vocab = Object.entries(content.vocabulary);
                    return vocab.length > 5; // Need enough variety

                default:
                    return false;
            }

        } catch (error) {
            console.warn(`❌ Error checking content availability:`, error);
            return false;
        }
    }

    _hasReadingContent(content) {
        // Check if there are predefined reading exercises in JSON
        if (content.exercises) {
            for (const [key, exercise] of Object.entries(content.exercises)) {
                if (key.includes('reading') || key.includes('comprehension') ||
                    exercise.type === 'reading' || exercise.type === 'comprehension') {
                    return true;
                }

                // Check if exercise has passages/texts/stories with questions
                if ((exercise.passages && exercise.passages.some(p => p.questions)) ||
                    (exercise.texts && exercise.texts.some(t => t.questions)) ||
                    (exercise.stories && exercise.stories.some(s => s.questions))) {
                    return true;
                }
            }
        }

        // Check if stories have questions
        if (content.stories && content.stories.some(story => story.questions && story.questions.length > 0)) {
            return true;
        }

        // Check if texts have questions
        if (content.texts && content.texts.some(text => text.questions && text.questions.length > 0)) {
            return true;
        }

        // Check if dialogs have questions
        if (content.dialogs) {
            const dialogsWithQuestions = Object.values(content.dialogs).some(dialog =>
                dialog.questions && dialog.questions.length > 0
            );
            if (dialogsWithQuestions) {
                return true;
            }
        }

        // No reading content with questions found
        console.log(`⚠️ No reading content with questions found for this chapter`);
        return false;
    }

    async _calculateExerciseScore(candidate) {
        // Calculate variety score (avoid recent repetition)
        const varietyScore = this._calculateVarietyScore(candidate);

        // Calculate performance-based score (adaptive difficulty)
        const performanceScore = this._calculatePerformanceScore(candidate);

        // Calculate freshness score (prefer less practiced combinations)
        const freshnessScore = this._calculateFreshnessScore(candidate);

        // NEW: Calculate content abundance bonus (prefer types with more content)
        const abundanceBonus = await this._calculateContentAbundanceBonus(candidate.type);

        // Weighted combination with abundance bonus
        const totalScore = (
            varietyScore * this._config.varietyWeight +
            performanceScore * this._config.performanceWeight +
            freshnessScore * this._config.freshnessWeight
        ) + abundanceBonus; // Add bonus directly to total

        return totalScore;
    }

    _calculateVarietyScore(candidate) {
        // Check recent exercises for repetition
        const recentWindow = this._exerciseHistory.slice(-this._config.repetitionAvoidanceWindow);
        const recentTypes = recentWindow.map(ex => ex.type);
        const recentDifficulties = recentWindow.map(ex => ex.difficulty);
        const recentCombos = recentWindow.map(ex => `${ex.type}_${ex.difficulty}`);

        let varietyScore = 1.0;

        // Penalize if type was used recently
        const typeFreq = recentTypes.filter(t => t === candidate.type).length;
        varietyScore -= (typeFreq * 0.2);

        // Penalize if difficulty was used recently
        const difficultyFreq = recentDifficulties.filter(d => d === candidate.difficulty).length;
        varietyScore -= (difficultyFreq * 0.1);

        // Heavy penalty if exact combination was used very recently
        const comboKey = `${candidate.type}_${candidate.difficulty}`;
        const comboFreq = recentCombos.filter(c => c === comboKey).length;
        varietyScore -= (comboFreq * 0.4);

        return Math.max(varietyScore, 0);
    }

    _calculatePerformanceScore(candidate) {
        const typePerf = this._performanceHistory.get(candidate.type);

        if (!typePerf || typePerf.attempts === 0) {
            return 0.5; // Neutral score for untested areas
        }

        const avgAccuracy = typePerf.totalAccuracy / typePerf.attempts;
        const avgTime = typePerf.totalTime / typePerf.attempts;

        // Adapt difficulty based on performance
        let difficultyFit = 0.5;

        if (avgAccuracy > this._config.difficultyAdaptationThreshold) {
            // Good performance, prefer harder exercises
            if (candidate.difficulty === 'hard') difficultyFit = 0.9;
            else if (candidate.difficulty === 'medium') difficultyFit = 0.6;
            else difficultyFit = 0.3;
        } else if (avgAccuracy < 0.6) {
            // Poor performance, prefer easier exercises
            if (candidate.difficulty === 'easy') difficultyFit = 0.9;
            else if (candidate.difficulty === 'medium') difficultyFit = 0.6;
            else difficultyFit = 0.3;
        } else {
            // Moderate performance, prefer medium difficulty
            if (candidate.difficulty === 'medium') difficultyFit = 0.9;
            else difficultyFit = 0.7;
        }

        return difficultyFit;
    }

    _calculateFreshnessScore(candidate) {
        const comboKey = `${candidate.type}_${candidate.difficulty}`;

        // Count how many times this combination has been practiced
        const comboCount = this._exerciseHistory.filter(ex =>
            ex.type === candidate.type && ex.difficulty === candidate.difficulty
        ).length;

        // Prefer less practiced combinations
        return Math.max(1.0 - (comboCount * 0.1), 0.1);
    }

    async _calculateContentAbundanceBonus(exerciseType) {
        // Give bonus to exercise types with MORE available content
        // This makes phrase (53 items) more likely to appear than text (3 items)

        const session = this._currentSession;
        if (!session) return 0;

        try {
            const contentPath = `/content/chapters/${session.chapterId || session.bookId}.json`;
            const response = await fetch(contentPath);

            if (!response.ok) return 0;

            const content = await response.json();
            let itemCount = 0;

            // Count available items for this exercise type
            switch (exerciseType) {
                case 'phrase':
                    itemCount = content.phrases ? Object.keys(content.phrases).length : 0;
                    break;
                case 'text':
                    itemCount = content.texts ? content.texts.length : 0;
                    break;
                case 'reading':
                    // Count texts + dialogs with questions
                    const textsWithQ = content.texts ? content.texts.filter(t => t.questions?.length > 0).length : 0;
                    const dialogsWithQ = content.dialogs ? Object.values(content.dialogs).filter(d => d.questions?.length > 0).length : 0;
                    itemCount = textsWithQ + dialogsWithQ;
                    break;
                case 'audio':
                    // Count dialogs
                    itemCount = content.dialogs ? Object.keys(content.dialogs).length : 0;
                    break;
                case 'grammar':
                    itemCount = content.grammar ? Object.keys(content.grammar).length : 0;
                    break;
                default:
                    itemCount = 0;
            }

            // Calculate bonus based on item count
            // 50+ items → 0.5 bonus (HUGE boost)
            // 20-49 items → 0.3 bonus (big boost)
            // 10-19 items → 0.2 bonus (moderate boost)
            // 5-9 items → 0.1 bonus (small boost)
            // <5 items → 0 bonus

            if (itemCount >= 50) {
                console.log(`📊 Content abundance bonus for ${exerciseType}: 0.5 (${itemCount} items)`);
                return 0.5;
            } else if (itemCount >= 20) {
                console.log(`📊 Content abundance bonus for ${exerciseType}: 0.3 (${itemCount} items)`);
                return 0.3;
            } else if (itemCount >= 10) {
                console.log(`📊 Content abundance bonus for ${exerciseType}: 0.2 (${itemCount} items)`);
                return 0.2;
            } else if (itemCount >= 5) {
                console.log(`📊 Content abundance bonus for ${exerciseType}: 0.1 (${itemCount} items)`);
                return 0.1;
            }

            return 0;

        } catch (error) {
            console.warn(`⚠️ Error calculating content abundance:`, error);
            return 0;
        }
    }

    _updatePerformanceTracking(record) {
        const type = record.type;

        if (!this._performanceHistory.has(type)) {
            this._performanceHistory.set(type, {
                attempts: 0,
                totalAccuracy: 0,
                totalTime: 0,
                lastPracticed: 0,
                bestAccuracy: 0,
                averageTime: 0
            });
        }

        const typeData = this._performanceHistory.get(type);
        typeData.attempts++;
        typeData.totalAccuracy += record.performance.accuracy;
        typeData.totalTime += record.performance.timeSpent;
        typeData.lastPracticed = record.timestamp;
        typeData.bestAccuracy = Math.max(typeData.bestAccuracy, record.performance.accuracy);
        typeData.averageTime = typeData.totalTime / typeData.attempts;
    }

    _calculateOverallStats() {
        if (this._exerciseHistory.length === 0) {
            return {
                totalExercises: 0,
                averageAccuracy: 0,
                totalTime: 0,
                completionRate: 0
            };
        }

        const total = this._exerciseHistory.length;
        const totalAccuracy = this._exerciseHistory.reduce((sum, ex) => sum + ex.performance.accuracy, 0);
        const totalTime = this._exerciseHistory.reduce((sum, ex) => sum + ex.performance.timeSpent, 0);
        const completed = this._exerciseHistory.filter(ex => ex.performance.completed).length;

        return {
            totalExercises: total,
            averageAccuracy: totalAccuracy / total,
            totalTime,
            completionRate: completed / total
        };
    }

    _getTypePerformance() {
        const typePerf = {};

        for (const [type, data] of this._performanceHistory.entries()) {
            typePerf[type] = {
                averageAccuracy: data.totalAccuracy / data.attempts,
                averageTime: data.averageTime,
                attempts: data.attempts,
                bestAccuracy: data.bestAccuracy,
                lastPracticed: data.lastPracticed
            };
        }

        return typePerf;
    }

    _getDifficultyProgress() {
        const difficultyStats = {
            easy: { attempts: 0, accuracy: 0 },
            medium: { attempts: 0, accuracy: 0 },
            hard: { attempts: 0, accuracy: 0 }
        };

        for (const exercise of this._exerciseHistory) {
            const diff = exercise.difficulty;
            if (difficultyStats[diff]) {
                difficultyStats[diff].attempts++;
                difficultyStats[diff].accuracy += exercise.performance.accuracy;
            }
        }

        // Calculate averages
        for (const diff of Object.keys(difficultyStats)) {
            const stats = difficultyStats[diff];
            if (stats.attempts > 0) {
                stats.averageAccuracy = stats.accuracy / stats.attempts;
            }
        }

        return difficultyStats;
    }

    _generateRecommendations() {
        const recommendations = [];
        const typePerf = this._getTypePerformance();

        // Identify weak areas
        for (const [type, perf] of Object.entries(typePerf)) {
            if (perf.averageAccuracy < 0.7 && perf.attempts >= 2) {
                recommendations.push({
                    type: 'improvement',
                    message: `Consider practicing more ${type} exercises to improve accuracy`,
                    priority: 'medium',
                    targetType: type
                });
            }
        }

        // Suggest variety
        const recentTypes = this._exerciseHistory.slice(-10).map(ex => ex.type);
        const typeDistribution = {};
        for (const type of recentTypes) {
            typeDistribution[type] = (typeDistribution[type] || 0) + 1;
        }

        const overusedType = Object.entries(typeDistribution).find(([_, count]) => count > 5);
        if (overusedType) {
            recommendations.push({
                type: 'variety',
                message: `Try mixing in other exercise types - you've done a lot of ${overusedType[0]} recently`,
                priority: 'low'
            });
        }

        return recommendations;
    }

    _getRecentTrends() {
        if (this._exerciseHistory.length < 5) {
            return { trend: 'insufficient_data' };
        }

        const recent = this._exerciseHistory.slice(-5);
        const accuracies = recent.map(ex => ex.performance.accuracy);

        // Simple trend calculation
        const firstHalf = accuracies.slice(0, Math.floor(accuracies.length / 2));
        const secondHalf = accuracies.slice(Math.floor(accuracies.length / 2));

        const firstAvg = firstHalf.reduce((a, b) => a + b, 0) / firstHalf.length;
        const secondAvg = secondHalf.reduce((a, b) => a + b, 0) / secondHalf.length;

        let trend = 'stable';
        if (secondAvg > firstAvg + 0.1) trend = 'improving';
        else if (secondAvg < firstAvg - 0.1) trend = 'declining';

        return {
            trend,
            recentAccuracy: secondAvg,
            change: secondAvg - firstAvg
        };
    }

    _completeSession() {
        if (!this._currentSession) return;

        const session = this._currentSession;
        const sessionTime = Date.now() - session.startTime;

        console.log('🎉 Guided session completed:', {
            exercises: session.completed,
            duration: Math.round(sessionTime / 1000) + 's',
            sessionId: session.id
        });

        // Emit session completion
        this._eventBus.emit('sequencer:session-completed', {
            sessionId: session.id,
            exercisesCompleted: session.completed,
            duration: sessionTime,
            exercises: session.exercises
        }, this.name);

        this._currentSession = null;
        this._isGuiding = false;
    }

    _handleExerciseCompleted(event) {
        if (!this.isGuiding()) return;

        const data = event.data;
        this.recordExerciseCompletion(
            {
                type: data.exerciseType || 'text',
                difficulty: data.difficulty || 'medium',
                bookId: data.bookId,
                chapterId: data.chapterId
            },
            {
                timeSpent: data.stats?.timeSpent || 0,
                accuracy: data.stats?.accuracy || 0.8,
                hintsUsed: data.stats?.hintsUsed || 0,
                completed: true
            }
        );
    }

    _handleStepCompleted(event) {
        // Could track individual step performance here
        console.log('📊 Step completed in guided session:', event.data);
    }

    _loadPerformanceData() {
        try {
            const saved = localStorage.getItem('intelligentSequencer_performance');
            if (saved) {
                const data = JSON.parse(saved);
                this._performanceHistory = new Map(data.performanceHistory || []);
                this._exerciseHistory = data.exerciseHistory || [];
                console.log('📚 Loaded performance history:', this._exerciseHistory.length, 'exercises');
            }
        } catch (error) {
            console.warn('⚠️ Failed to load performance data:', error);
        }
    }

    _savePerformanceData() {
        try {
            const data = {
                performanceHistory: Array.from(this._performanceHistory.entries()),
                exerciseHistory: this._exerciseHistory
            };
            localStorage.setItem('intelligentSequencer_performance', JSON.stringify(data));
        } catch (error) {
            console.warn('⚠️ Failed to save performance data:', error);
        }
    }
}

export default IntelligentSequencer;