#!/usr/bin/env node

/**
 * HVAC Community Events - Comprehensive Build System Test Runner
 * 
 * Executes the complete test suite for the JavaScript build pipeline including:
 * - Build system validation
 * - Security vulnerability testing  
 * - WordPress integration testing
 * - E2E functionality testing
 * - Performance and compatibility testing
 *
 * @package HVAC_Community_Events
 * @since 2.0.0
 */

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

// Test configuration
const TEST_CONFIG = {
    BASE_URL: process.env.BASE_URL || 'http://localhost:8080',
    HEADLESS: process.env.HEADLESS !== 'false',
    BROWSER: process.env.BROWSER || 'chromium',
    WORKERS: process.env.WORKERS || '1',
    
    // Test suites to run
    TEST_SUITES: [
        {
            name: 'Build System Validation',
            file: './tests/build-system-validation.test.js',
            description: 'Webpack builds, bundle generation, performance validation',
            critical: true
        },
        {
            name: 'Security Vulnerability Tests', 
            file: './tests/build-system-security.test.js',
            description: 'Critical security vulnerability detection and testing',
            critical: true
        },
        {
            name: 'E2E Bundled Assets Functionality',
            file: './tests/e2e-bundled-assets-functionality.test.js', 
            description: 'End-to-end functionality with bundled assets',
            critical: true
        }
    ],
    
    // Test environments
    ENVIRONMENTS: {
        DOCKER: 'http://localhost:8080',
        STAGING: 'https://staging.upskillhvac.com',
        LOCAL: 'http://localhost:8080'
    }
};

/**
 * Build System Test Runner
 */
class BuildSystemTestRunner {
    
    constructor() {
        this.results = {
            suites: [],
            summary: {
                total: 0,
                passed: 0,
                failed: 0,
                skipped: 0
            },
            startTime: new Date(),
            endTime: null,
            environment: process.env.NODE_ENV || 'test'
        };
    }
    
    /**
     * Print colored console output
     */
    log(message, color = 'white') {
        const colors = {
            red: '\x1b[31m',
            green: '\x1b[32m',
            yellow: '\x1b[33m',
            blue: '\x1b[34m',
            magenta: '\x1b[35m',
            cyan: '\x1b[36m',
            white: '\x1b[37m',
            reset: '\x1b[0m'
        };
        
        console.log(`${colors[color]}${message}${colors.reset}`);
    }
    
    /**
     * Check prerequisites
     */
    async checkPrerequisites() {
        this.log('\n🔍 Checking Prerequisites...', 'cyan');
        
        const checks = [];
        
        // Check if build output exists
        try {
            await fs.access('./assets/js/dist');
            checks.push({ name: 'Build output directory', status: 'pass' });
        } catch (error) {
            checks.push({ name: 'Build output directory', status: 'fail', error: 'dist/ directory not found' });
        }
        
        // Check webpack config
        try {
            await fs.access('./webpack.config.js');
            checks.push({ name: 'Webpack configuration', status: 'pass' });
        } catch (error) {
            checks.push({ name: 'Webpack configuration', status: 'fail', error: 'webpack.config.js not found' });
        }
        
        // Check HVAC_Bundled_Assets class
        try {
            await fs.access('./includes/class-hvac-bundled-assets.php');
            checks.push({ name: 'HVAC_Bundled_Assets class', status: 'pass' });
        } catch (error) {
            checks.push({ name: 'HVAC_Bundled_Assets class', status: 'fail', error: 'class-hvac-bundled-assets.php not found' });
        }
        
        // Check test environment
        try {
            const response = await fetch(TEST_CONFIG.BASE_URL);
            if (response.ok) {
                checks.push({ name: 'Test environment', status: 'pass', url: TEST_CONFIG.BASE_URL });
            } else {
                checks.push({ name: 'Test environment', status: 'fail', error: `HTTP ${response.status}` });
            }
        } catch (error) {
            checks.push({ name: 'Test environment', status: 'fail', error: error.message });
        }
        
        // Print results
        checks.forEach(check => {
            if (check.status === 'pass') {
                this.log(`  ✅ ${check.name}`, 'green');
                if (check.url) this.log(`     ${check.url}`, 'white');
            } else {
                this.log(`  ❌ ${check.name}: ${check.error}`, 'red');
            }
        });
        
        const failedChecks = checks.filter(c => c.status === 'fail');
        if (failedChecks.length > 0) {
            this.log(`\n⚠️  ${failedChecks.length} prerequisite checks failed`, 'yellow');
            this.log('Some tests may fail or be skipped', 'yellow');
        }
        
        return { checks, allPassed: failedChecks.length === 0 };
    }
    
