#!/usr/bin/env node
/**
 * Comprehensive Test Runner for HVAC Testing Framework 2.0
 * Orchestrates test execution with proper setup, cleanup, and reporting
 */

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

class TestRunner {
    constructor() {
        this.config = {
            environment: process.env.TEST_ENVIRONMENT || 'staging',
            parallel: process.env.PARALLEL === 'true',
            headless: process.env.HEADLESS !== 'false',
            retries: parseInt(process.env.RETRIES) || 2,
            timeout: parseInt(process.env.TIMEOUT) || 60000
        };
        
        this.results = {
            total: 0,
            passed: 0,
            failed: 0,
            skipped: 0,
            duration: 0,
            suites: []
        };
    }

    /**
     * Main test runner entry point
     */
    async run() {
        console.log('🚀 HVAC Testing Framework 2.0 - Test Runner');
        console.log(`Environment: ${this.config.environment}`);
        console.log(`Parallel: ${this.config.parallel}`);
        console.log(`Headless: ${this.config.headless}`);
        console.log('─'.repeat(60));

        try {
            await this.setupEnvironment();
            await this.runTestSuites();
            await this.generateReports();
            await this.cleanup();
            
            this.printSummary();
            process.exit(this.results.failed > 0 ? 1 : 0);
            
        } catch (error) {
            console.error('❌ Test Runner Failed:', error.message);
            process.exit(1);
        }
    }

    /**
     * Set up test environment
     */
    async setupEnvironment() {
        console.log('📋 Setting up test environment...');
        
        // Create evidence directories
        const evidenceDirs = [
            'evidence/screenshots',
            'evidence/videos', 
            'evidence/reports',
            'evidence/logs'
        ];
        
        for (const dir of evidenceDirs) {
            await fs.mkdir(dir, { recursive: true });
        }
        
        // Validate framework dependencies
        await this.validateFramework();
        
        console.log('✅ Environment setup complete');
    }

    /**
     * Validate framework dependencies
     */
    async validateFramework() {
        try {
            // Check if core framework files exist
            const coreFiles = [
                'framework/base/BasePage.js',
                'framework/base/BaseTest.js',
                'framework/browser/BrowserManager.js',
                'framework/authentication/AuthManager.js'
            ];
            
            for (const file of coreFiles) {
                const filePath = path.join(__dirname, '..', file);
                await fs.access(filePath);
            }
            
            console.log('  ✅ Framework core files validated');
            
        } catch (error) {
            throw new Error(`Framework validation failed: ${error.message}`);
        }
    }

    /**
     * Run test suites based on arguments or configuration
     */
    async runTestSuites() {
        const args = process.argv.slice(2);
        let suitesToRun = [];
        
        if (args.length === 0) {
            // Run all test suites
            suitesToRun = await this.discoverTestSuites();
        } else {
            // Run specific suites
            suitesToRun = args.map(suite => this.resolveTestSuite(suite));
        }
        
        console.log(`📊 Running ${suitesToRun.length} test suite(s):`);
        suitesToRun.forEach(suite => console.log(`  - ${suite}`));
        console.log('─'.repeat(60));
        
        for (const suite of suitesToRun) {
            await this.runSingleSuite(suite);
        }
    }

    /**
     * Discover all available test suites
     */
    async discoverTestSuites() {
        const suites = [];
        const suitesDir = path.join(__dirname, '..', 'suites');
        
        try {
            const entries = await fs.readdir(suitesDir, { withFileTypes: true });
            
            for (const entry of entries) {
                if (entry.isDirectory()) {
                    const suiteFiles = await fs.readdir(path.join(suitesDir, entry.name));
                    const testFiles = suiteFiles.filter(file => 
                        file.endsWith('.js') && 
                        (file.includes('test') || file.includes('Test'))
                    );
                    
                    for (const testFile of testFiles) {
                        suites.push(`suites/${entry.name}/${testFile}`);
                    }
                }
            }
        } catch (error) {
            console.warn(`Warning: Could not discover test suites: ${error.message}`);
        }
        
        return suites.length > 0 ? suites : ['suites/master-trainer/MasterTrainerE2E.modernized.js'];
    }

    /**
     * Resolve test suite path
     */
    resolveTestSuite(suiteName) {
        // Handle different suite name formats
        if (suiteName.includes('/') && suiteName.endsWith('.js')) {
            return suiteName; // Already a file path
        }
        
        if (suiteName === 'master-trainer' || suiteName === 'mt') {
            return 'suites/master-trainer/MasterTrainerE2E.modernized.js';
        }
        
        if (suiteName === 'security') {
            return 'suites/security/SecurityTests.js';
        }
        
        if (suiteName === 'trainer') {
            return 'suites/trainer/TrainerTests.js';
        }
        
        // Default: assume it's a file in suites directory
        return `suites/${suiteName}`;
    }

