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

const BASE_URL = 'http://127.0.0.1:5000';
const TIMEOUT = 120000; // 2 minutes for research to complete

// Color codes for output
const colors = {
    info: '\x1b[36m',
    success: '\x1b[32m',
    warning: '\x1b[33m',
    error: '\x1b[31m',
    section: '\x1b[34m',
    reset: '\x1b[0m'
};

function log(message, type = 'info') {
    const timestamp = new Date().toLocaleTimeString();
    console.log(`${colors[type]}[${timestamp}] ${message}${colors.reset}`);
}

async function configureSettingsForTest(page) {
    log('Configuring settings for faster test...', 'info');

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

    // Set minimal iterations and questions
    await page.evaluate(() => {
        // Set iterations to 1
        const iterationsInput = document.querySelector('input[name="app.research_iterations"]') ||
                               document.querySelector('#app\\.research_iterations');
        if (iterationsInput) {
            iterationsInput.value = '1';
            iterationsInput.dispatchEvent(new Event('change', { bubbles: true }));
        }

        // Set questions per iteration to 1
        const questionsInput = document.querySelector('input[name="app.questions_per_iteration"]') ||
                               document.querySelector('#app\\.questions_per_iteration');
        if (questionsInput) {
            questionsInput.value = '1';
            questionsInput.dispatchEvent(new Event('change', { bubbles: true }));
        }

        // Set direct mode if available
        const directModeCheckbox = document.querySelector('input[name="app.direct_mode"]') ||
                                   document.querySelector('#app\\.direct_mode');
        if (directModeCheckbox && !directModeCheckbox.checked) {
            directModeCheckbox.click();
        }
    });

    // Save settings
    const saveButton = await page.$('button[type="submit"]');
    if (saveButton) {
        await saveButton.click();
        await new Promise(r => setTimeout(r, 2000));
    }

    log('Settings configured', 'success');
}

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

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

    // Wait for research form
    await page.waitForSelector('#research-form', { visible: true });

    // Clear and type research query - use correct selector
    const queryInput = await page.$('#query') || await page.$('#research_query') || await page.$('input[name="query"]');
    if (queryInput) {
        await queryInput.click({ clickCount: 3 }); // Select all
        await queryInput.type(query);
    } else {
        throw new Error('Could not find query input field');
    }

    // Submit research
    await Promise.all([
        page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
        page.click('#start-research-btn, #submit-research, button[type="submit"]')
    ]);

    // Get research ID from URL
    const url = page.url();
    const match = url.match(/\/research\/(\d+)/);
    const researchId = match ? match[1] : null;
    log(`Research started with ID: ${researchId}`, 'success');

    // Wait for research to complete or make significant progress
    log('Waiting for research to generate metrics...', 'info');

    const startTime = Date.now();
    const maxWaitTime = 60000; // 1 minute max
    let metricsGenerated = false;

    // In CI, don't wait long for research
    while (Date.now() - startTime < 10000 && !metricsGenerated) {  // Only wait 10 seconds
        try {
            // Check research status with error handling
            const status = await page.evaluate(() => {
                const statusEl = document.querySelector('.status-text, .research-status, .status');
                const progressEl = document.querySelector('.progress-bar, .search-progress');
                const searchCount = document.querySelector('.search-count, .searches-completed');
                const tokenCount = document.querySelector('.token-count, .tokens-used');

                const statusText = statusEl ? statusEl.textContent.toLowerCase() : '';
                const hasProgress = Boolean(progressEl);
                const hasSearches = Boolean(searchCount);
                const hasTokens = Boolean(tokenCount);

                return {
                    text: statusText,
                    isComplete: statusText.includes('complet') || statusText.includes('finish'),
                    hasProgress,
                    hasSearches,
                    hasTokens,
                    hasMetrics: hasSearches || hasTokens
                };
            });

            if (status.isComplete) {
                log('Research completed!', 'success');
                metricsGenerated = true;
                break;
            }

            if (status.hasMetrics) {
                log('Research has generated some metrics', 'info');
                metricsGenerated = true;
            }

            // Log progress
            if (status.text) {
                log(`Status: ${status.text}`, 'info');
            }

        } catch {
            // Page might be reloading
        }

        await new Promise(r => setTimeout(r, 1000));  // Check more frequently
    }

    if (!metricsGenerated) {
        log('Research is still running, but proceeding to check metrics...', 'warning');
    }

    return researchId;
}

