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

// Test configuration
const TEST_TIMEOUT = 300000; // 5 minutes per test

// 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}`);
}

// Test files to run
const testFiles = [
    // Authentication tests
    'test_auth_flow.js',
    'test_simple_auth.js',

    // Core functionality tests
    'test_simple_research.js',
    'test_history_page.js',
    'test_research_details.js',
    'test_settings_persistence.js',
    'test_research_cancellation.js',

    // Settings tests
    'test_settings_page.js',
    'test_api_key_settings.js',

    // Research tests
    'test_research_form.js',
    'test_research_submit.js',

    // Navigation tests
    'test_full_navigation.js',

    // Metrics tests
    'test_simple_metrics.js',
    'test_metrics_display.js',

    // Complete workflow tests
    'test_complete_workflow.js'
];

// Test results
const results = {
    total: testFiles.length,
    passed: 0,
    failed: 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;
        }

        log(`\n${'='.repeat(60)}`, 'section');
        log(`🧪 Running test: ${testFile}`, 'test');
        log(`${'='.repeat(60)}`, 'section');

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

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

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

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

        // Set timeout
        const timeout = setTimeout(() => {
            log(`⏱️ Test timeout after ${TEST_TIMEOUT/1000} seconds`, 'error');
            testProcess.kill('SIGTERM');
        }, 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: duration,
                    output: output
                });
            } else {
                log(`❌ Test failed with code ${code} (${duration}s)`, 'error');
                results.failed++;
                results.details.push({
                    name: testFile,
                    status: 'failed',
                    duration: duration,
                    code: code,
                    output: output,
                    error: errorOutput
                });
            }

            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 ensureScreenshotsDir() {
    const screenshotsDir = path.join(__dirname, 'screenshots');
    if (!fs.existsSync(screenshotsDir)) {
        fs.mkdirSync(screenshotsDir, { recursive: true });
        log('📁 Created screenshots directory', 'info');
    }
}

async function generateReport() {
    log('\n' + '='.repeat(60), 'section');
    log('📊 TEST SUMMARY REPORT', 'section');
    log('='.repeat(60), '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(`⏭️  Skipped: ${results.skipped}`, 'warning');
    log(`📈 Success Rate: ${successRate}%`,
        successRate >= 80 ? 'success' : successRate >= 50 ? 'warning' : 'error');

    // Detailed results
    log('\n📋 Detailed Results:', 'section');
    results.details.forEach((test, index) => {
        const icon = test.status === 'passed' ? '✅' :
                     test.status === 'failed' ? '❌' : '⏭️';
        log(`\n${index + 1}. ${icon} ${test.name}`, 'info');
        if (test.duration) {
            log(`   Duration: ${test.duration}s`, 'info');
        }
        if (test.status === 'failed' && test.error) {
            log(`   Error: ${test.error}`, 'error');
        }
        if (test.status === 'skipped' && test.reason) {
            log(`   Reason: ${test.reason}`, 'warning');
        }
    });

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

    // List screenshots
    const screenshotsDir = path.join(__dirname, 'screenshots');
    if (fs.existsSync(screenshotsDir)) {
        const screenshots = fs.readdirSync(screenshotsDir);
        if (screenshots.length > 0) {
            log('\n📸 Screenshots captured:', 'section');
            screenshots.forEach(file => {
                log(`   - ${file}`, 'info');
            });
        }
    }
}

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

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

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

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

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

        req.end();
    });
}

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

    // Ensure screenshots directory exists
    await ensureScreenshotsDir();

    // 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 with: ./scripts/test_with_restart.sh', 'info');
        process.exit(1);
    }

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

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

    for (const testFile of testFiles) {
        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) {
        log('\n❌ Some tests failed. 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);
});
