const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');

// Test configuration
const TEST_TIMEOUT = 120000; // 2 minutes per test (reduced for faster execution)

// Colors for console output
const colors = {
    reset: '\x1b[0m',
    bright: '\x1b[1m',
    green: '\x1b[32m',
    red: '\x1b[31m',
    yellow: '\x1b[33m',
    blue: '\x1b[34m',
    cyan: '\x1b[36m',
    magenta: '\x1b[35m'
};

function log(message, type = 'info') {
    const timestamp = new Date().toISOString().split('T')[1].split('.')[0];
    const typeColors = {
        'info': colors.cyan,
        'success': colors.green,
        'error': colors.red,
        'warning': colors.yellow,
        'section': colors.blue,
        'test': colors.magenta
    };
    const color = typeColors[type] || colors.reset;
    console.log(`${color}[${timestamp}] ${message}${colors.reset}`);
}

// Get all test files dynamically
function getAllTestFiles() {
    const testDir = __dirname;
    const files = fs.readdirSync(testDir);

    return files.filter(file => {
        // Include files that start with 'test_' and end with '.js'
        if (!file.startsWith('test_') || !file.endsWith('.js')) {
            return false;
        }

        // Exclude our comprehensive test files
        const excludeFiles = [
            'test_api_key_comprehensive.js', // Already know this has issues
            'test_settings_simple.js' // Debug file
        ];

        return !excludeFiles.includes(file);
    }).sort();
}

// Test results
const results = {
    total: 0,
    passed: 0,
    failed: 0,
    timeout: 0,
    skipped: 0,
    details: []
};

async function runTest(testFile) {
    return new Promise((resolve) => {
        const testPath = path.join(__dirname, testFile);

        // Check if test file exists
        if (!fs.existsSync(testPath)) {
            log(`⚠️ Test file not found: ${testFile}`, 'warning');
            results.skipped++;
            results.details.push({
                name: testFile,
                status: 'skipped',
                reason: 'File not found'
            });
            resolve();
            return;
        }

        const startTime = Date.now();
        const testProcess = spawn('node', [testPath], {
            cwd: __dirname,
            env: { ...process.env, NODE_ENV: 'test', HEADLESS: 'true' }
        });

        let output = '';
        let errorOutput = '';
        let hasOutput = false;

        // Capture stdout
        testProcess.stdout.on('data', (data) => {
            const text = data.toString();
            output += text;
            hasOutput = true;

            // Only show first 100 chars of output
            const preview = text.substring(0, 100);
            if (preview.length < text.length) {
                process.stdout.write(preview + '...\n');
            } else {
                process.stdout.write(preview);
            }
        });

        // Capture stderr
        testProcess.stderr.on('data', (data) => {
            const text = data.toString();
            errorOutput += text;

            // Show error output
            if (text.length > 100) {
                process.stderr.write(text.substring(0, 100) + '...\n');
            } else {
                process.stderr.write(text);
            }
        });

        // Set timeout
        const timeout = setTimeout(() => {
            log(`⏱️ Test timeout after ${TEST_TIMEOUT/1000} seconds`, 'error');
            testProcess.kill('SIGTERM');
            results.timeout++;
            results.details.push({
                name: testFile,
                status: 'timeout',
                duration: TEST_TIMEOUT/1000,
                output: output.substring(0, 500),
                error: errorOutput.substring(0, 500)
            });
            resolve();
        }, TEST_TIMEOUT);

        // Handle test completion
        testProcess.on('close', (code) => {
            clearTimeout(timeout);
            const duration = ((Date.now() - startTime) / 1000).toFixed(2);

            if (code === 0) {
                log(`✅ Test passed (${duration}s)`, 'success');
                results.passed++;
                results.details.push({
                    name: testFile,
                    status: 'passed',
                    duration
                });
            } else if (code !== null) {
                log(`❌ Test failed with code ${code} (${duration}s)`, 'error');
                results.failed++;
                results.details.push({
                    name: testFile,
                    status: 'failed',
                    duration,
                    code,
                    output: output.substring(0, 500),
                    error: errorOutput.substring(0, 500)
                });
            }

            resolve();
        });

        // Handle errors
        testProcess.on('error', (error) => {
            clearTimeout(timeout);
            log(`❌ Failed to run test: ${error.message}`, 'error');
            results.failed++;
            results.details.push({
                name: testFile,
                status: 'failed',
                error: error.message
            });
            resolve();
        });
    });
}

