/**
 * UI Test Suite Runner
 *
 * Runs all UI tests in sequence and provides a summary report.
 * This script executes each test individually and tracks pass/fail status.
 *
 * Prerequisites: Web server running on http://127.0.0.1:5000
 *
 * Usage: node tests/ui_tests/run_all_tests.js
 */

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

/** Format a Date as HH:MM:SS for log timestamps */
function ts(date = new Date()) {
    return date.toISOString().slice(11, 19);
}

/**
 * Wait for the server to be responsive before starting the next test.
 * Prevents cascade failures when a previous test stressed the server
 * (e.g., registration creating encrypted databases).
 */
async function waitForServer(maxWaitMs = 60000) {
    const startTime = Date.now();
    let delay = 1000;
    let wasDown = false;
    while (Date.now() - startTime < maxWaitMs) {
        try {
            const ok = await new Promise((resolve) => {
                const req = http.get('http://127.0.0.1:5000/api/v1/health', { timeout: 5000 }, (res) => {
                    resolve(res.statusCode >= 200 && res.statusCode < 400);
                    res.resume();
                });
                req.on('error', () => resolve(false));
                req.on('timeout', () => { req.destroy(); resolve(false); });
            });
            if (ok) {
                if (wasDown) console.log('Server recovered after being unresponsive');
                return true;
            }
            wasDown = true;
        } catch (e) {
            wasDown = true;
        }
        await new Promise(r => setTimeout(r, delay));
        delay = Math.min(delay * 2, 8000);
    }
    console.log(`Server did not respond within ${maxWaitMs/1000}s — subsequent tests may fail`);
    return false;
}

