/**
 * Puppeteer tests for SSRF protection changes.
 *
 * These tests verify that the safe_get/safe_post/SafeSession migration
 * hasn't broken any functionality. Key areas tested:
 *
 * 1. Settings page - Ollama connection checks
 * 2. News/Research - Internal API calls
 * 3. Library - Download functionality
 */

const puppeteer = require('puppeteer');
const { expect } = require('chai');

// Import shared helpers (alias takeScreenshot as screenshot for compatibility)
const {
    BASE_URL,
    HEADLESS,
    SLOW_MO,
    SCREENSHOT_DIR,
    delay,
    takeScreenshot: screenshot,
    ensureLoggedIn,
    registerUser,
    getLaunchOptions
} = require('./helpers');

// Test user credentials
const TEST_USERNAME = 'ssrf_test_user';
const TEST_PASSWORD = 'Testpassword123';

describe('SSRF Protection - Functionality Tests', function() {
    this.timeout(120000); // 2 minute timeout for UI tests

    let browser;
    let page;

    before(async () => {
        console.log(`Starting browser (headless: ${HEADLESS}, slowMo: ${SLOW_MO})`);
        console.log(`Screenshots will be saved to: ${SCREENSHOT_DIR}`);
        browser = await puppeteer.launch(getLaunchOptions());
        page = await browser.newPage();

        // Set viewport for consistent testing
        await page.setViewport({ width: 1400, height: 900 });
        page.setDefaultNavigationTimeout(30000);

        // Log console messages for debugging
        page.on('console', msg => {
            if (msg.type() === 'error') {
                console.log('Browser ERROR:', msg.text());
            }
        });

        // Log page errors
        page.on('pageerror', err => {
            console.log('Page Error:', err.message);
        });
    });

    after(async () => {
        if (browser) {
            await browser.close();
        }
    });

    // First, ensure we're logged in (try login, register if needed)
    describe('Setup - Authentication', () => {
        it('should be logged in (login or register as needed)', async () => {
            console.log('\n--- Setup: Ensure logged in ---');

            // First try to login
            let loggedIn = await ensureLoggedIn(page, TEST_USERNAME, TEST_PASSWORD);

            if (!loggedIn) {
                // Login failed, try to register
                console.log('  -> Login failed, attempting registration...');
                const registered = await registerUser(page, TEST_USERNAME, TEST_PASSWORD);

                if (registered) {
                    console.log('  -> Registration successful, now logging in...');
                    loggedIn = await ensureLoggedIn(page, TEST_USERNAME, TEST_PASSWORD);
                }
            }

            await screenshot(page, '00-after-auth');

            const url = page.url();
            console.log(`  -> Final URL: ${url}`);

            // Verify we're logged in
            expect(loggedIn).to.be.true;
            expect(url).to.not.include('/login');
        });
    });

    describe('Settings Page - Provider Checks', () => {
        it('should load the settings page without errors', async () => {
            console.log('\n--- Test: Load settings page ---');
            console.log(`Navigating to: ${BASE_URL}/settings`);

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

            const url = page.url();
            const title = await page.title();
            console.log(`Current URL: ${url}`);
            console.log(`Page title: ${title}`);

            await screenshot(page, '01-settings-page');

            // Check page loaded successfully
            expect(title).to.not.include('Error');
            expect(title).to.not.include('500');

            // Log what we see
            const bodyText = await page.$eval('body', el => el.innerText.substring(0, 500));
            console.log(`Page content preview:\n${bodyText}\n---`);

            // Either on settings page or redirected to login (which is expected without auth)
            const isSettings = url.includes('settings') || bodyText.toLowerCase().includes('settings');
            const isLogin = url.includes('login') || bodyText.toLowerCase().includes('login');

            console.log(`Is settings page: ${isSettings}, Is login page: ${isLogin}`);
            expect(isSettings || isLogin).to.be.true;
        });

        it('should check Ollama availability without crashing', async () => {
            console.log('\n--- Test: Ollama availability ---');

            await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
            await screenshot(page, '02-before-ollama-check');

            // Wait for page to settle
            await delay(2000);

            // Look for Ollama section or provider dropdown
            const ollamaSection = await page.$('[data-provider="ollama"], #ollama-settings, .ollama-config');
            console.log(`Found Ollama section element: ${ollamaSection !== null}`);

            if (ollamaSection) {
                await ollamaSection.click();
                await delay(3000);
                await screenshot(page, '02b-after-ollama-click');
            }

            // Check API endpoint directly
            const response = await page.evaluate(async (baseUrl) => {
                try {
                    const res = await fetch(`${baseUrl}/api/settings/ollama/models`);
                    const text = await res.text();
                    return { status: res.status, ok: res.ok, body: text.substring(0, 300) };
                } catch (e) {
                    return { error: e.message };
                }
            }, BASE_URL);

            console.log('Ollama models API response:', JSON.stringify(response, null, 2));
            await screenshot(page, '02c-after-ollama-api');

            expect(response.error).to.be.undefined;
        });

        it('should test Ollama connection endpoint', async () => {
            console.log('\n--- Test: Ollama connection endpoint ---');

            const response = await page.evaluate(async (baseUrl) => {
                try {
                    const res = await fetch(`${baseUrl}/api/settings/ollama/test`);
                    const text = await res.text();
                    return { status: res.status, body: text.substring(0, 500) };
                } catch (e) {
                    return { error: e.message };
                }
            }, BASE_URL);

            console.log('Ollama test endpoint response:', JSON.stringify(response, null, 2));

            expect(response.error).to.be.undefined;
            if (response.status) {
                expect(response.status).to.not.equal(500);
            }
        });

        it('should load LM Studio settings without errors', async () => {
            console.log('\n--- Test: LM Studio settings ---');

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

            const url = page.url();
            console.log(`Current URL: ${url}`);

            // Try to find LM Studio option
            const lmstudioOption = await page.$('[data-provider="lmstudio"], option[value="lmstudio"]');
            console.log(`Found LM Studio option: ${lmstudioOption !== null}`);

            if (lmstudioOption) {
                await page.select('select[name="llm.provider"]', 'lmstudio');
                await delay(2000);
                await screenshot(page, '03b-after-lmstudio-select');

                const errors = await page.$$('.error, .alert-danger');
                console.log(`Found ${errors.length} error elements`);
            }

            const bodyText = await page.$eval('body', el => el.innerText);
            expect(bodyText.toLowerCase()).to.not.include('internal server error');
        });
    });

    describe('Research Functionality', () => {
        it('should load the home/research page', async () => {
            console.log('\n--- Test: Home/research page ---');

            await page.goto(BASE_URL, { waitUntil: 'domcontentloaded' });

            const url = page.url();
            const title = await page.title();
            console.log(`Current URL: ${url}`);
            console.log(`Page title: ${title}`);

            await screenshot(page, '04-home-page');

            const bodyText = await page.$eval('body', el => el.innerText.substring(0, 500));
            console.log(`Page content preview:\n${bodyText}\n---`);

            expect(title).to.not.include('Error');

            const hasResearchContent = bodyText.toLowerCase().includes('research') ||
                                       bodyText.toLowerCase().includes('search') ||
                                       bodyText.toLowerCase().includes('query');
            expect(hasResearchContent).to.be.true;
        });

        it('should have working API endpoints', async () => {
            console.log('\n--- Test: API endpoints ---');

            const endpoints = [
                '/settings/api',
                '/api/history',
            ];

            for (const endpoint of endpoints) {
                const response = await page.evaluate(async (baseUrl, ep) => {
                    try {
                        const res = await fetch(`${baseUrl}${ep}`);
                        const text = await res.text();
                        return { endpoint: ep, status: res.status, body: text.substring(0, 200) };
                    } catch (e) {
                        return { endpoint: ep, error: e.message };
                    }
                }, BASE_URL, endpoint);

                console.log(`API ${endpoint}:`, JSON.stringify(response, null, 2));

                expect(response.error).to.be.undefined;
                expect(response.status).to.equal(200,
                    `Endpoint ${endpoint} should return 200`);
            }
        });

    });

    describe('News API Functionality', () => {
        it('should access news page without errors', async () => {
            console.log('\n--- Test: News page ---');

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

            const url = page.url();
            const title = await page.title();
            console.log(`Current URL: ${url}`);
            console.log(`Page title: ${title}`);

            await screenshot(page, '05-news-page');

            const bodyText = await page.$eval('body', el => el.innerText.substring(0, 500));
            console.log(`Page content preview:\n${bodyText}\n---`);

            expect(title).to.not.include('500');
            expect(title).to.not.include('Internal Server Error');
        });

        it('should test news API endpoints', async () => {
            console.log('\n--- Test: News API endpoints ---');

            const response = await page.evaluate(async (baseUrl) => {
                try {
                    const res = await fetch(`${baseUrl}/news/api/feed`);
                    const text = await res.text();
                    return { status: res.status, ok: res.ok, body: text.substring(0, 300) };
                } catch (e) {
                    return { error: e.message };
                }
            }, BASE_URL);

            console.log('News feed API:', JSON.stringify(response, null, 2));

            expect(response.error).to.be.undefined;
            expect(response.status).to.equal(200,
                'News feed endpoint should return 200');
        });
    });

    describe('Library/Download Functionality', () => {
        it('should access library page', async () => {
            console.log('\n--- Test: Library page ---');

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

            const url = page.url();
            const title = await page.title();
            console.log(`Current URL: ${url}`);
            console.log(`Page title: ${title}`);

            await screenshot(page, '06-library-page');

            const bodyText = await page.$eval('body', el => el.innerText.substring(0, 500));
            console.log(`Page content preview:\n${bodyText}\n---`);

            expect(title).to.not.include('500');
        });

        it('should test library API endpoints', async () => {
            console.log('\n--- Test: Library API endpoints ---');

            const endpoints = [
                '/library/api/stats',
                '/library/api/documents',
            ];

            for (const endpoint of endpoints) {
                const response = await page.evaluate(async (baseUrl, ep) => {
                    try {
                        const res = await fetch(`${baseUrl}${ep}`);
                        const text = await res.text();
                        return { endpoint: ep, status: res.status, body: text.substring(0, 200) };
                    } catch (e) {
                        return { endpoint: ep, error: e.message };
                    }
                }, BASE_URL, endpoint);

                console.log(`Library API ${endpoint}:`, JSON.stringify(response, null, 2));

                expect(response.error).to.be.undefined;
                expect(response.status).to.equal(200,
                    `Library endpoint ${endpoint} should return 200`);
            }
        });

        it('should handle download-source endpoint gracefully', async () => {
            console.log('\n--- Test: Download source endpoint ---');

            // Navigate to /library to get a fresh CSRF token from the page
            await page.goto(`${BASE_URL}/library`, { waitUntil: 'domcontentloaded' });

            const csrfToken = await page.$eval('meta[name="csrf-token"]', el => el.content).catch(() => null);
            expect(csrfToken).to.not.be.null;

            const response = await page.evaluate(async (baseUrl, csrf) => {
                try {
                    const res = await fetch(`${baseUrl}/library/api/download-source`, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRFToken': csrf
                        },
                        body: JSON.stringify({
                            url: 'https://example.com/test.pdf',
                            research_id: 'test-123'
                        })
                    });
                    const text = await res.text();
                    return { status: res.status, body: text.substring(0, 300) };
                } catch (e) {
                    return { error: e.message };
                }
            }, BASE_URL, csrfToken);

            console.log('Download-source API:', JSON.stringify(response, null, 2));

            expect(response.error).to.be.undefined;
            // With valid CSRF token, endpoint returns 404 "Resource not found" for fake research_id
            expect(response.status).to.equal(404,
                'Download endpoint should return 404 for non-existent resource');
        });
    });

    describe('Search Engine Integrations', () => {
        it('should check search configuration page loads', async () => {
            console.log('\n--- Test: Search configuration ---');

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

            const url = page.url();
            console.log(`Current URL: ${url}`);

            // Wait for settings to finish loading (spinner is in static HTML, removed after API fetch + render)
            await page.waitForFunction(
                () => !document.querySelector('.ldr-loading-spinner'),
                { timeout: 10000 }
            );
            console.log('Settings loaded (spinner gone)');

            await screenshot(page, '07-search-settings');

            // Click the Search Engines tab
            const searchTab = await page.$('[data-tab="search"]');
            expect(searchTab).to.not.be.null;
            await searchTab.click();

            // Wait for search-specific sections to render
            await page.waitForSelector('[id^="section-search-"]', { timeout: 5000 });
            const searchSections = await page.$$('[id^="section-search-"]');
            console.log(`Found search settings sections: ${searchSections.length}`);
            expect(searchSections.length).to.be.greaterThan(0);

            await screenshot(page, '07b-search-tab-active');

            const bodyText = await page.$eval('body', el => el.innerText);
            expect(bodyText.toLowerCase()).to.not.include('internal server error');
        });
    });

    describe('Error Handling', () => {
        it('should handle network errors gracefully', async () => {
            console.log('\n--- Test: Error handling ---');

            await page.goto(BASE_URL, { waitUntil: 'domcontentloaded' });

            const response = await page.evaluate(async (baseUrl) => {
                try {
                    const res = await fetch(`${baseUrl}/api/nonexistent-endpoint`);
                    const text = await res.text();
                    return { status: res.status, body: text.substring(0, 200) };
                } catch (e) {
                    return { error: e.message };
                }
            }, BASE_URL);

            console.log('Non-existent endpoint response:', JSON.stringify(response, null, 2));

            if (response.status) {
                expect(response.status).to.equal(404);
            }
        });
    });
});