async function generateReport() {
    log('\n' + '='.repeat(80), 'section');
    log('📊 COMPREHENSIVE TEST SUMMARY REPORT', 'section');
    log('='.repeat(80), 'section');

    const successRate = results.total > 0 ?
        ((results.passed / results.total) * 100).toFixed(1) : 0;

    log(`\nTotal Tests: ${results.total}`, 'info');
    log(`✅ Passed: ${results.passed}`, 'success');
    log(`❌ Failed: ${results.failed}`, results.failed > 0 ? 'error' : 'info');
    log(`⏱️ Timeout: ${results.timeout}`, results.timeout > 0 ? 'warning' : 'info');
    log(`⏭️  Skipped: ${results.skipped}`, 'warning');
    log(`📈 Success Rate: ${successRate}%`,
        successRate >= 80 ? 'success' : successRate >= 50 ? 'warning' : 'error');

    // Group results by status
    const passed = results.details.filter(t => t.status === 'passed');
    const failed = results.details.filter(t => t.status === 'failed');
    const timeout = results.details.filter(t => t.status === 'timeout');
    const skipped = results.details.filter(t => t.status === 'skipped');

    // Show passed tests
    if (passed.length > 0) {
        log('\n✅ PASSED TESTS:', 'success');
        passed.forEach(test => {
            log(`   ${test.name} (${test.duration}s)`, 'info');
        });
    }

    // Show failed tests
    if (failed.length > 0) {
        log('\n❌ FAILED TESTS:', 'error');
        failed.forEach(test => {
            log(`   ${test.name} (${test.duration}s) - Exit code: ${test.code || 'N/A'}`, 'error');
            if (test.error) {
                log(`      Error: ${test.error.substring(0, 100)}...`, 'error');
            }
        });
    }

    // Show timeout tests
    if (timeout.length > 0) {
        log('\n⏱️ TIMEOUT TESTS:', 'warning');
        timeout.forEach(test => {
            log(`   ${test.name}`, 'warning');
        });
    }

    // Show skipped tests
    if (skipped.length > 0) {
        log('\n⏭️ SKIPPED TESTS:', 'warning');
        skipped.forEach(test => {
            log(`   ${test.name} - ${test.reason}`, 'warning');
        });
    }

    // Save report to file
    const reportPath = path.join(__dirname, 'comprehensive_test_report.json');
    fs.writeFileSync(reportPath, JSON.stringify(results, null, 2));
    log(`\n💾 Test report saved to: ${reportPath}`, 'info');
}

async function checkServerRunning() {
    const http = require('http');

    return new Promise((resolve) => {
        const options = {
            hostname: '127.0.0.1',
            port: 5000,
            path: '/',
            method: 'GET',
            timeout: 5000
        };

        const req = http.request(options, (res) => {
            resolve(res.statusCode === 200 || res.statusCode === 302 || res.statusCode === 404);
        });

        req.on('error', () => {
            resolve(false);
        });

        req.on('timeout', () => {
            req.destroy();
            resolve(false);
        });

        req.end();
    });
}

async function runAllTests() {
    log('🚀 Starting LDR COMPREHENSIVE UI Test Suite', 'section');
    log(`📅 Date: ${new Date().toLocaleString()}`, 'info');

    // Check if server is running
    log('\n🔍 Checking if LDR server is running...', 'info');
    const serverRunning = await checkServerRunning();

    if (!serverRunning) {
        log('❌ LDR server is not running on http://127.0.0.1:5000', 'error');
        log('💡 Please start the server first', 'info');
        process.exit(1);
    }

    log('✅ Server is running', 'success');

    // Get all test files
    const testFiles = getAllTestFiles();
    results.total = testFiles.length;

    log(`\n📋 Found ${testFiles.length} test files to run`, 'info');
    log('Note: Tests will run with reduced output to prevent log overflow\n', 'info');

    // Run tests sequentially
    const startTime = Date.now();

    for (let i = 0; i < testFiles.length; i++) {
        const testFile = testFiles[i];
        log(`\n[${i + 1}/${testFiles.length}] 🧪 Running: ${testFile}`, 'test');
        await runTest(testFile);
    }

    const totalDuration = ((Date.now() - startTime) / 1000).toFixed(2);
    log(`\n⏱️ Total test duration: ${totalDuration}s`, 'info');

    // Generate report
    await generateReport();

    // Exit with appropriate code
    if (results.failed > 0 || results.timeout > 0) {
        log('\n❌ Some tests failed or timed out. Please check the results above.', 'error');
        process.exit(1);
    } else if (results.passed === results.total) {
        log('\n🎉 All tests passed!', 'success');
        process.exit(0);
    } else {
        log('\n⚠️ Some tests were skipped. Please check the results above.', 'warning');
        process.exit(0);
    }
}

// Handle interruptions gracefully
process.on('SIGINT', () => {
    log('\n\n🛑 Test suite interrupted by user', 'warning');
    generateReport().then(() => {
        process.exit(1);
    });
});

// Run all tests
runAllTests().catch(error => {
    log(`\n❌ Test suite error: ${error.message}`, 'error');
    process.exit(1);
});