async function captureMetricsDashboard(page, timestamp) {
    log('Navigating to metrics dashboard...', 'info');

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

    // Wait for page to load
    await page.waitForSelector('body');
    await new Promise(r => setTimeout(r, 3000)); // Give time for data to load

    // Capture all metrics data
    const metricsData = await page.evaluate(() => {
        const data = {
            timestamp: new Date().toISOString(),
            url: window.location.href,
            pageTitle: document.title,
            tokenMetrics: {},
            searchMetrics: {},
            researchMetrics: {},
            chartData: {},
            rawContent: '',
            elements: {}
        };

        // Get page content
        data.rawContent = document.body.innerText.substring(0, 2000);

        // Look for token usage metrics
        const tokenElements = [
            { selector: '.total-tokens', label: 'Total Tokens' },
            { selector: '.prompt-tokens', label: 'Prompt Tokens' },
            { selector: '.completion-tokens', label: 'Completion Tokens' },
            { selector: '.token-count', label: 'Token Count' },
            { selector: '.usage-value', label: 'Usage Value' },
            { selector: '[data-metric="tokens"]', label: 'Token Metric' }
        ];

        tokenElements.forEach(({ selector, label }) => {
            const el = document.querySelector(selector);
            if (el) {
                data.tokenMetrics[label] = el.textContent.trim();
            }
        });

        // Look for search metrics
        const searchElements = [
            { selector: '.search-count', label: 'Search Count' },
            { selector: '.searches-completed', label: 'Searches Completed' },
            { selector: '.search-calls', label: 'Search Calls' },
            { selector: '[data-metric="searches"]', label: 'Search Metric' }
        ];

        searchElements.forEach(({ selector, label }) => {
            const el = document.querySelector(selector);
            if (el) {
                data.searchMetrics[label] = el.textContent.trim();
            }
        });

        // Look for metric cards or stat boxes
        const metricCards = document.querySelectorAll('.metric-card, .stat-box, .metric-item, .dashboard-card');
        metricCards.forEach(card => {
            const title = card.querySelector('.metric-title, .card-title, h3, h4, .label');
            const value = card.querySelector('.metric-value, .card-value, .value, .number, span');
            if (title && value) {
                const key = title.textContent.trim();
                const val = value.textContent.trim();
                if (key.toLowerCase().includes('token')) {
                    data.tokenMetrics[key] = val;
                } else if (key.toLowerCase().includes('search')) {
                    data.searchMetrics[key] = val;
                } else {
                    data.researchMetrics[key] = val;
                }
            }
        });

        // Look for tables with metrics
        const tables = document.querySelectorAll('table');
        tables.forEach((table, index) => {
            const headers = Array.from(table.querySelectorAll('th')).map(th => th.textContent.trim());
            const rows = Array.from(table.querySelectorAll('tbody tr')).map(tr => {
                return Array.from(tr.querySelectorAll('td')).map(td => td.textContent.trim());
            });
            if (headers.length > 0 || rows.length > 0) {
                data.chartData[`table_${index}`] = { headers, rows };
            }
        });

        // Look for canvas elements (charts)
        const canvases = document.querySelectorAll('canvas');
        data.elements.canvasCount = canvases.length;

        // Check for Chart.js
        data.elements.hasChartJS = typeof Chart !== 'undefined';

        return data;
    });

    // Log findings
    log('\n=== METRICS DASHBOARD ANALYSIS ===', 'section');

    log('\nToken Metrics Found:', 'info');
    if (Object.keys(metricsData.tokenMetrics).length > 0) {
        console.log(JSON.stringify(metricsData.tokenMetrics, null, 2));
    } else {
        log('No token metrics found', 'warning');
    }

    log('\nSearch Metrics Found:', 'info');
    if (Object.keys(metricsData.searchMetrics).length > 0) {
        console.log(JSON.stringify(metricsData.searchMetrics, null, 2));
    } else {
        log('No search metrics found', 'warning');
    }

    log('\nOther Research Metrics:', 'info');
    if (Object.keys(metricsData.researchMetrics).length > 0) {
        console.log(JSON.stringify(metricsData.researchMetrics, null, 2));
    } else {
        log('No other metrics found', 'warning');
    }

    log('\nPage Elements:', 'info');
    console.log(`- Canvas elements: ${metricsData.elements.canvasCount}`);
    console.log(`- Chart.js loaded: ${metricsData.elements.hasChartJS}`);
    console.log(`- Tables found: ${Object.keys(metricsData.chartData).length}`);

    // Show snippet of raw content
    log('\nRaw page content preview:', 'info');
    console.log(metricsData.rawContent.substring(0, 500) + '...');


    // Save full data
    const dataPath = path.join(__dirname, `metrics-full-data-${timestamp}.json`);
    await fs.writeFile(dataPath, JSON.stringify(metricsData, null, 2));
    log(`Full data saved: ${dataPath}`, 'success');

    // Determine success
    const hasTokenData = Object.keys(metricsData.tokenMetrics).length > 0;
    const hasSearchData = Object.keys(metricsData.searchMetrics).length > 0;
    const hasAnyData = hasTokenData || hasSearchData || Object.keys(metricsData.researchMetrics).length > 0;

    return { hasTokenData, hasSearchData, hasAnyData, metricsData };
}

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

    const page = await browser.newPage();
    page.setDefaultTimeout(TIMEOUT);

    // Log console errors
    page.on('console', msg => {
        if (msg.type() === 'error') {
            log(`Browser error: ${msg.text()}`, 'error');
        }
    });

    try {
        // Create test user with special characters in password
        const timestamp = Date.now();
        const username = `metrics_${timestamp}`;
        const password = `test'pass"with$pecial`;

        log('\n=== FULL METRICS FLOW TEST ===', 'section');
        log(`Username: ${username}`, 'info');
        log(`Password: ${password} (with special characters)`, 'info');

        // Step 1: Register/Login
        log('\n=== AUTHENTICATION ===', 'section');
        const auth = new AuthHelper(page, BASE_URL);
        await auth.register(username, password);

        // Step 2: Configure settings for fast test
        log('\n=== CONFIGURING SETTINGS ===', 'section');
        await configureSettingsForTest(page);

        // Step 3: Run a research
        log('\n=== RUNNING RESEARCH ===', 'section');
        const researchId = await startAndCompleteResearch(page, "What are the top 3 benefits of renewable energy?");

        // Step 4: Navigate around to ensure metrics are saved
        log('\n=== GENERATING ADDITIONAL ACTIVITY ===', 'section');

        // Visit history
        await page.goto(`${BASE_URL}/history`, { waitUntil: 'domcontentloaded' });
        log('Visited history page', 'success');
        await new Promise(r => setTimeout(r, 2000));

        // Go back to research
        if (researchId) {
            await page.goto(`${BASE_URL}/research/${researchId}`, { waitUntil: 'domcontentloaded' });
            log('Returned to research page', 'success');
            await new Promise(r => setTimeout(r, 2000));
        }

        // Step 5: Check metrics dashboard
        log('\n=== CHECKING METRICS DASHBOARD ===', 'section');
        const { hasTokenData, hasSearchData, hasAnyData } = await captureMetricsDashboard(page, timestamp);

        // Final verdict
        log('\n=== TEST RESULTS ===', 'section');
        if (hasTokenData && hasSearchData) {
            log('✅ METRICS DASHBOARD IS FULLY WORKING!', 'success');
            log('✅ Both token and search metrics are displayed', 'success');
        } else if (hasAnyData) {
            log('⚠️  METRICS DASHBOARD IS PARTIALLY WORKING', 'warning');
            log(`Token metrics: ${hasTokenData ? '✅' : '❌'}`, hasTokenData ? 'success' : 'error');
            log(`Search metrics: ${hasSearchData ? '✅' : '❌'}`, hasSearchData ? 'success' : 'error');
        } else {
            log('❌ METRICS DASHBOARD IS NOT SHOWING ANY DATA', 'error');
        }

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

    } finally {
        // Close browser properly
        await browser.close();
    }
}

// Run the test
testMetricsFullFlow().catch(console.error);
