#!/usr/bin/env node
/**
 * Script principal pour lancer tous les tests
 * Usage: node tests/run-tests.js [options]
 */

import { spawn } from 'child_process';
import { readdir } from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Configuration
const config = {
    timeout: 30000, // 30 secondes par test
    verbose: process.argv.includes('--verbose'),
    watch: process.argv.includes('--watch'),
    coverage: process.argv.includes('--coverage'),
    pattern: process.argv.find(arg => arg.startsWith('--pattern='))?.split('=')[1] || '*',
    bail: process.argv.includes('--bail'),
    unitOnly: process.argv.includes('--unit-only'),
    integrationOnly: process.argv.includes('--integration-only')
};

// Couleurs pour les logs
const colors = {
    green: '\x1b[32m',
    red: '\x1b[31m',
    yellow: '\x1b[33m',
    blue: '\x1b[34m',
    reset: '\x1b[0m',
    bold: '\x1b[1m'
};

function log(message, color = 'reset') {
    console.log(`${colors[color]}${message}${colors.reset}`);
}

function logSection(title) {
    log(`\n${'='.repeat(60)}`, 'blue');
    log(`${title}`, 'bold');
    log(`${'='.repeat(60)}`, 'blue');
}

async function findTestFiles(directory, pattern = '*.test.js') {
    try {
        const files = await readdir(directory);
        return files
            .filter(file => file.endsWith('.test.js'))
            .filter(file => pattern === '*' || file.includes(pattern))
            .map(file => path.join(directory, file));
    } catch (error) {
        log(`⚠️  Impossible de lire ${directory}: ${error.message}`, 'yellow');
        return [];
    }
}

async function runTests(testFiles, description) {
    if (testFiles.length === 0) {
        log(`📁 Aucun test trouvé pour ${description}`, 'yellow');
        return { success: true, total: 0, passed: 0, failed: 0 };
    }

    logSection(`🧪 ${description} (${testFiles.length} fichiers)`);

    const args = ['--test'];

    if (config.coverage) {
        args.push('--experimental-test-coverage');
    }

    args.push(...testFiles);

    return new Promise((resolve) => {
        const nodeProcess = spawn('node', args, {
            stdio: 'pipe',
            cwd: path.resolve(__dirname, '..')
        });

        let output = '';
        let errorOutput = '';

        nodeProcess.stdout.on('data', (data) => {
            const text = data.toString();
            output += text;
            if (config.verbose) {
                process.stdout.write(text);
            }
        });

        nodeProcess.stderr.on('data', (data) => {
            const text = data.toString();
            errorOutput += text;
            if (config.verbose) {
                process.stderr.write(text);
            }
        });

        nodeProcess.on('close', (code) => {
            const success = code === 0;

            // Parser les résultats basiques
            const lines = output.split('\n');
            const summary = lines.find(line => line.includes('tests') && line.includes('passed'));

            let stats = { total: 0, passed: 0, failed: 0 };
            if (summary) {
                const match = summary.match(/(\\d+) passed.*?(\\d+) failed/);
                if (match) {
                    stats.passed = parseInt(match[1]);
                    stats.failed = parseInt(match[2]);
                    stats.total = stats.passed + stats.failed;
                }
            }

            if (success) {
                log(`✅ ${description} - Tous les tests sont passés!`, 'green');
            } else {
                log(`❌ ${description} - Des tests ont échoué`, 'red');
                if (!config.verbose && errorOutput) {
                    log('Erreurs:', 'red');
                    console.error(errorOutput);
                }
            }

            resolve({ success, ...stats, output, errorOutput });
        });

        // Timeout
        setTimeout(() => {
            nodeProcess.kill();
            log(`⏰ Timeout atteint pour ${description}`, 'yellow');
            resolve({ success: false, total: 0, passed: 0, failed: 0, timeout: true });
        }, config.timeout);
    });
}

async function checkDependencies() {
    log('🔍 Vérification des dépendances...', 'blue');

    // Vérifier que Node.js supporte --test
    const nodeVersion = process.version;
    const majorVersion = parseInt(nodeVersion.split('.')[0].slice(1));

    if (majorVersion < 18) {
        log(`❌ Node.js ${nodeVersion} ne supporte pas --test. Version minimale: 18.0.0`, 'red');
        return false;
    }

    log(`✅ Node.js ${nodeVersion} - Support des tests natif OK`, 'green');
    return true;
}

