// === SCANNER AUTOMATIQUE DE CONTENU ===

class ContentScanner {
    constructor() {
        this.discoveredContent = new Map();
        this.contentDirectory = 'js/content/';

        // Configuration depuis EnvConfig
        this.envConfig = window.envConfig;
        logSh('🔧 ContentScanner configuré avec:', 'INFO');
    }

    async scanAllContent() {
        logSh('🔍 ContentScanner - Scan automatique du dossier content...', 'INFO');

        const results = {
            found: [],
            errors: [],
            total: 0
        };

        try {
            // Découvrir tous les fichiers .js dans le dossier content
            const contentFiles = await this.discoverContentFiles();
            logSh(`📁 Fichiers trouvés: ${contentFiles.join(', ')}`, 'INFO');

            for (const filename of contentFiles) {
                try {
                    logSh(`🔍 Scanning content file: ${filename}`, 'DEBUG');
                    const contentInfo = await this.scanContentFile(filename);
                    if (contentInfo) {
                        logSh(`✅ Successfully scanned: ${contentInfo.id} (${contentInfo.name})`, 'INFO');
                        this.discoveredContent.set(contentInfo.id, contentInfo);
                        results.found.push(contentInfo);
                    } else {
                        logSh(`⚠️ scanContentFile returned null for ${filename}`, 'WARN');
                    }
                } catch (error) {
                    logSh(`⚠️ Erreur scan ${filename}: ${error.message}`, 'WARN');
                    results.errors.push({ filename, error: error.message });
                }
            }
        } catch (error) {
            logSh('❌ Erreur lors de la découverte des fichiers:', error.message, 'ERROR');
            results.errors.push({ error: `Scan directory failed: ${error.message}` });
        }

        results.total = results.found.length;
        // Analyser les capacités globales du contenu découvert
        this.analyzeGlobalCapabilities(results.found);

        logSh(`✅ Scan terminé: ${results.total} modules trouvés`, 'INFO');

        return results;
    }

    async discoverContentFiles() {
        // Détecter si on est en mode file:// ou serveur web
        const isFileProtocol = window.location.protocol === 'file:';

        if (isFileProtocol) {
            logSh('📂 Mode fichier local - chargement des fichiers connus', 'INFO');
            // D'abord essayer de charger les fichiers connus
            await this.preloadKnownFiles();
            // Puis scanner les modules chargés
            return this.scanLoadedModules();
        }

        let allFiles = [];

        // Méthode 1: Récupérer le listing local
        try {
            const response = await fetch(this.contentDirectory);
            if (response.ok) {
                const html = await response.text();
                // Parser les liens .js dans le HTML du directory listing
                const jsFiles = this.parseDirectoryListing(html);
                if (jsFiles.length > 0) {
                    logSh('📂 Méthode directory listing réussie', 'INFO');
                    allFiles = [...jsFiles];
                }
            }
        } catch (error) {
            logSh('📂 Directory listing failed', 'INFO');
        }

        // Méthode 2: Toujours essayer les fichiers distants connus
        logSh('📂 Tentative de scan des fichiers distants...', 'INFO');
        const commonFiles = await this.tryCommonFiles();

        // Combiner les résultats locaux et distants sans doublons
        for (const file of commonFiles) {
            if (!allFiles.includes(file)) {
                allFiles.push(file);
            }
        }

        logSh(`📁 Fichiers trouvés: ${allFiles.join(', ')}`, 'INFO');
        return allFiles;
    }

    async preloadKnownFiles() {
        const knownFiles = [
            'sbs-level-7-8-new.js',           // Local JS file
            'SBS-level-1.js',                 // Side by Side Level 1 - English introduction with Chinese translation
            'english-class-demo.json',        // Remote JSON file
            'english-exemple-commented.js',   // Module JS complet nouvellement créé
            'story-test.js',                   // Story test module
            'story-prototype-1000words.js',   // 1000-word story prototype
            'story-complete-1000words.js',    // Complete 1000-word story with pronunciation
            'chinese-long-story.js',           // Chinese story with English translation and pinyin
            'french-beginner-story.js',       // French beginner story for English speakers
            'WTA1B1.js',                       // English letters and pets story with Chinese translation
            'story-prototype-optimized.js',   // Optimized story with centralized vocabulary
            'test-compatibility.js',           // Test content for compatibility system
            'test-minimal.js',                 // Minimal test content
            'test-rich.js',                    // Rich test content
            'NCE1-Lesson63-64.js',            // New Concept English Book 1 - Lessons 63-64
            'NCE2-Lesson3.js',                // New Concept English Book 2 - Lesson 3
            'NCE2-Lesson30.js'                // New Concept English Book 2 - Lesson 30
        ];

        logSh('📂 Préchargement des fichiers connus...', 'INFO');
        this.updateConnectionStatus('loading');

        let remoteSuccess = 0;
        let localSuccess = 0;

        for (const filename of knownFiles) {
            try {
                if (filename.endsWith('.json')) {
                    // Essayer d'abord le contenu distant, puis local en fallback
                    const success = await this.loadJsonWithFallback(filename);
                    if (success === 'remote') remoteSuccess++;
                    else if (success === 'local') localSuccess++;
                } else {
                    // Fichiers JS en local uniquement
                    await this.loadScript(`${this.contentDirectory}${filename}`);
                    localSuccess++;
                }
                logSh(`✓ Chargé: ${filename}`, 'INFO');
            } catch (error) {
                logSh(`⚠️ Ignoré: ${filename} (${error.message})`, 'INFO');
            }
        }

        // Mise à jour du statut de connexion
        if (remoteSuccess > 0) {
            this.updateConnectionStatus('online', `${remoteSuccess} contenus distants`);
        } else if (localSuccess > 0) {
            this.updateConnectionStatus('offline', `${localSuccess} contenus locaux`);
        } else {
            this.updateConnectionStatus('error', 'Aucun contenu chargé');
        }
    }