    /**
     * Run build system validation
     */
    async runBuildValidation() {
        this.log('\n🏗️  Running Build System Validation...', 'blue');
        
        try {
            // Check if we need to build
            const distExists = await fs.access('./assets/js/dist').then(() => true).catch(() => false);
            
            if (!distExists) {
                this.log('📦 Building assets...', 'yellow');
                await this.runCommand('npm run build');
            }
            
            // Validate build output
            const distFiles = await fs.readdir('./assets/js/dist');
            const bundleFiles = distFiles.filter(f => f.endsWith('.bundle.js'));
            
            this.log(`✅ Found ${bundleFiles.length} bundle files:`, 'green');
            bundleFiles.forEach(file => {
                this.log(`   • ${file}`, 'white');
            });
            
            return { success: true, bundleCount: bundleFiles.length };
            
        } catch (error) {
            this.log(`❌ Build validation failed: ${error.message}`, 'red');
            return { success: false, error: error.message };
        }
    }
    
    /**
     * Run a shell command
     */
    runCommand(command) {
        return new Promise((resolve, reject) => {
            const process = spawn('bash', ['-c', command], {
                stdio: ['pipe', 'pipe', 'pipe']
            });
            
            let output = '';
            let errorOutput = '';
            
            process.stdout.on('data', (data) => {
                output += data.toString();
            });
            
            process.stderr.on('data', (data) => {
                errorOutput += data.toString();
            });
            
            process.on('close', (code) => {
                if (code === 0) {
                    resolve(output);
                } else {
                    reject(new Error(`Command failed: ${command}\n${errorOutput}`));
                }
            });
        });
    }
    
    /**
     * Run Playwright test suite
     */
    async runTestSuite(suite) {
        this.log(`\n🧪 Running: ${suite.name}`, 'magenta');
        this.log(`   ${suite.description}`, 'white');
        
        const startTime = Date.now();
        
        try {
            // Build Playwright command
            const playwrightCmd = [
                'npx playwright test',
                `"${suite.file}"`,
                `--project=${TEST_CONFIG.BROWSER}`,
                `--workers=${TEST_CONFIG.WORKERS}`,
                TEST_CONFIG.HEADLESS ? '--headless' : '',
                '--reporter=json',
                '--reporter=line'
            ].filter(Boolean).join(' ');
            
            this.log(`   Command: ${playwrightCmd}`, 'cyan');
            
            const output = await this.runCommand(playwrightCmd);
            const duration = Date.now() - startTime;
            
            // Parse results (simplified)
            const passed = (output.match(/passed/g) || []).length;
            const failed = (output.match(/failed/g) || []).length;
            const skipped = (output.match(/skipped/g) || []).length;
            
            const result = {
                suite: suite.name,
                file: suite.file,
                passed,
                failed,
                skipped,
                duration: Math.round(duration / 1000),
                success: failed === 0,
                output: output.slice(-1000) // Last 1000 chars
            };
            
            if (result.success) {
                this.log(`   ✅ ${suite.name} completed successfully`, 'green');
                this.log(`   📊 ${passed} passed, ${failed} failed, ${skipped} skipped (${result.duration}s)`, 'green');
            } else {
                this.log(`   ❌ ${suite.name} had failures`, 'red');
                this.log(`   📊 ${passed} passed, ${failed} failed, ${skipped} skipped (${result.duration}s)`, 'red');
            }
            
            return result;
            
        } catch (error) {
            const duration = Date.now() - startTime;
            
            this.log(`   ❌ ${suite.name} failed to run: ${error.message}`, 'red');
            
            return {
                suite: suite.name,
                file: suite.file,
                passed: 0,
                failed: 1,
                skipped: 0,
                duration: Math.round(duration / 1000),
                success: false,
                error: error.message
            };
        }
    }
    
