const puppeteer = require('puppeteer');
const { getPuppeteerLaunchOptions } = require('./puppeteer_config');
const AuthHelper = require('./auth_helper');

// NAVIGATION NOTE: Using 'domcontentloaded' instead of 'networkidle2' for page.goto()
// because networkidle2 waits for no network activity for 500ms, but WebSocket
// connections and background polling keep the network active, causing infinite hangs.
// See: test_login_validation.js and auth_helper.js for detailed explanation.
// Test configuration
const BASE_URL = 'http://127.0.0.1:5000';

// 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'
};

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
    };
    const color = typeColors[type] || colors.reset;
    console.log(`${color}[${timestamp}] ${message}${colors.reset}`);
}

async function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function startResearch(page, query) {
    log(`🔬 Starting research: "${query}"`, 'info');

    await page.goto(`${BASE_URL}/`, { waitUntil: 'domcontentloaded' });
    await page.waitForSelector('#query', { timeout: 10000 });

    // Use longer iterations for cancellation test
    await page.evaluate(() => {
        // Try to set iterations to a higher value if the field exists
        const iterationsInput = document.querySelector('input[name="iterations"], #iterations');
        if (iterationsInput) {
            iterationsInput.value = '3';
        }
    });

    // Set query
    await page.evaluate((q) => {
        document.getElementById('query').value = q;
    }, query);

    // Submit form and wait for potential navigation or AJAX response
    const submitButton = await page.$('button[type="submit"], #submit-research, #start-research-btn');
    if (!submitButton) {
        log('❌ Submit button not found', 'error');
        return false;
    }

    // Click submit and wait for navigation to research page
    try {
        await Promise.all([
            page.waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 30000 }),
            submitButton.click()
        ]);
    } catch (e) {
        // Navigation might timeout but research could still have started
        log(`Navigation wait: ${e.message}`, 'info');
    }

    // The cancellation flow needs the research/progress page; wait for either the
    // URL to land or any progress UI to appear instead of a fixed sleep.
    await page.waitForFunction(
        () => {
            const p = window.location.pathname;
            return p.includes('/research/') ||
                   p.includes('/progress') ||
                   !!document.querySelector('.cancel-btn, .stop-btn, .progress-info, .progress-text');
        },
        { timeout: 5000 }
    ).catch(() => {});

    // Check if we're on a research page (URL-based check is safest during navigation)
    const url = page.url();
    if (url.includes('/research/') || url.includes('/progress')) {
        log('✅ Research started (page navigated)', 'success');
        return true;
    }

    return false;
}