    async loadJsonWithFallback(filename) {
        const tryRemoteFirst = this.envConfig?.get('TRY_REMOTE_FIRST') && this.shouldTryRemote();

        if (tryRemoteFirst) {
            // Mode distant prioritaire (rare)
            const remoteResult = await this.tryRemoteLoad(filename);
            if (remoteResult.success) return remoteResult.source;

            // Fallback local
            const localResult = await this.tryLocalLoad(filename);
            if (localResult.success) return localResult.source;

            throw new Error(`Impossible de charger ${filename}: Remote (${remoteResult.error}) et Local (${localResult.error})`);
        } else {
            // Mode LOCAL PRIORITAIRE (par défaut)
            const localResult = await this.tryLocalLoad(filename);
            if (localResult.success) return localResult.source;

            // Fallback distant seulement si configuré et réseau disponible
            if (this.shouldTryRemote()) {
                const remoteResult = await this.tryRemoteLoad(filename);
                if (remoteResult.success) return remoteResult.source;

                throw new Error(`Impossible de charger ${filename}: Local (${localResult.error}) et Remote (${remoteResult.error})`);
            } else {
                throw new Error(`Impossible de charger ${filename}: ${localResult.error} (distant désactivé)`);
            }
        }
    }

    async tryLocalLoad(filename) {
        try {
            const localUrl = `${this.contentDirectory}${filename}`;
            const response = await fetch(localUrl);
            if (response.ok) {
                const jsonData = await response.json();
                const moduleName = this.jsonFilenameToModuleName(filename);
                window.ContentModules = window.ContentModules || {};
                window.ContentModules[moduleName] = jsonData;
                logSh(`💾 Chargé depuis local: ${filename}`, 'INFO');
                return { success: true, source: 'local' };
            } else {
                throw new Error(`HTTP ${response.status}`);
            }
        } catch (error) {
            logSh(`💾 Local échoué pour ${filename}: ${error.message}`, 'INFO');
            return { success: false, error: error.message };
        }
    }

    async tryRemoteLoad(filename) {
        // Double vérification: ne pas essayer en mode file://
        if (window.location.protocol === 'file:') {
            logSh(`📁 Mode file:// - Saut du chargement distant pour ${filename}`, 'DEBUG');
            return { success: false, error: 'Mode file:// - distant désactivé' };
        }

        try {
            // UTILISER LE PROXY LOCAL au lieu de DigitalOcean directement
            const remoteUrl = `http://localhost:8083/do-proxy/${filename}`;

            logSh(`🔍 Tentative de chargement distant via proxy: ${remoteUrl}`, 'INFO');
            logSh(`🔧 Protocol: ${window.location.protocol}, Remote enabled: ${this.envConfig?.isRemoteContentEnabled()}`, 'DEBUG');

            // Fetch avec timeout court
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), this.envConfig.get('REMOTE_TIMEOUT'));

            await this.loadJsonContentWithTimeout(remoteUrl, controller.signal);
            clearTimeout(timeoutId);

