/**
 * API Key Inputs Test
 * Tests the API key input fields on the research form for cloud providers
 * CI-compatible: Works in both local and CI environments
 */

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

// API key provider configurations
const API_KEY_PROVIDERS = [
    { provider: 'OPENAI', containerId: 'openai_api_key_container', inputId: 'openai_api_key', settingKey: 'llm.openai.api_key' },
    { provider: 'ANTHROPIC', containerId: 'anthropic_api_key_container', inputId: 'anthropic_api_key', settingKey: 'llm.anthropic.api_key' },
    { provider: 'GOOGLE', containerId: 'google_api_key_container', inputId: 'google_api_key', settingKey: 'llm.google.api_key' },
    { provider: 'OPENROUTER', containerId: 'openrouter_api_key_container', inputId: 'openrouter_api_key', settingKey: 'llm.openrouter.api_key' },
    { provider: 'XAI', containerId: 'xai_api_key_container', inputId: 'xai_api_key', settingKey: 'llm.xai.api_key' },
    { provider: 'IONOS', containerId: 'ionos_api_key_container', inputId: 'ionos_api_key', settingKey: 'llm.ionos.api_key' },
    { provider: 'OPENAI_ENDPOINT', containerId: 'openai_endpoint_api_key_container', inputId: 'openai_endpoint_api_key', settingKey: 'llm.openai_endpoint.api_key' },
    { provider: 'OLLAMA', containerId: 'ollama_api_key_container', inputId: 'ollama_api_key', settingKey: 'llm.ollama.api_key' },
];

// Local providers that should NOT show API key fields (except Ollama which has optional key)
const LOCAL_PROVIDERS_NO_KEY = ['LMSTUDIO', 'LLAMACPP', 'VLLM'];

