/**
 * IAEngine - Intelligence Artificielle Engine pour les exercices éducatifs
 * Basé sur LLMManager.js mais adapté pour ES6 modules et contexte éducatif
 */

class IAEngine {
    constructor(config = {}) {
        // Configuration par défaut
        this.config = {
            defaultProvider: config.defaultProvider || 'openai',
            fallbackProviders: config.fallbackProviders || ['deepseek'], // OpenAI -> DeepSeek -> Disable
            timeout: config.timeout || 30000, // 30 secondes
            maxRetries: config.maxRetries || 3,
            retryDelay: config.retryDelay || 1000,
            enableFallback: config.enableFallback !== false,
            debug: config.debug || true, // Enable debug par défaut pour voir le fallback
            disableOnAllFailed: config.disableOnAllFailed !== false, // Désactive si tous échouent
            ...config
        };

        // Configuration des providers LLM
        this.providers = {
            openai: {
                endpoint: 'https://api.openai.com/v1/chat/completions',
                model: 'gpt-4o-mini',
                headers: {
                    'Authorization': 'Bearer {API_KEY}',
                    'Content-Type': 'application/json'
                },
                temperature: 0.3, // Plus conservateur pour l'éducation
                maxTokens: 1000,
                timeout: 30000,
                retries: 3
            },
            claude: {
                endpoint: 'https://api.anthropic.com/v1/messages',
                model: 'claude-3-haiku-20240307',
                headers: {
                    'x-api-key': '{API_KEY}',
                    'Content-Type': 'application/json',
                    'anthropic-version': '2023-06-01'
                },
                temperature: 0.3,
                maxTokens: 1000,
                timeout: 30000,
                retries: 3
            },
            deepseek: {
                endpoint: 'https://api.deepseek.com/v1/chat/completions',
                model: 'deepseek-chat',
                headers: {
                    'Authorization': 'Bearer {API_KEY}',
                    'Content-Type': 'application/json'
                },
                temperature: 0.3,
                maxTokens: 1000,
                timeout: 30000,
                retries: 3
            }
        };

        // Cache pour éviter les appels répétés
        this.cache = new Map();
        this.stats = {
            totalRequests: 0,
            successfulRequests: 0,
            failedRequests: 0,
            cacheHits: 0,
            providerUsage: {}
        };

        // Variables d'environnement simulées (en production, celles-ci viendraient du serveur)
        this.apiKeys = null;
        this.consecutiveErrors = 0;
        this.maxConsecutiveErrors = 5;

        // État de disponibilité des providers
        this.providerStatus = {
            openai: { available: null, lastTested: null, consecutiveFailures: 0 },
            deepseek: { available: null, lastTested: null, consecutiveFailures: 0 }
        };
        this.aiDisabled = false; // État global : IA complètement désactivée
        this.disableReason = null;

        this._initializeApiKeys();
    }

    /**
     * Initialise les clés API (simulation, en production elles viendraient du serveur)
     */
    async _initializeApiKeys() {
        // Détecter l'environnement Node.js vs Browser
        const isNodeJS = typeof window === 'undefined' && typeof process !== 'undefined';

        if (isNodeJS) {
            // En Node.js, charger directement depuis les variables d'environnement
            try {
                // Charger dotenv pour les tests
                const { config } = await import('dotenv');
                config();

                this.apiKeys = {
                    OPENAI_API_KEY: process.env.OPENAI_API_KEY,
                    ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
                    DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY,
                    MISTRAL_API_KEY: process.env.MISTRAL_API_KEY,
                    GEMINI_API_KEY: process.env.GEMINI_API_KEY
                };

                // Filtrer les clés valides
                this.apiKeys = Object.fromEntries(
                    Object.entries(this.apiKeys).filter(([key, value]) => value && value.length > 0)
                );

                if (Object.keys(this.apiKeys).length > 0) {
                    this._log('✅ API keys loaded from environment variables');
                    return;
                } else {
                    throw new Error('No valid API keys in environment');
                }
            } catch (error) {
                this._log('⚠️ Failed to load env vars, using mock mode');
                this.apiKeys = { mock: true };
                return;
            }
        }

        // En Browser, utiliser l'endpoint serveur
        try {
            this._log('🔍 Fetching API keys from server...');
            const response = await fetch('/api/llm-config', {
                method: 'GET',
                credentials: 'same-origin'
            });

            this._log(`🔍 Server response status: ${response.status}`);

            if (response.ok) {
                this.apiKeys = await response.json();
                this._log('✅ API keys loaded from server');
                this._log(`🔍 Keys loaded: ${Object.keys(this.apiKeys)}`);
            } else {
                const errorText = await response.text();
                throw new Error(`Server API keys not available. Status: ${response.status}, Response: ${errorText}`);
            }
        } catch (error) {
            this._log(`❌ Failed to load API keys: ${error.message}`);
            this._log('⚠️ NO MOCK MODE - FAILING HARD');
            throw new Error(`Failed to initialize API keys: ${error.message}`);
        }
    }