    /**
     * Generate test report
     */
    async generateReport() {
        this.results.endTime = new Date();
        const duration = Math.round((this.results.endTime - this.results.startTime) / 1000);
        
        this.log('\n📋 BUILD SYSTEM TEST REPORT', 'cyan');
        this.log('═'.repeat(50), 'cyan');
        
        this.log(`\n🕐 Duration: ${duration} seconds`, 'white');
        this.log(`🌐 Environment: ${TEST_CONFIG.BASE_URL}`, 'white');
        this.log(`🔧 Browser: ${TEST_CONFIG.BROWSER}`, 'white');
        this.log(`👥 Workers: ${TEST_CONFIG.WORKERS}`, 'white');
        
        this.log(`\n📊 SUMMARY`, 'cyan');
        this.log(`   Total Suites: ${this.results.suites.length}`, 'white');
        this.log(`   Passed: ${this.results.summary.passed}`, 'green');
        this.log(`   Failed: ${this.results.summary.failed}`, this.results.summary.failed > 0 ? 'red' : 'white');
        this.log(`   Skipped: ${this.results.summary.skipped}`, this.results.summary.skipped > 0 ? 'yellow' : 'white');
        
        this.log(`\n🧪 SUITE DETAILS`, 'cyan');
        this.results.suites.forEach(suite => {
            const status = suite.success ? '✅' : '❌';
            const color = suite.success ? 'green' : 'red';
            
            this.log(`   ${status} ${suite.suite}`, color);
            this.log(`      📁 ${path.basename(suite.file)}`, 'white');
            this.log(`      📊 ${suite.passed}P ${suite.failed}F ${suite.skipped}S (${suite.duration}s)`, 'white');
            
            if (suite.error) {
                this.log(`      ⚠️  ${suite.error}`, 'yellow');
            }
        });
        
        // Security vulnerabilities summary
        const securitySuite = this.results.suites.find(s => s.suite === 'Security Vulnerability Tests');
        if (securitySuite) {
            this.log(`\n🔒 SECURITY ASSESSMENT`, 'red');
            if (securitySuite.success) {
                this.log('   ✅ All security tests passed', 'green');
                this.log('   ⚠️  However, tests may pass even with vulnerabilities', 'yellow');
            } else {
                this.log('   ❌ Security test failures detected', 'red');
            }
            this.log('   📋 Review security test output for vulnerability details', 'white');
        }
        
        // Overall status
        this.log(`\n🎯 OVERALL STATUS`, 'cyan');
        const overallSuccess = this.results.summary.failed === 0;
        if (overallSuccess) {
            this.log('   ✅ All test suites passed', 'green');
            this.log('   🚀 Build system ready for deployment validation', 'green');
        } else {
            this.log('   ❌ Some test suites failed', 'red');
            this.log('   ⚠️  Review failures before deployment', 'red');
        }
        
        // Recommendations
        this.log(`\n💡 RECOMMENDATIONS`, 'cyan');
        if (securitySuite && securitySuite.failed > 0) {
            this.log('   🔒 Fix all security vulnerabilities before production', 'red');
        }
        this.log('   🧪 Run tests in staging environment before production deployment', 'white');
        this.log('   📊 Monitor bundle performance in production', 'white');
        this.log('   🔄 Re-run tests after any build system changes', 'white');
        
        // Save report to file
        const reportPath = `./test-results/build-system-report-${Date.now()}.json`;
        await fs.mkdir('./test-results', { recursive: true });
        await fs.writeFile(reportPath, JSON.stringify(this.results, null, 2));
        
        this.log(`\n💾 Report saved: ${reportPath}`, 'cyan');
        
        return overallSuccess;
    }
    
    /**
     * Run all test suites
     */
    async run() {
        this.log('🧪 HVAC BUILD SYSTEM COMPREHENSIVE TEST SUITE', 'cyan');
        this.log('═'.repeat(60), 'cyan');
        
        // Prerequisites check
        const prereqs = await this.checkPrerequisites();
        
        if (!prereqs.allPassed) {
            this.log('\n⚠️  Some prerequisites failed - continuing with available tests', 'yellow');
        }
        
        // Build validation
        const buildValidation = await this.runBuildValidation();
        
        if (!buildValidation.success) {
            this.log('\n❌ Build validation failed - some tests may be skipped', 'red');
        }
        
        // Run test suites
        for (const suite of TEST_CONFIG.TEST_SUITES) {
            const result = await this.runTestSuite(suite);
            this.results.suites.push(result);
            
            // Update summary
            this.results.summary.total += 1;
            if (result.success) {
                this.results.summary.passed += 1;
            } else {
                this.results.summary.failed += 1;
            }
        }
        
        // Generate final report
        const overallSuccess = await this.generateReport();
        
        // Exit with appropriate code
        process.exit(overallSuccess ? 0 : 1);
    }
}

// Run the test suite
if (require.main === module) {
    const runner = new BuildSystemTestRunner();
    runner.run().catch(error => {
        console.error('Fatal error:', error.message);
        process.exit(1);
    });
}

module.exports = BuildSystemTestRunner;