const tests = [
    // Core tests
    {
        name: 'Authentication Flow Test',
        file: 'test_auth_flow.js',
        description: 'Tests registration, login, and logout functionality'
    },
    {
        name: 'All Pages Browser Test',
        file: 'test_pages_browser.js',
        description: 'Tests all main pages for basic functionality'
    },
    {
        name: 'Error Recovery Test',
        file: 'test_error_recovery.js',
        description: 'Tests how the UI handles various error conditions gracefully'
    },
    {
        name: 'Research Workflow Test',
        file: 'test_research_workflow.js',
        description: 'Tests the complete research lifecycle from submission to results'
    },
    {
        name: 'Metrics Charts Test',
        file: 'test_metrics_charts.js',
        description: 'Tests Chart.js rendering for token and search charts'
    },
    {
        name: 'Research Results Test',
        file: 'test_research_results.js',
        description: 'Tests error handling for non-existent research and history page structure'
    },
    {
        name: 'Settings Page Test',
        file: 'test_settings_page.js',
        description: 'Tests settings page loading and API integration'
    },
    {
        name: 'Settings Error Detection Test',
        file: 'test_settings_errors.js',
        description: 'Tests error handling when changing settings'
    },
    {
        name: 'Settings Save Test',
        file: 'test_settings_save.js',
        description: 'Tests settings save workflow and validation'
    },
    {
        name: 'Star Reviews Test',
        file: 'test_star_reviews.js',
        description: 'Tests star reviews analytics page and visualizations'
    },
    {
        name: 'Rate Limiting Functionality Test',
        file: 'test_rate_limiting_settings.js',
        description: 'Tests rate limiting works on auth endpoints and static files are exempt'
    },

    // CI Test Suite - Comprehensive E2E tests
    {
        name: 'UI Functionality CI Tests',
        file: 'mobile/test_ui_functionality_ci.js',
        description: 'Tests forms, dropdowns, modals, navigation, buttons'
    },
    {
        name: 'Research Workflow CI Tests',
        file: 'test_research_workflow_ci.js',
        description: 'Tests research form, progress page, results, exports'
    },
    {
        name: 'Settings Pages CI Tests',
        file: 'test_settings_pages_ci.js',
        description: 'Tests settings tabs, navigation, provider/engine settings'
    },
    {
        name: 'Library Collections CI Tests',
        file: 'test_library_collections_ci.js',
        description: 'Tests library page, collections, document details'
    },
    {
        name: 'News Subscriptions CI Tests',
        file: 'test_news_subscriptions_ci.js',
        description: 'Tests news feeds, subscription CRUD, form validation'
    },
    {
        name: 'History Page CI Tests',
        file: 'test_history_page_ci.js',
        description: 'Tests history table, actions, search/filter'
    },
    {
        name: 'Metrics Dashboard CI Tests',
        file: 'test_metrics_dashboard_ci.js',
        description: 'Tests metrics dashboard, cost analytics, star reviews, links'
    },
    {
        name: 'Benchmark CI Tests',
        file: 'test_benchmark_ci.js',
        description: 'Tests benchmark dashboard and results pages'
    },
    {
        name: 'API Endpoints CI Tests',
        file: 'test_api_endpoints_ci.js',
        description: 'Tests all major API endpoints'
    },
    {
        name: 'CRUD Operations CI Tests',
        file: 'test_crud_operations_ci.js',
        description: 'Tests collections, subscriptions, documents CRUD'
    },
    {
        name: 'Realtime Progress CI Tests',
        file: 'test_realtime_progress_ci.js',
        description: 'Tests progress page and real-time elements'
    },
    {
        name: 'Error Handling CI Tests',
        file: 'test_error_handling_ci.js',
        description: 'Tests 404, 401, 429, validation errors'
    },
    {
        name: 'Mobile Interactions CI Tests',
        file: 'test_mobile_interactions_ci.js',
        description: 'Tests mobile modals, navigation, forms'
    },
    {
        name: 'Context Overflow CI Tests',
        file: 'test_context_overflow_ci.js',
        description: 'Tests context overflow analytics page'
    },
    {
        name: 'Follow-up Research CI Tests',
        file: 'test_followup_research_ci.js',
        description: 'Tests follow-up research flow'
    },

    // Extended CI Test Suite - Additional comprehensive tests
    {
        name: 'Auth Comprehensive CI Tests',
        file: 'test_auth_comprehensive_ci.js',
        description: 'Tests password strength, form validation, remember me, sessions'
    },
    {
        name: 'Research Form CI Tests',
        file: 'test_research_form_ci.js',
        description: 'Tests advanced options, mode toggle, dropdowns, validation'
    },
    {
        name: 'Results & Exports CI Tests',
        file: 'test_results_exports_ci.js',
        description: 'Tests star ratings, export buttons, download functionality'
    },
    {
        name: 'Library Documents CI Tests',
        file: 'test_library_documents_ci.js',
        description: 'Tests filters, views, PDF/text viewers, bulk actions'
    },
    {
        name: 'News Feed CI Tests',
        file: 'test_news_feed_ci.js',
        description: 'Tests feed, filters, templates, subscription management',
        skipCI: true,  // Intermittent 60s navigation timeouts; core coverage in test_news_subscriptions_ci.js
    },
    {
        name: 'Settings Interactions CI Tests',
        file: 'test_settings_interactions_ci.js',
        description: 'Tests tabs, search, toggles, save, raw config'
    },
    {
        name: 'Keyboard & Accessibility CI Tests',
        file: 'test_keyboard_accessibility_ci.js',
        description: 'Tests keyboard navigation, shortcuts, ARIA, focus management'
    },
    {
        name: 'Loading & Feedback CI Tests',
        file: 'test_loading_feedback_ci.js',
        description: 'Tests spinners, toasts, progress bars, hover states'
    },

    // Consolidated from critical-ui-tests.yml (validation & auth)
    {
        name: 'Register Validation Test',
        file: 'test_register_validation.js',
        description: 'Tests registration form validation without auth'
    },
    {
        name: 'Login Validation Test',
        file: 'test_login_validation.js',
        description: 'Tests login form validation'
    },
    {
        name: 'Research Submit Test',
        file: 'test_research_submit.js',
        description: 'Tests research submission'
    },
    {
        name: 'Export Functionality Test',
        file: 'test_export_functionality.js',
        description: 'Tests export features',
        skipCI: true,  // Auth hangs with "Navigating frame was detached" in Docker
    },
    {
        name: 'Concurrent Limit Test',
        file: 'test_concurrent_limit.js',
        description: 'Tests concurrent research limits',
        skipCI: true,  // Requires LLM backend — always fails without model server
    },

    // Consolidated from extended-ui-tests.yml (validation + features)
    // SKIPPED: Change Password Validation Test — /auth/change-password returns
    // server error in CI. Re-enable once the page is fixed.
    // {
    //     name: 'Change Password Validation Test',
    //     file: 'test_change_password_validation.js',
    //     description: 'Tests password change form validation'
    // },
    {
        name: 'Settings Validation Test',
        file: 'test_settings_validation.js',
        description: 'Tests settings input validation',
        skipCI: true,  // Same frame-detachment issue as Export test in Docker
    },
    {
        name: 'Research Form Validation Test',
        file: 'test_research_form_validation.js',
        description: 'Tests research form field validation',
        skipCI: true,  // Redundant with test_research_form_ci.js; auth frame-detachment in Docker
    },
    {
        name: 'Form Validation ARIA Tests',
        file: 'test_form_validation_aria_ci.js',
        description: 'Tests inline form validation with ARIA support',
        skipCI: true,  // Auth frame-detachment in Docker causes intermittent 120s timeout
    },
    {
        name: 'Research Simple Test',
        file: 'test_research_simple.js',
        description: 'Tests basic research flow',
        skipCI: true,  // Requires LLM backend to complete research submission
    },
    {
        name: 'Research Form Test',
        file: 'test_research_form.js',
        description: 'Tests research form interactions',
        skipCI: true,  // Diagnostic test — requires LLM for form submission
    },
    {
        name: 'Research API Test',
        file: 'test_research_api.js',
        description: 'Tests research API endpoints via UI',
        skipCI: true,  // Diagnostic test — requires functioning LLM API
    },
    {
        name: 'History Page Test',
        file: 'test_history_page.js',
        description: 'Tests history page functionality'
    },
    {
        name: 'Full Navigation Test',
        file: 'test_full_navigation.js',
        description: 'Tests full app navigation flow'
    },
    {
        name: 'Queue Simple Test',
        file: 'test_queue_simple.js',
        description: 'Tests research queue functionality',
        skipCI: true,  // Requires LLM backend — always fails without model server
    },

    // Consolidated from mobile-ui-tests.yml
    {
        name: 'Mobile Navigation CI Test',
        file: 'mobile/test_mobile_navigation_ci.js',
        description: 'Tests mobile navigation patterns'
    },

    // Consolidated from library-ui-tests.yml
    {
        name: 'Library Collections Page Test',
        file: 'library/test_collections_page.js',
        description: 'Tests library collections page'
    },

    // Register Full Flow runs last because it creates an encrypted SQLCipher
    // database (CPU-intensive key derivation + 58 tables + 500+ settings) which
    // can block the single-threaded CI server for 2+ minutes, causing cascade
    // failures in any tests that follow.
    {
        name: 'Register Full Flow Test',
        file: 'test_register_full_flow.js',
        description: 'Tests complete registration flow'
    }
];