    /**
     * Run a single test suite
     */
    async runSingleSuite(suitePath) {
        const fullPath = path.join(__dirname, '..', suitePath);
        const suiteName = path.basename(suitePath, '.js');
        
        console.log(`🧪 Running test suite: ${suiteName}`);
        
        const startTime = Date.now();
        let suiteResult = {
            name: suiteName,
            path: suitePath,
            passed: 0,
            failed: 0,
            skipped: 0,
            duration: 0,
            error: null
        };
        
        try {
            // Check if file exists
            await fs.access(fullPath);
            
            // Execute the test suite
            const result = await this.executeTestFile(fullPath);
            
            suiteResult.passed = result.passed || 0;
            suiteResult.failed = result.failed || 0;
            suiteResult.skipped = result.skipped || 0;
            
        } catch (error) {
            console.error(`  ❌ Suite execution failed: ${error.message}`);
            suiteResult.failed = 1;
            suiteResult.error = error.message;
        }
        
        suiteResult.duration = Date.now() - startTime;
        
        // Update overall results
        this.results.total += suiteResult.passed + suiteResult.failed + suiteResult.skipped;
        this.results.passed += suiteResult.passed;
        this.results.failed += suiteResult.failed;
        this.results.skipped += suiteResult.skipped;
        this.results.suites.push(suiteResult);
        
        // Print suite summary
        const status = suiteResult.failed === 0 ? '✅' : '❌';
        console.log(`  ${status} ${suiteName}: ${suiteResult.passed} passed, ${suiteResult.failed} failed (${suiteResult.duration}ms)`);
    }

    /**
     * Execute a test file
     */
    async executeTestFile(filePath) {
        return new Promise((resolve, reject) => {
            const env = {
                ...process.env,
                TEST_ENVIRONMENT: this.config.environment,
                HEADLESS: this.config.headless.toString(),
                PARALLEL: this.config.parallel.toString()
            };
            
            const childProcess = spawn('node', [filePath], {
                env: env,
                stdio: 'pipe'
            });
            
            let stdout = '';
            let stderr = '';
            
            childProcess.stdout.on('data', (data) => {
                const text = data.toString();
                stdout += text;
                process.stdout.write(text);
            });
            
            childProcess.stderr.on('data', (data) => {
                const text = data.toString();
                stderr += text;
                process.stderr.write(text);
            });
            
            childProcess.on('close', (code) => {
                if (code === 0) {
                    // Parse results from stdout if available
                    const results = this.parseTestResults(stdout);
                    resolve(results);
                } else {
                    reject(new Error(`Test suite exited with code ${code}: ${stderr}`));
                }
            });
            
            childProcess.on('error', (error) => {
                reject(new Error(`Failed to start test suite: ${error.message}`));
            });
            
            // Set timeout
            setTimeout(() => {
                childProcess.kill('SIGKILL');
                reject(new Error(`Test suite timed out after ${this.config.timeout}ms`));
            }, this.config.timeout);
        });
    }

    /**
     * Parse test results from stdout
     */
    parseTestResults(stdout) {
        const results = { passed: 0, failed: 0, skipped: 0 };
        
        // Look for test completion patterns
        const passedMatches = stdout.match(/✅.*passed/gi) || [];
        const failedMatches = stdout.match(/❌.*failed/gi) || [];
        
        results.passed = passedMatches.length;
        results.failed = failedMatches.length;
        
        // If no explicit results found, assume success if no errors
        if (results.passed === 0 && results.failed === 0) {
            if (stdout.includes('completed successfully') || stdout.includes('All tests passed')) {
                results.passed = 1;
            } else if (stdout.includes('failed') || stdout.includes('error')) {
                results.failed = 1;
            } else {
                results.passed = 1; // Default to passed if no clear indication
            }
        }
        
        return results;
    }