async function testCancellation() {
    const browser = await puppeteer.launch(getPuppeteerLaunchOptions());

    const page = await browser.newPage();

    // Set console log handler
    page.on('console', msg => {
        if (msg.type() === 'error' && !msg.text().includes('favicon')) {
            log(`Browser console error: ${msg.text()}`, 'error');
        }
    });

    try {
        // Register user using AuthHelper for consistent behavior
        const auth = new AuthHelper(page, BASE_URL);
        await auth.ensureAuthenticated();

        // Navigate to home page after authentication
        await page.goto(BASE_URL, { waitUntil: 'domcontentloaded', timeout: 10000 });

        // Test 1: Cancel during early stage
        log('\n=== TEST 1: EARLY CANCELLATION ===', 'section');

        await startResearch(page, 'Complex analysis of quantum computing applications');

        // The cancel button only renders once the research starts; the waitForSelector
        // below is the real signal we need, so no settle delay is required here.

        // Find and click cancel button - use waitForSelector to ensure page is stable
        let cancelButton = null;
        try {
            cancelButton = await page.waitForSelector('.cancel-btn, .stop-btn, button[data-action="cancel"]', { timeout: 5000 });
        } catch {
            log('⚠️ No cancel button found (may not be visible yet)', 'warning');
        }

        if (cancelButton) {
            log('🛑 Clicking cancel button...', 'info');

            // Handle potential confirmation dialog
            page.once('dialog', async dialog => {
                log(`📋 Confirmation dialog: ${dialog.message()}`, 'info');
                await dialog.accept();
            });

            await cancelButton.click();
            // Poll for the server-acknowledged cancel state instead of a fixed sleep;
            // .catch(() => {}) keeps behavior identical when the page navigates away.
            await page.waitForFunction(
                () => {
                    const status = document.querySelector('.status, .research-status')?.textContent || '';
                    return /cancel|stop|suspend/i.test(status);
                },
                { timeout: 5000 }
            ).catch(() => {});

            // Check if research was cancelled - wrap in try-catch for navigation safety
            try {
                const cancelStatus = await page.evaluate(() => {
                    const statusElement = document.querySelector('.status, .research-status');
                    const progressText = document.querySelector('.progress-info, .progress-text');

                    return {
                        status: statusElement?.textContent || '',
                        progress: progressText?.textContent || '',
                        hasCancelButton: !!document.querySelector('.cancel-btn, .stop-btn')
                    };
                });

                log(`📊 Status after cancellation:`, 'info');
                log(`  - Status: ${cancelStatus.status}`, 'info');
                log(`  - Progress: ${cancelStatus.progress}`, 'info');

                if (cancelStatus.status.toLowerCase().includes('cancel') ||
                    cancelStatus.status.toLowerCase().includes('stopped') ||
                    cancelStatus.status.toLowerCase().includes('suspended')) {
                    log('✅ Research cancelled successfully', 'success');
                }
            } catch {
                // Page may have navigated after cancellation - that's OK
                log('✅ Cancellation triggered (page state changed)', 'success');
            }
        } else {
            log('⚠️ No cancel button found', 'warning');
        }

        // Test 2: Cancel during mid-stage
        log('\n=== TEST 2: MID-STAGE CANCELLATION ===', 'section');

        await startResearch(page, 'Comprehensive study of artificial intelligence ethics');

        // Wait for research to progress
        log('⏳ Waiting for research to progress...', 'info');
        await delay(10000); // Wait 10 seconds

        // Get progress before cancellation - wrap in try-catch
        let progressBefore = { percentage: '0%', text: '' };
        try {
            progressBefore = await page.evaluate(() => {
                const progressBar = document.querySelector('.progress-bar, [role="progressbar"]');
                const progressText = document.querySelector('.progress-info, .progress-text');

                return {
                    percentage: progressBar?.getAttribute('aria-valuenow') ||
                               progressBar?.style.width ||
                               progressText?.textContent || '0%',
                    text: progressText?.textContent || ''
                };
            });
        } catch {
            log('⚠️ Could not get progress (page navigating)', 'warning');
        }

        log(`📊 Progress before cancellation: ${progressBefore.percentage}`, 'info');

        // Cancel research
        let cancelButton2 = null;
        try {
            cancelButton2 = await page.waitForSelector('.cancel-btn, .stop-btn, button[data-action="cancel"]', { timeout: 5000 });
        } catch {
            log('⚠️ No cancel button found for mid-stage test', 'warning');
        }

        if (cancelButton2) {
            page.once('dialog', async dialog => {
                await dialog.accept();
            });

            await cancelButton2.click();
            // Same pattern as the early-cancel branch: wait for the cancel state to
            // surface in the UI rather than sleeping for a fixed interval.
            await page.waitForFunction(
                () => {
                    const status = document.querySelector('.status-badge, .research-status')?.textContent || '';
                    return /cancel|stop|suspend/i.test(status);
                },
                { timeout: 5000 }
            ).catch(() => {});

            try {
                const afterCancel = await page.evaluate(() => {
                    const progressText = document.querySelector('.progress-info, .progress-text');
                    const statusBadge = document.querySelector('.status-badge, .research-status');

                    return {
                        progress: progressText?.textContent || '',
                        status: statusBadge?.textContent || ''
                    };
                });

                log(`📊 After mid-stage cancellation:`, 'info');
                log(`  - Progress: ${afterCancel.progress}`, 'info');
                log(`  - Status: ${afterCancel.status}`, 'info');
            } catch {
                log('✅ Cancellation triggered (page state changed)', 'success');
            }

            log('✅ Mid-stage cancellation tested', 'success');
        }

        // Test 3: Check cancelled research in history
        log('\n=== TEST 3: CANCELLED RESEARCH IN HISTORY ===', 'section');

        await page.goto(`${BASE_URL}/history`, { waitUntil: 'domcontentloaded' });

        try {
            await page.waitForSelector('.ldr-history-container, .ldr-history-list, .history-item', { timeout: 10000 });

            const cancelledItems = await page.evaluate(() => {
                const items = [];
                const historyItems = document.querySelectorAll('.history-item');

                historyItems.forEach(item => {
                    const status = item.querySelector('.status-badge, .status')?.textContent || '';
                    const query = item.querySelector('.query-text, .research-query')?.textContent || '';

                    if (status.toLowerCase().includes('cancel') ||
                        status.toLowerCase().includes('suspended') ||
                        status.toLowerCase().includes('stopped')) {
                        items.push({
                            query: query.trim(),
                            status: status.trim()
                        });
                    }
                });

                return items;
            });

            if (cancelledItems.length > 0) {
                log(`✅ Found ${cancelledItems.length} cancelled research items in history:`, 'success');
                cancelledItems.forEach(item => {
                    log(`  - "${item.query}" - Status: ${item.status}`, 'info');
                });
            } else {
                log('⚠️ No cancelled items found in history (research may have completed too fast)', 'warning');
            }
        } catch {
            log('⚠️ Could not check history (page issue)', 'warning');
        }

        // Test 4: Attempt to resume cancelled research (if feature exists)
        log('\n=== TEST 4: RESUME FUNCTIONALITY ===', 'section');

        try {
            const resumeButtons = await page.$$('.resume-btn, button[data-action="resume"]');
            if (resumeButtons.length > 0) {
                log('📊 Resume functionality available', 'info');

                // Click first resume button
                await resumeButtons[0].click();
                // Wait for the resume to actually route to a research/progress page
                // instead of using a fixed sleep.
                await page.waitForFunction(
                    () => {
                        const p = window.location.pathname;
                        return p.includes('/research') || p.includes('/progress');
                    },
                    { timeout: 5000 }
                ).catch(() => {});

                // Check if research resumed
                const url = page.url();
                if (url.includes('/research') || url.includes('/progress')) {
                    log('✅ Resume functionality works', 'success');
                }
            } else {
                log('ℹ️ No resume functionality found (might not be implemented)', 'info');
            }
        } catch {
            log('ℹ️ Resume test skipped (page issue)', 'info');
        }

        // Test 5: Multiple cancellations
        log('\n=== TEST 5: RAPID CANCELLATION ===', 'section');

        await startResearch(page, 'Quick test for immediate cancellation');

        // The waitForSelector below already waits for the cancel button to render;
        // no extra settle delay is needed.

        try {
            const quickCancel = await page.waitForSelector('.cancel-btn, .stop-btn', { timeout: 3000 });
            if (quickCancel) {
                page.once('dialog', async dialog => {
                    await dialog.accept();
                });

                await quickCancel.click();
                log('✅ Immediate cancellation tested', 'success');
            }
        } catch {
            log('⚠️ Quick cancel button not found (research may have completed)', 'warning');
        }

        log('\n✅ Research cancellation test completed successfully!', 'success');

    } catch (error) {
        log(`\n❌ Test failed: ${error.message}`, 'error');

        throw error;
    } finally {
        await browser.close();
    }
}

// Run the test
testCancellation().catch(error => {
    console.error('Test execution failed:', error);
    process.exit(1);
});