async function runTest(test) {
    return new Promise((resolve) => {
        const startTime = Date.now();
        console.log(`\n[${ts()}] Running: ${test.name}`);

        const testProcess = spawn('node', [test.file], {
            cwd: path.join(__dirname),
            stdio: 'inherit',
            env: { ...process.env, NODE_OPTIONS: '--max-old-space-size=4096' }
        });

        // Add timeout for individual tests
        // 300 seconds in CI to handle slow registration/auth tests.
        // In Docker, new user registration creates encrypted SQLCipher databases
        // with key derivation + 58 tables + 500+ settings, which can take 60-120s.
        // Subsequent tests may also be slow while the server recovers.
        // 60 seconds locally for faster feedback.
        const isCI = !!process.env.CI;
        const timeoutMs = isCI ? 300000 : 60000;
        const timeout = setTimeout(() => {
            const elapsed = Math.round((Date.now() - startTime) / 1000);
            console.log(`\n⏱️ Test timeout: ${test.name} exceeded ${timeoutMs/1000} seconds (${elapsed}s elapsed)`);
            console.log(`🔪 Sending SIGTERM to PID ${testProcess.pid}...`);
            testProcess.kill('SIGTERM');
            setTimeout(() => {
                if (!testProcess.killed) {
                    console.log(`🔫 Process still alive, sending SIGKILL to PID ${testProcess.pid}...`);
                    testProcess.kill('SIGKILL');
                }
            }, 5000);
        }, timeoutMs);

        testProcess.on('close', (code) => {
            clearTimeout(timeout);
            const elapsed = Math.round((Date.now() - startTime) / 1000);
            const success = code === 0;
            console.log(`[${ts()}] ${success ? '✅' : '❌'} ${test.name}: ${success ? 'PASSED' : 'FAILED'} (${elapsed}s)`);
            if (code !== 0 && code !== null) {
                console.log(`   Exit code: ${code}`);
            }
            resolve({
                name: test.name,
                success,
                code,
                duration: elapsed
            });
        });

        testProcess.on('error', (error) => {
            clearTimeout(timeout);
            const elapsed = Math.round((Date.now() - startTime) / 1000);
            console.log(`[${ts()}] ❌ ${test.name}: ERROR - ${error.message} (${elapsed}s)`);
            resolve({
                name: test.name,
                success: false,
                error: error.message,
                duration: elapsed
            });
        });
    });
}