    /**
     * Generate test reports
     */
    async generateReports() {
        console.log('📊 Generating test reports...');
        
        const reportData = {
            timestamp: new Date().toISOString(),
            environment: this.config.environment,
            configuration: this.config,
            results: this.results,
            summary: {
                totalTests: this.results.total,
                passRate: this.results.total > 0 ? ((this.results.passed / this.results.total) * 100).toFixed(2) : '0',
                duration: this.results.duration
            }
        };
        
        // Generate JSON report
        const jsonReportPath = path.join(__dirname, '..', 'evidence', 'reports', 'test-results.json');
        await fs.writeFile(jsonReportPath, JSON.stringify(reportData, null, 2));
        
        // Generate HTML report (simple)
        const htmlReport = this.generateHTMLReport(reportData);
        const htmlReportPath = path.join(__dirname, '..', 'evidence', 'reports', 'test-results.html');
        await fs.writeFile(htmlReportPath, htmlReport);
        
        console.log(`  ✅ Reports generated:`);
        console.log(`    📄 JSON: ${jsonReportPath}`);
        console.log(`    🌐 HTML: ${htmlReportPath}`);
    }

    /**
     * Generate simple HTML report
     */
    generateHTMLReport(reportData) {
        const { results, summary, timestamp, environment } = reportData;
        
        return `<!DOCTYPE html>
<html>
<head>
    <title>HVAC Testing Framework - Test Results</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .header { background: #f5f5f5; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
        .summary { display: flex; gap: 20px; margin: 20px 0; }
        .metric { background: #e8f4fd; padding: 15px; border-radius: 5px; text-align: center; }
        .metric.passed { background: #d4edda; }
        .metric.failed { background: #f8d7da; }
        .suite { border: 1px solid #ddd; margin: 10px 0; padding: 15px; border-radius: 5px; }
        .suite.passed { border-left: 5px solid #28a745; }
        .suite.failed { border-left: 5px solid #dc3545; }
    </style>
</head>
<body>
    <div class="header">
        <h1>🧪 HVAC Testing Framework - Test Results</h1>
        <p><strong>Environment:</strong> ${environment}</p>
        <p><strong>Timestamp:</strong> ${timestamp}</p>
        <p><strong>Pass Rate:</strong> ${summary.passRate}%</p>
    </div>
    
    <div class="summary">
        <div class="metric passed">
            <h3>${results.passed}</h3>
            <p>Passed</p>
        </div>
        <div class="metric failed">
            <h3>${results.failed}</h3>
            <p>Failed</p>
        </div>
        <div class="metric">
            <h3>${results.skipped}</h3>
            <p>Skipped</p>
        </div>
        <div class="metric">
            <h3>${results.total}</h3>
            <p>Total</p>
        </div>
    </div>
    
    <h2>📋 Test Suites</h2>
    ${results.suites.map(suite => `
        <div class="suite ${suite.failed === 0 ? 'passed' : 'failed'}">
            <h3>${suite.name}</h3>
            <p><strong>Path:</strong> ${suite.path}</p>
            <p><strong>Results:</strong> ${suite.passed} passed, ${suite.failed} failed, ${suite.skipped} skipped</p>
            <p><strong>Duration:</strong> ${suite.duration}ms</p>
            ${suite.error ? `<p><strong>Error:</strong> ${suite.error}</p>` : ''}
        </div>
    `).join('')}
    
    <footer style="margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; text-align: center; color: #666;">
        <p>Generated by HVAC Testing Framework 2.0</p>
    </footer>
</body>
</html>`;
    }

    /**
     * Clean up test environment
     */
    async cleanup() {
        console.log('🧹 Cleaning up...');
        
        // Clean up temporary files if needed
        // Keep evidence for analysis
        
        console.log('✅ Cleanup complete');
    }

    /**
     * Print final test summary
     */
    printSummary() {
        console.log('─'.repeat(60));
        console.log('📊 TEST SUMMARY');
        console.log('─'.repeat(60));
        console.log(`Environment: ${this.config.environment}`);
        console.log(`Total Tests: ${this.results.total}`);
        console.log(`✅ Passed: ${this.results.passed}`);
        console.log(`❌ Failed: ${this.results.failed}`);
        console.log(`⏭️  Skipped: ${this.results.skipped}`);
        
        if (this.results.total > 0) {
            const passRate = ((this.results.passed / this.results.total) * 100).toFixed(2);
            console.log(`📈 Pass Rate: ${passRate}%`);
        }
        
        console.log('─'.repeat(60));
        
        if (this.results.failed === 0) {
            console.log('🎉 ALL TESTS PASSED!');
        } else {
            console.log('💥 SOME TESTS FAILED');
            console.log('📄 Check reports in evidence/reports/ for details');
        }
    }
}

// Run the test runner if this file is executed directly
if (require.main === module) {
    const runner = new TestRunner();
    runner.run().catch(error => {
        console.error('Fatal error:', error);
        process.exit(1);
    });
}

module.exports = TestRunner;