    /**
     * Appel principal à un LLM pour validation éducative
     * @param {string} prompt - Le prompt éducatif à envoyer
     * @param {Object} options - Options personnalisées
     * @returns {Promise<Object>} - Réponse structurée
     */
    async validateEducationalContent(prompt, options = {}) {
        const startTime = Date.now();
        this.stats.totalRequests++;

        // Vérifier si l'IA est complètement désactivée
        if (this.aiDisabled) {
            this._log('🚫 AI system is disabled - NO MOCK FALLBACK');
            this.stats.failedRequests++;
            throw new Error('AI system is disabled and no mock fallback is available. Check your API keys and network connection.');
        }

        // Cache temporairement désactivé pour les tests - mais on génère quand même la clé
        const cacheKey = this._generateCacheKey(prompt, options);
        // if (this.cache.has(cacheKey)) {
        //     this.stats.cacheHits++;
        //     this._log('📦 Cache hit for educational validation');
        //     return this.cache.get(cacheKey);
        // }

        // Ordre de fallback : OpenAI -> DeepSeek -> Disable
        const providers = this._getProviderOrder(options.preferredProvider);
        let lastError = null;
        let allProvidersFailed = true;

        for (const provider of providers) {
            // Vérifier si le provider est marqué comme non disponible
            if (this.providerStatus[provider]?.available === false) {
                this._log(`⏭️ Skipping ${provider.toUpperCase()} - marked as unavailable`);
                continue;
            }

            try {
                this._log(`🤖 Attempting ${provider.toUpperCase()} for educational validation`);

                const result = await this._callProvider(provider, prompt, options);

                // Succès : mettre à jour le statut du provider
                this.providerStatus[provider] = {
                    available: true,
                    lastTested: new Date().toISOString(),
                    consecutiveFailures: 0,
                    lastDuration: Date.now() - startTime
                };

                // Cache le résultat
                this.cache.set(cacheKey, result);

                // Nettoyer le cache si il devient trop gros
                if (this.cache.size > 1000) {
                    const firstKey = this.cache.keys().next().value;
                    this.cache.delete(firstKey);
                }

                // Mettre à jour les stats
                this.stats.successfulRequests++;
                this.consecutiveErrors = 0;
                this._updateProviderStats(provider, Date.now() - startTime, true);
                allProvidersFailed = false;

                this._log(`✅ ${provider.toUpperCase()} educational validation successful (${Date.now() - startTime}ms)`);

                return result;

            } catch (error) {
                lastError = error;
                this.consecutiveErrors++;
                this._updateProviderStats(provider, Date.now() - startTime, false);

                // Mettre à jour le statut d'échec du provider
                this.providerStatus[provider].available = false;
                this.providerStatus[provider].lastTested = new Date().toISOString();
                this.providerStatus[provider].consecutiveFailures = (this.providerStatus[provider].consecutiveFailures || 0) + 1;
                this.providerStatus[provider].lastError = error.message;

                this._log(`❌ ${provider.toUpperCase()} failed: ${error.message}`);

                // Si pas de fallback activé, arrêter
                if (!this.config.enableFallback) {
                    break;
                }
            }
        }

        // Tous les providers ont échoué
        this.stats.failedRequests++;

        // Si tous les providers configurés ont échoué, désactiver l'IA
        if (allProvidersFailed && this.config.disableOnAllFailed) {
            this.aiDisabled = true;
            this.disableReason = 'All providers failed during operation';
            this._log('🚫 All providers failed - AI system disabled');
        }

        // PAS DE MOCK - FAIL HARD
        this._log('💥 All providers failed - NO MOCK FALLBACK');
        this.stats.failedRequests++;
        throw new Error(`All AI providers failed. Last error: ${lastError?.message || 'Unknown error'}. Check your API keys and network connection.`);
    }