async function setupEnvironment() {
    log('🔧 Configuration de l\'environnement de test...', 'blue');

    // Variables d'environnement pour les tests
    process.env.NODE_ENV = 'test';
    process.env.TEST_VERBOSE = config.verbose ? '1' : '0';

    // Désactiver les logs en mode non-verbose
    if (!config.verbose) {
        process.env.SILENT_TESTS = '1';
    }

    log('✅ Environnement configuré', 'green');
}

function printSummary(results) {
    logSection('📊 Résumé des Tests');

    let totalTests = 0, totalPassed = 0, totalFailed = 0;
    let allSuccess = true;

    results.forEach(({ description, success, total, passed, failed }) => {
        const status = success ? '✅' : '❌';
        const stats = total > 0 ? ` (${passed}/${total})` : '';
        log(`${status} ${description}${stats}`);

        totalTests += total;
        totalPassed += passed;
        totalFailed += failed;
        allSuccess = allSuccess && success;
    });

    log('\\n' + '─'.repeat(40));
    log(`📈 Total: ${totalTests} tests`, 'bold');
    log(`✅ Réussis: ${totalPassed}`, 'green');

    if (totalFailed > 0) {
        log(`❌ Échoués: ${totalFailed}`, 'red');
    }

    const successRate = totalTests > 0 ? Math.round((totalPassed / totalTests) * 100) : 100;
    log(`📊 Taux de réussite: ${successRate}%`, successRate === 100 ? 'green' : 'yellow');

    if (allSuccess && totalTests > 0) {
        log('\\n🎉 Tous les tests sont passés!', 'green');
    } else if (totalFailed > 0) {
        log('\\n💥 Certains tests ont échoué', 'red');
    }

    return allSuccess;
}

function printUsage() {
    log('📚 Usage: node tests/run-tests.js [options]\\n', 'bold');
    log('Options disponibles:');
    log('  --verbose          Affichage détaillé des tests');
    log('  --watch            Mode surveillance (redémarre les tests si changement)');
    log('  --coverage         Rapport de couverture de code');
    log('  --pattern=PATTERN  Ne lancer que les tests contenant PATTERN');
    log('  --bail             Arrêter au premier échec');
    log('  --unit-only        Lancer seulement les tests unitaires');
    log('  --integration-only Lancer seulement les tests d\'intégration');
    log('  --help             Afficher cette aide');
}

async function main() {
    if (process.argv.includes('--help')) {
        printUsage();
        return;
    }

    logSection('🚀 Class Generator - Suite de Tests');

    // Vérifications préliminaires
    if (!(await checkDependencies())) {
        process.exit(1);
    }

    await setupEnvironment();

    const results = [];

    try {
        // Tests unitaires
        if (!config.integrationOnly) {
            const unitTestDir = path.join(__dirname, 'unit');
            const unitTests = await findTestFiles(unitTestDir, config.pattern);
            const unitResult = await runTests(unitTests, 'Tests Unitaires');
            results.push({ description: 'Tests Unitaires', ...unitResult });

            if (config.bail && !unitResult.success) {
                log('🛑 Arrêt après échec des tests unitaires (--bail)', 'red');
                process.exit(1);
            }
        }

        // Tests d'intégration
        if (!config.unitOnly) {
            const integrationTestDir = path.join(__dirname, 'integration');
            const integrationTests = await findTestFiles(integrationTestDir, config.pattern);
            const integrationResult = await runTests(integrationTests, 'Tests d\'Intégration');
            results.push({ description: 'Tests d\'Intégration', ...integrationResult });

            if (config.bail && !integrationResult.success) {
                log('🛑 Arrêt après échec des tests d\'intégration (--bail)', 'red');
                process.exit(1);
            }
        }

        // Résumé final
        const allSuccess = printSummary(results);

        // Code de sortie
        process.exit(allSuccess ? 0 : 1);

    } catch (error) {
        log(`💥 Erreur lors de l'exécution des tests: ${error.message}`, 'red');
        console.error(error);
        process.exit(1);
    }
}

// Mode watch
if (config.watch) {
    log('👀 Mode surveillance activé - Ctrl+C pour arrêter', 'yellow');
    // TODO: Implémenter la surveillance des fichiers
    log('⚠️  Mode watch non encore implémenté', 'yellow');
}

// Lancement
main().catch(error => {
    console.error('Erreur fatale:', error);
    process.exit(1);
});