async function testApiKeyInputs() {
    const isCI = !!process.env.CI;
    console.log(`\n🧪 Running API Key Inputs test (CI mode: ${isCI})\n`);

    // Create screenshots directory if it doesn't exist
    const screenshotsDir = path.join(__dirname, 'screenshots');
    if (!fs.existsSync(screenshotsDir)) {
        fs.mkdirSync(screenshotsDir, { recursive: true });
    }

    const browser = await puppeteer.launch(getPuppeteerLaunchOptions());
    const page = await browser.newPage();
    const baseUrl = 'http://127.0.0.1:5000';

    // Increase default timeout in CI
    if (isCI) {
        page.setDefaultTimeout(60000);
        page.setDefaultNavigationTimeout(60000);
    }

    let testsPassed = 0;
    let testsFailed = 0;

    function logTest(name, passed, message = '') {
        if (passed) {
            console.log(`  ✅ ${name}${message ? ': ' + message : ''}`);
            testsPassed++;
        } else {
            console.log(`  ❌ ${name}${message ? ': ' + message : ''}`);
            testsFailed++;
        }
    }

    try {
        // Authenticate
        console.log('📋 Setup: Authenticating...');
        const authHelper = new AuthHelper(page, baseUrl);
        const testUser = {
            username: `apikey_test_${Date.now()}`,
            password: 'TestPass123!'
        };

        try {
            await authHelper.register(testUser.username, testUser.password);
            console.log('✅ Test user registered and logged in\n');
        } catch (regError) {
            try {
                await authHelper.ensureAuthenticated();
                console.log('✅ Authenticated via existing mechanism\n');
            } catch (authError) {
                console.log('❌ Cannot authenticate - skipping API key tests');
                await browser.close();
                process.exit(0);
            }
        }

        // Navigate to research page
        console.log('📄 Navigating to research page...');
        await page.goto(`${baseUrl}/`, {
            waitUntil: 'networkidle2',
            timeout: 30000
        });

        const currentUrl = page.url();
        if (currentUrl.includes('/auth/login')) {
            throw new Error('Redirected to login - not authenticated');
        }
        console.log('✅ Research page loaded\n');

        // ===== TEST GROUP 1: API Key HTML Elements Exist =====
        console.log('📋 Test Group 1: API Key HTML Elements Exist');

        for (const config of API_KEY_PROVIDERS) {
            const containerExists = await page.$(`#${config.containerId}`) !== null;
            const inputExists = await page.$(`#${config.inputId}`) !== null;
            logTest(
                `${config.provider} API key elements`,
                containerExists && inputExists,
                containerExists && inputExists ? 'container and input found' : 'missing elements'
            );
        }

        // ===== TEST GROUP 2: API Key Inputs Are Password Type =====
        console.log('\n📋 Test Group 2: API Key Inputs Are Password Type');

        for (const config of API_KEY_PROVIDERS) {
            const inputType = await page.$eval(`#${config.inputId}`, el => el.type).catch(() => null);
            logTest(
                `${config.provider} input is password type`,
                inputType === 'password',
                inputType === 'password' ? 'correctly masked' : `got type: ${inputType}`
            );
        }

        // ===== TEST GROUP 3: All API Key Containers Initially Hidden =====
        console.log('\n📋 Test Group 3: API Key Containers Initially Hidden');

        for (const config of API_KEY_PROVIDERS) {
            const displayStyle = await page.$eval(`#${config.containerId}`, el => {
                return window.getComputedStyle(el).display;
            }).catch(() => 'error');

            // Initially all should be hidden (display: none)
            logTest(
                `${config.provider} container initially hidden`,
                displayStyle === 'none',
                displayStyle === 'none' ? 'correctly hidden' : `display: ${displayStyle}`
            );
        }

        // ===== TEST GROUP 4: Ensure Advanced Options Expanded =====
        console.log('\n📋 Test Group 4: Ensure Advanced Options Expanded');

        const advancedToggle = await page.$('.ldr-advanced-options-toggle');
        if (advancedToggle) {
            // Check if panel is already expanded (default open)
            const panel = await page.$('.ldr-advanced-options-panel');
            const isAlreadyExpanded = panel ? await page.evaluate(el => {
                const style = window.getComputedStyle(el);
                return style.visibility !== 'hidden' && style.opacity !== '0';
            }, panel) : false;
            if (!isAlreadyExpanded) {
                await advancedToggle.click();
                await page.waitForTimeout(500); // Wait for animation
            }
            logTest('Advanced options expanded', true, isAlreadyExpanded ? 'already open by default' : 'expanded via click');
        } else {
            logTest('Advanced options toggle', false, 'toggle not found');
        }

        // ===== TEST GROUP 5: Provider Selection Shows Correct API Key Field =====
        console.log('\n📋 Test Group 5: Provider Selection Shows Correct API Key Field');

        const providerSelect = await page.$('#model_provider');
        if (!providerSelect) {
            logTest('Provider select', false, 'provider dropdown not found');
        } else {
            for (const config of API_KEY_PROVIDERS) {
                // Select the provider
                await page.select('#model_provider', config.provider);
                await page.waitForTimeout(300); // Wait for visibility toggle

                // Check that this provider's API key container is visible
                const isVisible = await page.$eval(`#${config.containerId}`, el => {
                    return window.getComputedStyle(el).display !== 'none';
                }).catch(() => false);

                logTest(
                    `${config.provider} shows API key field when selected`,
                    isVisible,
                    isVisible ? 'field visible' : 'field still hidden'
                );

                // Check that other API key containers are hidden
                for (const otherConfig of API_KEY_PROVIDERS) {
                    if (otherConfig.provider !== config.provider) {
                        const otherHidden = await page.$eval(`#${otherConfig.containerId}`, el => {
                            return window.getComputedStyle(el).display === 'none';
                        }).catch(() => true);

                        if (!otherHidden) {
                            logTest(
                                `${otherConfig.provider} hidden when ${config.provider} selected`,
                                false,
                                'should be hidden but is visible'
                            );
                        }
                    }
                }
            }
        }

        // ===== TEST GROUP 6: Local Providers Don't Show API Key (except Ollama) =====
        console.log('\n📋 Test Group 6: Local Providers Without API Key Fields');

        for (const localProvider of LOCAL_PROVIDERS_NO_KEY) {
            // Try to select the provider (may not exist in dropdown)
            try {
                await page.select('#model_provider', localProvider);
                await page.waitForTimeout(300);

                // Check that no cloud API key containers are visible
                let anyVisible = false;
                for (const config of API_KEY_PROVIDERS) {
                    // Skip Ollama since it has optional API key
                    if (config.provider === 'OLLAMA') continue;

                    const isVisible = await page.$eval(`#${config.containerId}`, el => {
                        return window.getComputedStyle(el).display !== 'none';
                    }).catch(() => false);

                    if (isVisible) {
                        anyVisible = true;
                        break;
                    }
                }

                logTest(
                    `${localProvider} hides cloud API key fields`,
                    !anyVisible,
                    anyVisible ? 'some API key fields visible' : 'all hidden correctly'
                );
            } catch (e) {
                // Provider may not be in the dropdown, that's OK
                console.log(`  ⏭️  ${localProvider} provider not in dropdown, skipping`);
            }
        }

        // ===== TEST GROUP 7: API Key Input Accepts Text =====
        console.log('\n📋 Test Group 7: API Key Input Accepts Text');

        // Select OpenAI provider
        await page.select('#model_provider', 'OPENAI');
        await page.waitForTimeout(300);

        const testApiKey = 'sk-test-key-12345';
        await page.type('#openai_api_key', testApiKey);

        const inputValue = await page.$eval('#openai_api_key', el => el.value);
        logTest(
            'API key input accepts text',
            inputValue === testApiKey,
            inputValue === testApiKey ? 'value stored correctly' : `got: ${inputValue}`
        );

        // ===== TEST GROUP 8: API Key Persists After Provider Switch and Back =====
        console.log('\n📋 Test Group 8: API Key Value Persistence');

        // Switch to another provider
        await page.select('#model_provider', 'ANTHROPIC');
        await page.waitForTimeout(300);

        // Switch back to OpenAI
        await page.select('#model_provider', 'OPENAI');
        await page.waitForTimeout(300);

        const persistedValue = await page.$eval('#openai_api_key', el => el.value);
        logTest(
            'API key persists after provider switch',
            persistedValue === testApiKey,
            persistedValue === testApiKey ? 'value preserved' : `got: ${persistedValue}`
        );

        // ===== TEST GROUP 9: API Key Save Handler Fires =====
        console.log('\n📋 Test Group 9: API Key Save Handler');

        // Listen for network requests to verify save
        let saveRequestFired = false;
        page.on('request', request => {
            if (request.url().includes('/settings/api/') && request.method() === 'PUT') {
                saveRequestFired = true;
            }
        });

        // Clear and type a new value, then blur to trigger save
        await page.$eval('#openai_api_key', el => el.value = '');
        await page.type('#openai_api_key', 'sk-new-test-key');
        await page.click('#model_provider'); // Click elsewhere to trigger blur/change
        await page.waitForTimeout(500);

        logTest(
            'API key save request fires on change',
            saveRequestFired,
            saveRequestFired ? 'save request detected' : 'no save request detected'
        );

        // Take a screenshot of the final state
        await page.screenshot({
            path: path.join(screenshotsDir, 'api_key_inputs_final.png'),
            fullPage: true
        });

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

        // Take error screenshot
        try {
            await page.screenshot({
                path: path.join(screenshotsDir, 'api_key_inputs_error.png'),
                fullPage: true
            });
        } catch (e) {
            // Ignore screenshot errors
        }

        testsFailed++;
    } finally {
        await browser.close();
    }

    // Summary
    console.log('\n' + '='.repeat(50));
    console.log(`📊 Test Summary: ${testsPassed} passed, ${testsFailed} failed`);
    console.log('='.repeat(50));

    if (testsFailed > 0) {
        console.log('\n❌ Some tests failed');
        process.exit(1);
    } else {
        console.log('\n✅ All tests passed!');
        process.exit(0);
    }
}

// Run the tests
testApiKeyInputs().catch(error => {
    console.error('Fatal error:', error);
    process.exit(1);
});