async function runAllTests() {
    const suiteStart = new Date();
    console.log(`[${ts(suiteStart)}] Starting UI Test Suite\n`);

    const results = [];

    const isCI = !!process.env.CI;

    for (const test of tests) {
        if (test.skipCI && isCI) {
            console.log(`\n[${ts()}] ⏭️  Skipping: ${test.name} (not supported in CI Docker)`);
            results.push({ name: test.name, success: true, duration: 0, skipped: true });
            continue;
        }
        // Ensure server is responsive before starting each test.
        // Prevents cascade failures when a previous test stressed the server.
        await waitForServer();
        const result = await runTest(test);
        results.push(result);
    }

    // Print summary
    const suiteEnd = new Date();
    const wallTime = Math.round((suiteEnd - suiteStart) / 1000);
    console.log(`\n[${ts(suiteEnd)}] TEST SUMMARY`);

    const passed = results.filter(r => r.success).length;
    const failed = results.filter(r => !r.success).length;
    const totalDuration = results.reduce((sum, r) => sum + (r.duration || 0), 0);

    // Sort by duration descending so slowest tests are easy to spot
    const sorted = [...results].sort((a, b) => (b.duration || 0) - (a.duration || 0));
    sorted.forEach(result => {
        const status = result.success ? '✅ PASS' : '❌ FAIL';
        const duration = result.duration ? ` (${result.duration}s)` : '';
        console.log(`${status} ${result.name}${duration}`);
        if (result.error) {
            console.log(`       Error: ${result.error}`);
        }
    });

    console.log(`Total: ${results.length} | Passed: ${passed} | Failed: ${failed} | Duration: ${totalDuration}s | Wall: ${wallTime}s | Rate: ${Math.round((passed / results.length) * 100)}%`);

    if (failed === 0) {
        console.log('All tests passed!');
    } else {
        console.log(`${failed} test(s) failed.`);
    }

    process.exit(failed > 0 ? 1 : 0);
}

runAllTests().catch(error => {
    console.error('💥 Test runner error:', error);
    process.exit(1);
});