            logSh(`🌐 Chargé depuis distant: ${filename}`, 'INFO');
            return { success: true, source: 'remote' };
        } catch (error) {
            logSh(`💥 Distant échoué pour ${filename}: ${error.message}`, 'ERROR');
            logSh(`🔍 Stack trace: ${error.stack}`, 'DEBUG');
            return { success: false, error: error.message };
        }
    }

    async loadJsonContentWithTimeout(url, signal) {
        const response = await fetch(url, { signal });
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
        }

        const jsonData = await response.json();
        const moduleName = this.jsonFilenameToModuleName(url);

        window.ContentModules = window.ContentModules || {};
        window.ContentModules[moduleName] = jsonData;
    }

    shouldTryRemote() {
        // Utiliser la configuration de EnvConfig
        return this.envConfig?.isRemoteContentEnabled() &&
               (window.location.protocol !== 'file:' || this.envConfig.get('FORCE_REMOTE_ON_FILE'));
    }

    updateConnectionStatus(status, details = '') {
        // Émettre un événement personnalisé pour l'UI
        const event = new CustomEvent('contentConnectionStatus', {
            detail: { status, details, timestamp: new Date() }
        });
        window.dispatchEvent(event);
    }

    scanLoadedModules() {
        // Scanner les modules déjà présents dans window.ContentModules
        const loadedFiles = [];

        if (window.ContentModules) {
            logSh(`📂 Modules already loaded in window.ContentModules:`, 'DEBUG');
            for (const moduleName in window.ContentModules) {
                // Convertir le nom du module en nom de fichier probable
                const filename = this.moduleNameToFilename(moduleName);
                loadedFiles.push(filename);
                logSh(`✓ Module découvert: ${moduleName} → ${filename}`, 'INFO');

                // Debug : vérifier si le module a un id
                const module = window.ContentModules[moduleName];
                if (module.id) {
                    logSh(`   Module ID: ${module.id}`, 'DEBUG');
                } else {
                    logSh(`   ⚠️ Module ${moduleName} has no ID!`, 'WARN');
                }
            }
        } else {
            logSh(`⚠️ window.ContentModules is undefined!`, 'WARN');
        }

        logSh(`📂 Total loaded files from modules: ${loadedFiles.length}`, 'INFO');
        return loadedFiles;
    }

    moduleNameToFilename(moduleName) {
        // Mapping des noms de modules vers les noms de fichiers
        const mapping = {
            'SBSLevel78New': 'sbs-level-7-8-new.js',
            'EnglishClassDemo': 'english-class-demo.json',
            'EnglishExemple': 'english_exemple.json',
            'EnglishExempleFixed': 'english_exemple_fixed.json',
            'EnglishExempleUltraCommented': 'english_exemple_ultra_commented.json',
            // AJOUT: Fichiers générés par le système de conversion
            'SbsLevel78GeneratedFromJs': 'sbs-level-7-8-GENERATED-from-js.json',
            'EnglishExempleCommentedGenerated': 'english-exemple-commented-GENERATED.json',
            // AJOUT: Module JS complet nouvellement créé
            'EnglishExempleCommented': 'english-exemple-commented.js',
            // AJOUT: Story modules
            'StoryTest': 'story-test.js',
            'StoryPrototype1000words': 'story-prototype-1000words.js',
            'StoryComplete1000words': 'story-complete-1000words.js',
            'ChineseLongStory': 'chinese-long-story.js',
            'FrenchBeginnerStory': 'french-beginner-story.js',
            'WTA1B1': 'WTA1B1.js',
            'SBSLevel1': 'SBS-level-1.js',
            'StoryPrototypeOptimized': 'story-prototype-optimized.js',
            // AJOUT: Test compatibility modules
            'TestMinimalContent': 'test-compatibility.js',
            'TestRichContent': 'test-compatibility.js',
            'TestSentenceOnly': 'test-compatibility.js',
            // AJOUT: NCE modules
            'NCE1Lesson6364': 'NCE1-Lesson63-64.js',
            'NCE2Lesson3': 'NCE2-Lesson3.js',
            'NCE2Lesson30': 'NCE2-Lesson30.js'
        };

        if (mapping[moduleName]) {
            return mapping[moduleName];
        }

        // Conversion générique PascalCase → kebab-case
        // Essayer d'abord .json puis .js
        const baseName = moduleName
            .replace(/([a-z])([A-Z])/g, '$1-$2')
            .toLowerCase();
        return baseName + '.json'; // Préférer JSON en premier
    }

    parseDirectoryListing(html) {
        const contentFiles = [];
        // Regex pour trouver les liens vers des fichiers .js ET .json
        const linkRegex = /<a[^>]+href="([^"]+\.(js|json))"[^>]*>/gi;
        let match;

        while ((match = linkRegex.exec(html)) !== null) {
            const filename = match[1];
            // Éviter les fichiers système ou temporaires
            if (!filename.startsWith('.') && !filename.includes('test') && !filename.includes('backup')) {
                contentFiles.push(filename);
            }
        }

        return contentFiles;
    }

    async tryCommonFiles() {
        // FIXME: Liste temporaire - À remplacer par listing dynamique DigitalOcean
        // Pour l'instant on met juste les fichiers qu'on sait qui existent
        const possibleFiles = [
            'sbs-level-7-8-new.js',      // Local JS legacy
            'english-class-demo.json',    // Remote JSON example
            'english_exemple.json',       // Local JSON basic
            'english_exemple_fixed.json', // Local JSON modular
            'english_exemple_ultra_commented.json', // Local JSON ultra-modular
            'example-with-images.js',     // Local JS with image support for Word Discovery
            // AJOUT: Fichiers générés par le système de conversion
            'sbs-level-7-8-GENERATED-from-js.json',
            'english-exemple-commented-GENERATED.json',
            // AJOUT: Fichiers NCE (New Concept English)
            'NCE1-Lesson63-64.js',        // New Concept English Book 1 - Lessons 63-64
            'NCE2-Lesson3.js',            // New Concept English Book 2 - Lesson 3
            'NCE2-Lesson30.js'            // New Concept English Book 2 - Lesson 30
        ];

        const existingFiles = [];

        for (const filename of possibleFiles) {
            try {
                // Tester local d'abord
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 1000);

                const response = await fetch(`${this.contentDirectory}${filename}`, {
                    method: 'HEAD',
                    signal: controller.signal
                });

                clearTimeout(timeoutId);

                if (response.ok) {
                    existingFiles.push(filename);
                    logSh(`✓ Trouvé (local): ${filename}`, 'INFO');
                    continue;
                }
            } catch (error) {
                // Fichier local n'existe pas
            }

            // Si pas trouvé en local et remote activé, tester remote via proxy
            if (this.envConfig.isRemoteContentEnabled() && window.location.protocol !== 'file:') {
                try {
                    const controller = new AbortController();
                    const timeoutId = setTimeout(() => controller.abort(), 3000);

                    // UTILISER LE PROXY LOCAL au lieu de DigitalOcean directement
                    const remoteUrl = `http://localhost:8083/do-proxy/${filename}`;
                    logSh(`🔍 Test existence via proxy: ${remoteUrl}`, 'DEBUG');

                    const response = await fetch(remoteUrl, {
                        method: 'HEAD',
                        signal: controller.signal
                    });

                    clearTimeout(timeoutId);

                    if (response.ok) {
                        existingFiles.push(filename);
                        logSh(`✓ Trouvé (remote): ${filename}`, 'INFO');
                    } else if (response.status === 403) {
                        logSh(`🔒 Trouvé mais privé (remote): ${filename}`, 'INFO');
                        // Même si privé, on considère que le fichier existe
                        existingFiles.push(filename);
                    }
                } catch (error) {
                    // Fichier remote n'existe pas ou timeout
                }
            }
        }

        return existingFiles;
    }

    async scanContentFile(filename) {
        const contentId = this.extractContentId(filename);
        const moduleName = this.getModuleName(contentId);

        try {
            // Vérifier d'abord si le module est déjà chargé
            if (!window.ContentModules || !window.ContentModules[moduleName]) {
                // Le module n'est pas encore chargé, on doit le charger
                // Détecter le type de fichier et charger en conséquence
                if (filename.endsWith('.json')) {
                    // Fichier JSON - essayer de le charger via proxy ou local
                    await this.loadJsonContent(filename);
                } else {
                    // Fichier JS - charger le script classique
                    await this.loadScript(`js/content/${filename}`);
                }

                // Vérifier si le module existe après chargement
                if (!window.ContentModules || !window.ContentModules[moduleName]) {
                    throw new Error(`Module ${moduleName} non trouvé après chargement`);
                }
            } else {
                logSh(`✓ Module ${moduleName} déjà chargé, pas besoin de recharger`, 'INFO');
            }

            const module = window.ContentModules[moduleName];

            // Extraire les métadonnées
            const contentInfo = this.extractContentInfo(module, contentId, filename);

            logSh(`📦 Contenu découvert: ${contentInfo.name}`, 'INFO');
            return contentInfo;

        } catch (error) {
            throw new Error(`Impossible de charger ${filename}: ${error.message}`);
        }
    }

    extractContentInfo(module, contentId, filename) {
        // Analyser les capacités du contenu ultra-modulaire
        let capabilities;
        try {
            capabilities = this.analyzeContentCapabilities(module);
        } catch (error) {
            logSh(`⚠️ Erreur dans analyzeContentCapabilities pour ${contentId}: ${error.message}`, 'WARN');
            // Fallback avec capacités basiques
            capabilities = {
                hasVocabulary: !!module.vocabulary,
                hasSentences: !!module.sentences,
                hasGrammar: !!module.grammar,
                hasBasicContent: true
            };
        }

        return {
            id: module.id || contentId,
            filename: filename,
            name: module.name || this.beautifyContentId(contentId),
            description: module.description || 'Contenu automatiquement détecté',

            // Ultra-modular metadata
            difficulty_level: module.difficulty_level,
            original_lang: module.original_lang,
            user_lang: module.user_lang,
            tags: module.tags || [],
            skills_covered: module.skills_covered || [],
            target_audience: module.target_audience || {},
            estimated_duration: module.estimated_duration,

            // Content capabilities analysis
            capabilities: capabilities,
            compatibility: this.safeCalculateGameCompatibility(capabilities),
            icon: this.safeGetContentIcon(module, contentId),
            difficulty: module.difficulty || 'medium',
            enabled: true,
            
            // Métadonnées détaillées
            metadata: {
                version: module.version || '1.0',
                format: module.format || 'legacy',
                totalItems: this.countItems(module),
                categories: this.extractCategories(module),
                contentTypes: this.extractContentTypes(module),
                estimatedTime: this.calculateEstimatedTime(module),
                lastScanned: new Date().toISOString()
            },

            // Statistiques
            stats: {
                vocabularyCount: this.countByType(module, 'vocabulary'),
                sentenceCount: this.countByType(module, 'sentence'),
                dialogueCount: this.countByType(module, 'dialogue'),
                grammarCount: this.countByType(module, 'grammar')
            },

            // Configuration pour les jeux
            gameCompatibility: this.safeAnalyzeGameCompatibility(module)
        };
    }

    safeCalculateGameCompatibility(capabilities) {
        try {
            return this.calculateGameCompatibility(capabilities);
        } catch (error) {
            logSh(`⚠️ Erreur dans calculateGameCompatibility: ${error.message}`, 'WARN');
            return {}; // Retourner un objet vide en cas d'erreur
        }
    }

    safeGetContentIcon(module, contentId) {
        try {
            return this.getContentIcon(module, contentId);
        } catch (error) {
            logSh(`⚠️ Erreur dans getContentIcon: ${error.message}`, 'WARN');
            return '📚'; // Icône par défaut
        }
    }

    safeAnalyzeGameCompatibility(module) {
        try {
            return this.analyzeGameCompatibility(module);
        } catch (error) {
            logSh(`⚠️ Erreur dans analyzeGameCompatibility: ${error.message}`, 'WARN');
            return {}; // Retourner un objet vide en cas d'erreur
        }
    }

    extractContentId(filename) {
        return filename.replace('.js', '').toLowerCase();
    }

    getModuleName(contentId) {
        const mapping = {
            'sbs-level-7-8-new': 'SBSLevel78New',
            'sbs-level-1': 'SBSLevel1',
            'chinese-long-story': 'ChineseLongStory',
            'french-beginner-story': 'FrenchBeginnerStory',
            'wta1b1': 'WTA1B1',
            'story-prototype-optimized': 'StoryPrototypeOptimized',
            'test-compatibility': 'TestMinimalContent',
            'test-minimal': 'TestMinimal',
            'test-rich': 'TestRich',
            // Ajout des modules NCE
            'nce1-lesson63-64': 'NCE1Lesson6364',
            'nce2-lesson3': 'NCE2Lesson3',
            'nce2-lesson30': 'NCE2Lesson30'
        };
        return mapping[contentId] || this.toPascalCase(contentId);
    }

    toPascalCase(str) {
        return str.split('-').map(word => 
            word.charAt(0).toUpperCase() + word.slice(1)
        ).join('');
    }

    beautifyContentId(contentId) {
        const beautified = {
            'sbs-level-7-8-new': 'SBS Level 7-8 (Simple Format)'
        };
        return beautified[contentId] || contentId.charAt(0).toUpperCase() + contentId.slice(1);
    }

    getContentIcon(module, contentId) {
        // Icône du module si disponible
        if (module.icon) return module.icon;

        // Icônes par défaut selon l'ID
        const defaultIcons = {
            'sbs-level-7-8-new': '✨'
        };

        return defaultIcons[contentId] || '📝';
    }

    countItems(module) {
        let count = 0;
        
        // Format moderne (contentItems)
        if (module.contentItems && Array.isArray(module.contentItems)) {
            return module.contentItems.length;
        }
        
        // Format simple (vocabulary object + sentences array)
        if (module.vocabulary && typeof module.vocabulary === 'object' && !Array.isArray(module.vocabulary)) {
            count += Object.keys(module.vocabulary).length;
        }
        // Format legacy (vocabulary array)
        else if (module.vocabulary && Array.isArray(module.vocabulary)) {
            count += module.vocabulary.length;
        }
        
        // Autres contenus
        if (module.sentences && Array.isArray(module.sentences)) count += module.sentences.length;
        if (module.dialogues && Array.isArray(module.dialogues)) count += module.dialogues.length;
        if (module.phrases && Array.isArray(module.phrases)) count += module.phrases.length;
        if (module.texts && Array.isArray(module.texts)) count += module.texts.length;
        
        return count;
    }

    extractCategories(module) {
        const categories = new Set();

        if (module.categories) {
            Object.keys(module.categories).forEach(cat => categories.add(cat));
        }

        if (module.metadata && module.metadata.categories) {
            module.metadata.categories.forEach(cat => categories.add(cat));
        }

        // Extraire des contenus si format moderne
        if (module.contentItems) {
            module.contentItems.forEach(item => {
                if (item.category) categories.add(item.category);
            });
        }

        // Extraire du vocabulaire selon le format
        if (module.vocabulary) {
            // Format simple (vocabulary object)
            if (typeof module.vocabulary === 'object' && !Array.isArray(module.vocabulary)) {
                // Pour l'instant, pas de catégories dans le format simple
                categories.add('vocabulary');
            }
            // Format legacy (vocabulary array)
            else if (Array.isArray(module.vocabulary)) {
                module.vocabulary.forEach(word => {
                    if (word.category) categories.add(word.category);
                });
            }
        }

        return Array.from(categories);
    }

    extractContentTypes(module) {
        const types = new Set();

        if (module.contentItems) {
            module.contentItems.forEach(item => {
                if (item.type) types.add(item.type);
            });
        } else {
            // Format legacy - deviner les types
            if (module.vocabulary) types.add('vocabulary');
            if (module.sentences) types.add('sentence');
            if (module.dialogues || module.dialogue) types.add('dialogue');
            if (module.phrases) types.add('sentence');
        }

        return Array.from(types);
    }

    calculateEstimatedTime(module) {
        if (module.metadata && module.metadata.estimatedTime) {
            return module.metadata.estimatedTime;
        }

        // Calcul basique : 1 minute par 3 éléments
        const itemCount = this.countItems(module);
        return Math.max(5, Math.ceil(itemCount / 3));
    }

    countByType(module, type) {
        if (module.contentItems) {
            return module.contentItems.filter(item => item.type === type).length;
        }

        // Format simple et legacy
        switch(type) {
            case 'vocabulary':
                // Format simple (vocabulary object)
                if (module.vocabulary && typeof module.vocabulary === 'object' && !Array.isArray(module.vocabulary)) {
                    return Object.keys(module.vocabulary).length;
                }
                // Format legacy (vocabulary array)
                return module.vocabulary ? module.vocabulary.length : 0;
                
            case 'sentence':
                return (module.sentences ? module.sentences.length : 0) + 
                       (module.phrases ? module.phrases.length : 0);
                       
            case 'dialogue':
                return module.dialogues ? module.dialogues.length : 0;
                
            case 'grammar':
                // Format simple (grammar object avec sous-propriétés)
                if (module.grammar && typeof module.grammar === 'object') {
                    return Object.keys(module.grammar).length;
                }
                return module.grammar && Array.isArray(module.grammar) ? module.grammar.length : 0;
                
            default:
                return 0;
        }
    }

    analyzeGameCompatibility(module) {
        const compatibility = {
            'whack-a-mole': { compatible: false, score: 0 },
            'memory-game': { compatible: false, score: 0 },
            'story-builder': { compatible: false, score: 0 },
        };

        const vocabCount = this.countByType(module, 'vocabulary');
        const sentenceCount = this.countByType(module, 'sentence');
        const dialogueCount = this.countByType(module, 'dialogue');

        // Whack-a-Mole - aime le vocabulaire et phrases simples
        if (vocabCount > 5 || sentenceCount > 3) {
            compatibility['whack-a-mole'].compatible = true;
            compatibility['whack-a-mole'].score = Math.min(100, vocabCount * 5 + sentenceCount * 3);
        }

        // Memory Game - parfait pour vocabulaire avec images
        if (vocabCount > 4) {
            compatibility['memory-game'].compatible = true;
            compatibility['memory-game'].score = Math.min(100, vocabCount * 8);
        }

        // Story Builder - aime les dialogues et séquences
        if (dialogueCount > 0 || sentenceCount > 5) {
            compatibility['story-builder'].compatible = true;
            compatibility['story-builder'].score = Math.min(100, dialogueCount * 15 + sentenceCount * 2);
        }


        return compatibility;
    }


    async loadJsonContent(filename) {
        logSh(`🔍 Chargement JSON: ${filename}`, 'INFO');

        let loaded = false;
        let lastError = null;

        // Méthode 1: Essayer distant via proxy (si configuré)
        if (this.shouldTryRemote()) {
            try {
                const result = await this.tryRemoteLoad(filename);
                if (result.success) {
                    logSh(`✅ JSON chargé depuis distant: ${filename}`, 'INFO');
                    loaded = true;
                }
            } catch (error) {
                logSh(`⚠️ Distant échoué pour ${filename}: ${error.message}`, 'WARN');
                lastError = error;
            }
        }

        // Méthode 2: Essayer local
        if (!loaded) {
            try {
                const localUrl = `js/content/${filename}`;
                const response = await fetch(localUrl);
                if (response.ok) {
                    const jsonData = await response.json();
                    const moduleName = this.jsonFilenameToModuleName(filename);

                    window.ContentModules = window.ContentModules || {};
                    window.ContentModules[moduleName] = jsonData;

                    logSh(`✅ JSON chargé depuis local: ${filename}`, 'INFO');
                    loaded = true;
                }
            } catch (error) {
                logSh(`⚠️ Local échoué pour ${filename}: ${error.message}`, 'WARN');
                lastError = error;
            }
        }

        if (!loaded) {
            throw new Error(`Impossible de charger JSON ${filename}: ${lastError?.message || 'toutes les méthodes ont échoué'}`);
        }
    }

    jsonFilenameToModuleName(src) {
        // Extraire le nom du fichier et le convertir en PascalCase compatible
        const filename = src.split('/').pop().replace('.json', '');

        // Mapping spécifique pour certains noms de fichiers
        const specialMappings = {
            'sbs-level-7-8-new': 'SBSLevel78New',
            'sbs-level-1': 'SBSLevel1',
            'english-class-demo': 'EnglishClassDemo',
            'chinese-long-story': 'ChineseLongStory',
            'french-beginner-story': 'FrenchBeginnerStory',
            'wta1b1': 'WTA1B1',
            'story-prototype-optimized': 'StoryPrototypeOptimized',
            // Ajout des modules NCE
            'nce1-lesson63-64': 'NCE1Lesson6364',
            'nce2-lesson3': 'NCE2Lesson3',
            'nce2-lesson30': 'NCE2Lesson30'
        };

        return specialMappings[filename] || this.toPascalCase(filename);
    }

    async loadScript(src) {
        return new Promise((resolve, reject) => {
            // Vérifier si déjà chargé
            const existingScript = document.querySelector(`script[src="${src}"]`);
            if (existingScript) {
                resolve();
                return;
            }

            const script = document.createElement('script');
            script.src = src;
            script.onload = resolve;
            script.onerror = () => reject(new Error(`Impossible de charger ${src}`));
            document.head.appendChild(script);
        });
    }

    // === API PUBLIQUE ===

    async getAvailableContent() {
        if (this.discoveredContent.size === 0) {
            await this.scanAllContent();
        }
        return Array.from(this.discoveredContent.values());
    }

    async getContentById(id) {
        if (this.discoveredContent.size === 0) {
            await this.scanAllContent();
        }
        return this.discoveredContent.get(id);
    }

    async getContentByGame(gameType) {
        const allContent = await this.getAvailableContent();
        
        return allContent.filter(content => {
            const compat = content.gameCompatibility[gameType];
            return compat && compat.compatible;
        }).sort((a, b) => {
            // Trier par score de compatibilité
            const scoreA = a.gameCompatibility[gameType].score;
            const scoreB = b.gameCompatibility[gameType].score;
            return scoreB - scoreA;
        });
    }

    async refreshContent() {
        this.discoveredContent.clear();
        return await this.scanAllContent();
    }

    getContentStats() {
        const stats = {
            totalModules: this.discoveredContent.size,
            totalItems: 0,
            categories: new Set(),
            contentTypes: new Set(),
            difficulties: new Set()
        };

        for (const content of this.discoveredContent.values()) {
            stats.totalItems += content.metadata.totalItems;
            content.metadata.categories.forEach(cat => stats.categories.add(cat));
            content.metadata.contentTypes.forEach(type => stats.contentTypes.add(type));
            stats.difficulties.add(content.difficulty);
        }

        return {
            ...stats,
            categories: Array.from(stats.categories),
            contentTypes: Array.from(stats.contentTypes),
            difficulties: Array.from(stats.difficulties)
        };
    }

    /**
     * Analyse les capacités d'un module ultra-modulaire
     */
    analyzeContentCapabilities(module) {
        const capabilities = {
            // Core content analysis
            hasVocabulary: this.hasContent(module, 'vocabulary'),
            hasSentences: this.hasContent(module, 'sentences'),
            hasGrammar: this.hasContent(module, 'grammar'),
            hasAudio: this.hasContent(module, 'audio'),
            hasDialogues: this.hasContent(module, 'dialogues'),
            hasPoems: this.hasContent(module, 'poems'),
            hasCulture: this.hasContent(module, 'culture'),

            // Advanced features
            hasExercises: this.hasExercises(module),
            hasMatching: this.hasContent(module, 'matching'),
            hasFillInBlanks: this.hasContent(module, 'fillInBlanks'),
            hasCorrections: this.hasContent(module, 'corrections'),
            hasComprehension: this.hasContent(module, 'comprehension'),
            hasParametricSentences: this.hasContent(module, 'parametric_sentences'),

            // Multimedia capabilities
            hasAudioFiles: this.hasAudioFiles(module),
            hasImages: this.hasImages(module),
            hasVideos: this.hasVideos(module),
            hasIPA: this.hasIPA(module),

            // Metadata richness
            hasDetailedMetadata: this.hasDetailedMetadata(module),
            hasProgressiveDifficulty: this.hasProgressiveDifficulty(module),
            hasMultipleLanguages: this.hasMultipleLanguages(module),
            hasCulturalContext: this.hasCulturalContext(module),

            // Content depth levels
            vocabularyDepth: this.analyzeVocabularyDepth(module),
            contentRichness: this.analyzeContentRichness(module)
        };

        return capabilities;
    }

    /**
     * Calcule la compatibilité avec les jeux selon les capacités
     */
    calculateGameCompatibility(capabilities) {
        const games = {
            'whack-a-mole': this.calculateWhackAMoleCompat(capabilities),
            'memory-match': this.calculateMemoryMatchCompat(capabilities),
            'quiz-game': this.calculateQuizGameCompat(capabilities),
            'fill-the-blank': this.calculateFillBlankCompat(capabilities),
            'adventure-reader': this.calculateAdventureCompat(capabilities),
            'sentence-builder': this.calculateSentenceBuilderCompat(capabilities),
            'pronunciation-game': this.calculatePronunciationCompat(capabilities),
            'culture-explorer': this.calculateCultureCompat(capabilities)
        };

        return games;
    }

    /**
     * Vérifie si un module a un type de contenu spécifique
     */
    hasContent(module, contentType) {
        const content = module[contentType];
        if (!content) return false;

        if (Array.isArray(content)) return content.length > 0;
        if (typeof content === 'object') return Object.keys(content).length > 0;
        return !!content;
    }

    /**
     * Vérifie si un module a des exercices
     */
    hasExercises(module) {
        return this.hasContent(module, 'exercises') ||
               this.hasContent(module, 'fillInBlanks') ||
               this.hasContent(module, 'corrections') ||
               this.hasContent(module, 'comprehension') ||
               this.hasContent(module, 'matching');
    }

    /**
     * Vérifie la présence de fichiers audio
     */
    hasAudioFiles(module) {
        // Vérifier dans le vocabulaire
        if (module.vocabulary) {
            for (const word of Object.values(module.vocabulary)) {
                if (typeof word === 'object' && (word.audio_file || word.audio || word.pronunciation)) {
                    return true;
                }
            }
        }

        // Vérifier dans l'audio dédié
        return this.hasContent(module, 'audio');
    }

    /**
     * Analyse la profondeur du vocabulaire (niveaux 1-6)
     */
    analyzeVocabularyDepth(module) {
        if (!module.vocabulary) return 0;

        let maxDepth = 1; // Au minimum niveau 1 (string simple)

        for (const definition of Object.values(module.vocabulary)) {
            if (typeof definition === 'object') {
                maxDepth = Math.max(maxDepth, 2); // Niveau 2: objet de base

                if (definition.examples || definition.grammar_notes) maxDepth = Math.max(maxDepth, 3);
                if (definition.etymology || definition.word_family) maxDepth = Math.max(maxDepth, 4);
                if (definition.cultural_significance) maxDepth = Math.max(maxDepth, 5);
                if (definition.memory_techniques || definition.visual_associations) maxDepth = Math.max(maxDepth, 6);
            }
        }

        return maxDepth;
    }

    /**
     * Calculs de compatibilité spécifiques par jeu
     */
    calculateWhackAMoleCompat(capabilities) {
        let score = 0;
        if (capabilities.hasVocabulary) score += 40;
        if (capabilities.hasSentences) score += 30;
        if (capabilities.hasAudioFiles) score += 20;
        if (capabilities.vocabularyDepth >= 2) score += 10;

        return { compatible: score >= 40, score, reason: 'Nécessite vocabulaire ou phrases' };
    }

    calculateMemoryMatchCompat(capabilities) {
        let score = 0;
        if (capabilities.hasVocabulary) score += 50;
        if (capabilities.hasImages) score += 30;
        if (capabilities.hasAudioFiles) score += 20;

        return { compatible: score >= 50, score, reason: 'Optimisé pour vocabulaire visuel' };
    }

    calculateQuizGameCompat(capabilities) {
        let score = 0;
        if (capabilities.hasVocabulary) score += 30;
        if (capabilities.hasGrammar) score += 25;
        if (capabilities.hasExercises) score += 45;

        return { compatible: score >= 30, score, reason: 'Fonctionne avec tout contenu' };
    }

    calculateFillBlankCompat(capabilities) {
        let score = 0;
        if (capabilities.hasFillInBlanks) score += 70;
        if (capabilities.hasSentences) score += 30;

        return { compatible: score >= 30, score, reason: 'Nécessite phrases à trous' };
    }


    calculateAdventureCompat(capabilities) {
        let score = 0;
        if (capabilities.hasDialogues) score += 60;
        if (capabilities.hasCulture) score += 30;
        if (capabilities.contentRichness >= 5) score += 10;

        return { compatible: score >= 50, score, reason: 'Nécessite dialogues riches' };
    }

    calculateSentenceBuilderCompat(capabilities) {
        let score = 0;
        if (capabilities.hasParametricSentences) score += 70;
        if (capabilities.hasSentences) score += 30;

        return { compatible: score >= 30, score, reason: 'Construit des phrases' };
    }

    calculatePronunciationCompat(capabilities) {
        let score = 0;
        if (capabilities.hasAudioFiles) score += 60;
        if (capabilities.hasIPA) score += 40;

        return { compatible: score >= 60, score, reason: 'Nécessite fichiers audio' };
    }

    calculateCultureCompat(capabilities) {
        let score = 0;
        if (capabilities.hasCulture) score += 60;
        if (capabilities.hasPoems) score += 30;
        if (capabilities.hasCulturalContext) score += 10;

        return { compatible: score >= 30, score, reason: 'Nécessite contenu culturel' };
    }

    /**
     * Analyse les capacités globales de tous les modules
     */
    analyzeGlobalCapabilities(contentList) {
        const globalStats = {
            totalCapabilities: new Set(),
            averageRichness: 0,
            recommendedGames: new Map(),
            contentGaps: []
        };

        let totalRichness = 0;

        for (const content of contentList) {
            // Compiler toutes les capacités
            Object.keys(content.capabilities).forEach(cap => {
                if (content.capabilities[cap]) globalStats.totalCapabilities.add(cap);
            });

            totalRichness += content.capabilities.contentRichness || 0;

            // Analyser la compatibilité des jeux
            Object.entries(content.compatibility || {}).forEach(([game, compat]) => {
                if (compat.compatible) {
                    const current = globalStats.recommendedGames.get(game) || { count: 0, avgScore: 0 };
                    current.count++;
                    current.avgScore = (current.avgScore + compat.score) / current.count;
                    globalStats.recommendedGames.set(game, current);
                }
            });
        }

        globalStats.averageRichness = totalRichness / contentList.length;
        globalStats.totalCapabilities = Array.from(globalStats.totalCapabilities);

        logSh(`📊 Analyse globale: ${globalStats.totalCapabilities.length} capacités, richesse moyenne: ${globalStats.averageRichness.toFixed(1)}`, 'INFO');

        return globalStats;
    }

    // Helper methods pour les analyses spécialisées
    hasImages(module) { return false; } // TODO: implémenter
    hasVideos(module) { return false; }
    hasIPA(module) { return module.vocabulary && Object.values(module.vocabulary).some(w => typeof w === 'object' && w.ipa); }
    hasDetailedMetadata(module) { return !!(module.tags && module.skills_covered && module.target_audience); }
    hasProgressiveDifficulty(module) { return !!(module.difficulty_level && typeof module.difficulty_level === 'number'); }
    hasMultipleLanguages(module) { return !!(module.original_lang && module.user_lang); }
    hasCulturalContext(module) { return this.hasContent(module, 'culture') || this.hasContent(module, 'poems'); }
    analyzeContentRichness(module) { return this.countItems(module) / 10; } // Score sur 10 basé sur le nombre d'items
}

// Export global
window.ContentScanner = ContentScanner;