    /**
     * Appelle un provider spécifique
     * @private
     */
    async _callProvider(provider, prompt, options) {
        // Si pas de clés API, FAIL HARD - PAS DE MOCK
        if (!this.apiKeys || this.apiKeys.mock) {
            throw new Error(`No API keys available for ${provider}. Mock mode disabled. Configure your API keys properly.`);
        }

        const config = this.providers[provider];
        if (!config) {
            throw new Error(`Provider ${provider} not configured`);
        }

        const apiKey = this.apiKeys[`${provider.toUpperCase()}_API_KEY`];
        if (!apiKey) {
            throw new Error(`API key missing for ${provider}`);
        }

        // Construire la requête
        const requestData = this._buildRequest(provider, prompt, options);

        // Préparer les headers
        const headers = {};
        Object.keys(config.headers).forEach(key => {
            headers[key] = config.headers[key].replace('{API_KEY}', apiKey);
        });

        // Effectuer l'appel
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), config.timeout);

        try {
            const response = await fetch(config.endpoint, {
                method: 'POST',
                headers,
                body: JSON.stringify(requestData),
                signal: controller.signal
            });

            clearTimeout(timeoutId);

            if (!response.ok) {
                const errorText = await response.text();
                throw new Error(`HTTP ${response.status}: ${errorText}`);
            }

            const responseData = await response.json();
            return this._parseResponse(provider, responseData);

        } catch (error) {
            clearTimeout(timeoutId);
            throw error;
        }
    }

    /**
     * Construit la requête selon le format du provider
     * @private
     */
    _buildRequest(provider, prompt, options) {
        const config = this.providers[provider];
        const temperature = options.temperature ?? config.temperature;
        const maxTokens = options.maxTokens ?? config.maxTokens;

        // Prompt système pour l'éducation
        const systemPrompt = options.systemPrompt ||
            'You are an expert language learning evaluator. Provide constructive, encouraging feedback for students. Return responses in valid JSON format only.';

        switch (provider) {
            case 'openai':
            case 'deepseek':
                return {
                    model: config.model,
                    messages: [
                        { role: 'system', content: systemPrompt },
                        { role: 'user', content: prompt }
                    ],
                    max_tokens: maxTokens,
                    temperature: temperature,
                    stream: false
                };

            case 'claude':
                return {
                    model: config.model,
                    max_tokens: maxTokens,
                    temperature: temperature,
                    system: systemPrompt,
                    messages: [
                        { role: 'user', content: prompt }
                    ]
                };

            default:
                throw new Error(`Request format not supported for ${provider}`);
        }
    }

    /**
     * Parse la réponse selon le format du provider
     * @private
     */
    _parseResponse(provider, responseData) {
        let content;

        try {
            switch (provider) {
                case 'openai':
                case 'deepseek':
                    content = responseData.choices[0].message.content.trim();
                    break;

                case 'claude':
                    content = responseData.content[0].text.trim();
                    break;

                default:
                    throw new Error(`Parser not supported for ${provider}`);
            }

            // Essayer de parser en JSON si possible
            try {
                // Nettoyer le contenu des backticks markdown (DeepSeek)
                let cleanContent = content;
                if (content.includes('```json')) {
                    const jsonMatch = content.match(/```json\s*([\s\S]*?)\s*```/);
                    if (jsonMatch) {
                        cleanContent = jsonMatch[1].trim();
                    }
                } else if (content.includes('```')) {
                    const codeMatch = content.match(/```\s*([\s\S]*?)\s*```/);
                    if (codeMatch) {
                        cleanContent = codeMatch[1].trim();
                    }
                }

                const jsonResponse = JSON.parse(cleanContent);
                return {
                    ...jsonResponse,
                    provider,
                    timestamp: new Date().toISOString(),
                    cached: false
                };
            } catch (jsonError) {
                // Si ce n'est pas du JSON valide, retourner comme texte
                return {
                    content: content,
                    provider,
                    timestamp: new Date().toISOString(),
                    cached: false
                };
            }

        } catch (error) {
            this._log(`❌ Error parsing ${provider} response: ${error.message}`);
            throw new Error(`Failed to parse ${provider} response: ${error.message}`);
        }
    }

    // MOCK FUNCTIONALITY COMPLETELY REMOVED
    // SYSTEM WILL FAIL HARD IF AI NOT AVAILABLE

    /**
     * Détecte le type d'exercice depuis le prompt
     * @private
     */
    _detectExerciseType(prompt) {
        const lowerPrompt = prompt.toLowerCase();

        if (lowerPrompt.includes('translation') || lowerPrompt.includes('translate')) {
            return 'translation';
        }
        if (lowerPrompt.includes('grammar') || lowerPrompt.includes('grammatical')) {
            return 'grammar';
        }
        if (lowerPrompt.includes('comprehension') || lowerPrompt.includes('understand')) {
            return 'comprehension';
        }

        return 'general';
    }

    /**
     * Détermine l'ordre des providers à essayer (OpenAI -> DeepSeek seulement)
     * @private
     */
    _getProviderOrder(preferredProvider) {
        // Ordre fixe : OpenAI -> DeepSeek seulement
        const preferredOrder = ['openai', 'deepseek'];

        if (preferredProvider && preferredOrder.includes(preferredProvider)) {
            // Commencer par le provider préféré, puis les autres dans l'ordre
            return [preferredProvider, ...preferredOrder.filter(p => p !== preferredProvider)];
        }

        // Utiliser l'ordre par défaut : OpenAI -> DeepSeek
        return preferredOrder;
    }

    /**
     * Génère une clé de cache
     * @private
     */
    _generateCacheKey(prompt, options) {
        const keyData = {
            prompt: prompt.substring(0, 100), // Première partie du prompt
            temperature: options.temperature || 0.3,
            type: this._detectExerciseType(prompt)
        };
        return JSON.stringify(keyData);
    }

    /**
     * Met à jour les statistiques du provider
     * @private
     */
    _updateProviderStats(provider, duration, success) {
        if (!this.stats.providerUsage[provider]) {
            this.stats.providerUsage[provider] = {
                calls: 0,
                successes: 0,
                failures: 0,
                totalDuration: 0,
                avgDuration: 0
            };
        }

        const stats = this.stats.providerUsage[provider];
        stats.calls++;
        stats.totalDuration += duration;
        stats.avgDuration = Math.round(stats.totalDuration / stats.calls);

        if (success) {
            stats.successes++;
        } else {
            stats.failures++;
        }
    }

    /**
     * Log avec contrôle de debug
     * @private
     */
    _log(message, level = 'INFO') {
        if (this.config.debug || level === 'ERROR') {
            console.log(`[IAEngine ${level}] ${message}`);
        }
    }

    /**
     * API publiques utilitaires
     */

    /**
     * Obtient les statistiques d'usage
     */
    getStats() {
        return {
            ...this.stats,
            cacheSize: this.cache.size,
            consecutiveErrors: this.consecutiveErrors,
            isInMockMode: this.consecutiveErrors >= this.maxConsecutiveErrors
        };
    }

    /**
     * Vide le cache
     */
    clearCache() {
        this.cache.clear();
        this._log('🧹 Cache cleared');
    }

    /**
     * Reset les statistiques
     */
    resetStats() {
        this.stats = {
            totalRequests: 0,
            successfulRequests: 0,
            failedRequests: 0,
            cacheHits: 0,
            providerUsage: {}
        };
        this.consecutiveErrors = 0;
        this._log('📊 Stats reset');
    }

    /**
     * Test de connectivité spécifique à un provider
     */
    async testProviderConnectivity(provider) {
        if (!this.providers[provider]) {
            throw new Error(`Provider ${provider} not configured`);
        }

        const testPrompt = 'Test';
        const testOptions = {
            maxTokens: 10,
            temperature: 0,
            timeout: 10000 // Test plus rapide
        };

        const startTime = Date.now();

        try {
            // Forcer l'utilisation du provider spécifique
            const result = await this._callProvider(provider, testPrompt, testOptions);

            const duration = Date.now() - startTime;

            // Mettre à jour le statut
            this.providerStatus[provider] = {
                available: true,
                lastTested: new Date().toISOString(),
                consecutiveFailures: 0,
                lastDuration: duration
            };

            this._log(`✅ ${provider.toUpperCase()} connectivity test successful (${duration}ms)`);

            return {
                success: true,
                provider: provider,
                duration: duration,
                response: result
            };

        } catch (error) {
            const duration = Date.now() - startTime;

            // Mettre à jour le statut d'échec
            this.providerStatus[provider].available = false;
            this.providerStatus[provider].lastTested = new Date().toISOString();
            this.providerStatus[provider].consecutiveFailures++;
            this.providerStatus[provider].lastError = error.message;

            this._log(`❌ ${provider.toUpperCase()} connectivity test failed: ${error.message} (${duration}ms)`);

            return {
                success: false,
                provider: provider,
                duration: duration,
                error: error.message
            };
        }
    }

    /**
     * Test de connectivité global (tous les providers)
     */
    async testAllProvidersConnectivity() {
        this._log('🔍 Testing connectivity for all providers...');

        const results = {};
        const testPromises = [];

        // Tester OpenAI et DeepSeek en parallèle
        for (const provider of ['openai', 'deepseek']) {
            testPromises.push(
                this.testProviderConnectivity(provider)
                    .then(result => results[provider] = result)
                    .catch(error => results[provider] = { success: false, error: error.message })
            );
        }

        await Promise.allSettled(testPromises);

        // Déterminer l'état global
        const availableProviders = Object.keys(results).filter(p => results[p].success);

        if (availableProviders.length === 0) {
            this.aiDisabled = true;
            this.disableReason = 'All providers failed connectivity test';
            this._log('🚫 All AI providers failed - AI system disabled');
        } else {
            this.aiDisabled = false;
            this.disableReason = null;
            this._log(`✅ AI system available with providers: ${availableProviders.join(', ')}`);
        }

        return {
            results,
            availableProviders,
            aiDisabled: this.aiDisabled,
            disableReason: this.disableReason,
            providerStatus: this.providerStatus
        };
    }

    /**
     * Test de connectivité simplifié (pour compatibilité)
     */
    async testConnectivity() {
        const fullTest = await this.testAllProvidersConnectivity();

        if (fullTest.availableProviders.length > 0) {
            return {
                success: true,
                provider: fullTest.availableProviders[0],
                availableProviders: fullTest.availableProviders,
                providerStatus: this.providerStatus
            };
        } else {
            return {
                success: false,
                error: this.disableReason,
                providerStatus: this.providerStatus,
                stats: this.getStats()
            };
        }
    }

    /**
     * Méthodes spécialisées pour l'éducation
     */

    /**
     * Validation de traduction éducative
     */
    async validateTranslation(original, userTranslation, context = {}) {
        const prompt = `Evaluate this language learning translation with STRICT scoring:
- Original (English): "${original}"
- Student translation: "${userTranslation}"
- Context: ${context.exerciseType || 'vocabulary'} exercise
- Target language: ${context.toLang || context.targetLanguage || 'French/Chinese'}

STRICT SCORING RULES:
- 0-20 points: Completely wrong/unrelated words (e.g., "pizza spaghetti" for "good morning")
- 20-40 points: Some correct words but wrong overall meaning
- 40-70 points: Partially captured meaning but significant errors
- 70-90 points: Mostly correct with minor errors
- 90-100 points: Perfect or near-perfect translation

Return JSON: {
    "score": 0-100,
    "correct": boolean,
    "feedback": "specific feedback about accuracy",
    "keyPoints": ["translation errors or successes"],
    "encouragement": "constructive guidance"
}`;

        return await this.validateEducationalContent(prompt, {
            systemPrompt: 'You are a strict but fair language tutor. Grade translations accurately based on meaning and correctness, not effort.',
            preferredProvider: 'openai'
        });
    }

    /**
     * Validation de compréhension audio/texte
     */
    async validateComprehension(content, userResponse, context = {}) {
        const prompt = `Evaluate text comprehension with STRICT scoring:
- Content: "${content}"
- Student response: "${userResponse}"
- Exercise type: ${context.exerciseType || 'comprehension'}

STRICT SCORING RULES:
- 0-20 points: Completely unrelated/nonsensical response (e.g., "Elephants are purple" for Amazon rainforest)
- 20-40 points: Some keywords mentioned but wrong understanding
- 40-70 points: Partial understanding with significant gaps
- 70-90 points: Good understanding with minor errors
- 90-100 points: Perfect or near-perfect comprehension

Return JSON: {
    "score": 0-100,
    "correct": boolean,
    "feedback": "specific feedback about comprehension accuracy",
    "mainPointsUnderstood": ["concepts captured"],
    "encouragement": "constructive guidance"
}`;

        return await this.validateEducationalContent(prompt, {
            systemPrompt: 'You are a strict but fair reading comprehension tutor. Grade based on actual understanding, not effort. Be harsh on completely wrong answers.'
        });
    }

    /**
     * Validation grammaticale
     */
    async validateGrammar(userResponse, context = {}) {
        const prompt = `Evaluate grammar usage:
- Student response: "${userResponse}"
- Target concepts: ${JSON.stringify(context.grammarConcepts || {})}
- Language level: ${context.languageLevel || 'beginner'}

Evaluate grammatical correctness and naturalness. Be encouraging.
Return JSON: {
    "score": 0-100,
    "correct": boolean,
    "feedback": "constructive grammar feedback",
    "grammarErrors": ["specific errors"],
    "grammarStrengths": ["what was done well"],
    "suggestion": "improvement suggestion",
    "encouragement": "positive reinforcement"
}`;

        return await this.validateEducationalContent(prompt, {
            systemPrompt: 'You are a grammar expert who focuses on helping students improve with kindness.'
        });
    }
}

export default IAEngine;