#!/usr/bin/env node
/**
 * Comprehensive Mobile UI CI Test
 * Tests all pages for mobile UI issues with proper assertions
 *
 * Features:
 * - Tests all pages at multiple mobile viewports
 * - Checks for horizontal overflow, touch targets, mobile nav
 * - Verifies sheet menu shows all sections including Settings
 * - Generates JSON/JUnit reports for CI
 */

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

// Test configuration
const CONFIG = {
    baseUrl: process.env.TEST_BASE_URL || 'http://127.0.0.1:5000',
    timeout: 30000,
    outputFormat: process.env.OUTPUT_FORMAT || 'json',
};

// Mobile viewports to test
const VIEWPORTS = {
    'iPhone_SE': { width: 375, height: 667, isMobile: true, hasTouch: true },
    'iPhone_14_Pro': { width: 430, height: 932, isMobile: true, hasTouch: true },
};

// Pages to test
const PAGES = [
    { path: '/', name: 'Research', requiresAuth: true },
    { path: '/history/', name: 'History', requiresAuth: true },
    { path: '/news/', name: 'News', requiresAuth: true },
    { path: '/news/subscriptions', name: 'Subscriptions', requiresAuth: true },
    { path: '/settings/', name: 'Settings', requiresAuth: true },
    { path: '/metrics/', name: 'Metrics', requiresAuth: true },
    { path: '/benchmark/', name: 'Benchmark', requiresAuth: true },
    { path: '/settings/collections', name: 'Collections', requiresAuth: true },
    { path: '/auth/login', name: 'Login', requiresAuth: false },
];

class MobileAllPagesTest {
    constructor() {
        this.results = {
            startTime: new Date(),
            tests: [],
            summary: { total: 0, passed: 0, failed: 0 }
        };
    }

    async run() {
        console.log('🚀 Mobile UI CI Test - All Pages');
        console.log('='.repeat(50));

        let browser;
        try {
            browser = await puppeteer.launch(getPuppeteerLaunchOptions());

            for (const [deviceName, viewport] of Object.entries(VIEWPORTS)) {
                await this.testDevice(browser, deviceName, viewport);
            }

            await this.outputResults();
            process.exit(this.results.summary.failed > 0 ? 1 : 0);

        } catch (error) {
            console.error('❌ Test suite failed:', error);
            process.exit(1);
        } finally {
            if (browser) await browser.close();
        }
    }

    async testDevice(browser, deviceName, viewport) {
        console.log(`\n📱 Testing ${deviceName} (${viewport.width}x${viewport.height})`);
        console.log('─'.repeat(50));

        const page = await browser.newPage();
        await page.setViewport(viewport);

        // Authenticate
        const authHelper = new AuthHelper(page, CONFIG.baseUrl);
        try {
            await authHelper.ensureAuthenticated();
        } catch (error) {
            console.log('  ⚠️ Authentication failed, testing unauthenticated pages only');
        }

        // Test each page
        for (const pageInfo of PAGES) {
            await this.testPage(page, deviceName, pageInfo);
        }

        // Test sheet menu specifically
        await this.testSheetMenu(page, deviceName);

        await page.close();
    }

    async testPage(page, deviceName, pageInfo) {
        const testName = `${deviceName}/${pageInfo.name}`;
        const startTime = Date.now();

        try {
            await page.goto(CONFIG.baseUrl + pageInfo.path, {
                waitUntil: 'domcontentloaded',
                timeout: CONFIG.timeout
            });

            // Wait for mobile nav to initialize
            await new Promise(resolve => setTimeout(resolve, 1000));

            // Run all checks
            const checks = await page.evaluate(() => {
                const results = {
                    horizontalOverflow: false,
                    mobileNavExists: false,
                    mobileNavVisible: false,
                    sidebarHidden: true,
                    smallTouchTargets: 0,
                    errors: []
                };

                // Check horizontal overflow
                if (document.body.scrollWidth > window.innerWidth + 5) {
                    results.horizontalOverflow = true;
                    results.errors.push(`Horizontal overflow: ${document.body.scrollWidth}px > ${window.innerWidth}px`);
                }

                // Check mobile nav
                const mobileNav = document.querySelector('.ldr-mobile-bottom-nav');
                results.mobileNavExists = !!mobileNav;
                if (mobileNav) {
                    const style = window.getComputedStyle(mobileNav);
                    results.mobileNavVisible = style.display !== 'none' &&
                        mobileNav.classList.contains('visible');
                }

                // Check sidebar is hidden on mobile
                const sidebar = document.querySelector('.ldr-sidebar');
                if (sidebar) {
                    const style = window.getComputedStyle(sidebar);
                    results.sidebarHidden = style.display === 'none' ||
                        style.visibility === 'hidden';
                    if (!results.sidebarHidden && window.innerWidth <= 768) {
                        results.errors.push('Desktop sidebar visible on mobile');
                    }
                }

                // Check touch targets (only count critical ones)
                document.querySelectorAll('button:not([disabled]), a:not([disabled]), input:not([type="hidden"])').forEach(el => {
                    const rect = el.getBoundingClientRect();
                    if (rect.width > 0 && rect.height > 0 && rect.width < 40 && rect.height < 40) {
                        results.smallTouchTargets++;
                    }
                });

                return results;
            });

            // Determine test result
            let passed = true;
            const issues = [];

            if (checks.horizontalOverflow) {
                passed = false;
                issues.push('Horizontal overflow detected');
            }

            // Only check mobile nav on authenticated pages (login page won't have it)
            if (pageInfo.requiresAuth && !checks.mobileNavVisible) {
                // Check if we're actually on the page (not redirected to login)
                const currentUrl = page.url();
                if (!currentUrl.includes('/auth/')) {
                    passed = false;
                    issues.push('Mobile navigation not visible');
                }
            }

            if (!checks.sidebarHidden) {
                passed = false;
                issues.push('Desktop sidebar visible on mobile');
            }

            // Warnings (don't fail test)
            if (checks.smallTouchTargets > 10) {
                issues.push(`${checks.smallTouchTargets} small touch targets (warning)`);
            }

            this.addResult(testName, passed, issues, Date.now() - startTime);

            const status = passed ? '✅' : '❌';
            console.log(`  ${status} ${pageInfo.name} ${issues.length > 0 ? '- ' + issues.join(', ') : ''}`);

        } catch (error) {
            this.addResult(testName, false, [error.message], Date.now() - startTime);
            console.log(`  ❌ ${pageInfo.name} - Error: ${error.message}`);
        }
    }

    async testSheetMenu(page, deviceName) {
        const testName = `${deviceName}/SheetMenu`;
        const startTime = Date.now();

        try {
            // Navigate to a page with mobile nav
            await page.goto(CONFIG.baseUrl + '/news/', {
                waitUntil: 'domcontentloaded',
                timeout: CONFIG.timeout
            });
            await new Promise(resolve => setTimeout(resolve, 1000));

            // Click More button to open sheet
            const moreBtn = await page.$('.ldr-mobile-nav-tab[data-tab-id="more"]');
            if (!moreBtn) {
                this.addResult(testName, false, ['More button not found'], Date.now() - startTime);
                console.log(`  ❌ SheetMenu - More button not found`);
                return;
            }

            await moreBtn.click();
            await new Promise(resolve => setTimeout(resolve, 500));

            // Check if sheet opened and Settings section is visible
            const sheetStatus = await page.evaluate(() => {
                const sheet = document.querySelector('.ldr-mobile-sheet-menu');
                if (!sheet || !sheet.classList.contains('active')) {
                    return { opened: false, error: 'Sheet did not open' };
                }

                const sheetContent = document.querySelector('.ldr-mobile-sheet-content');
                const settingsTitle = Array.from(sheetContent?.querySelectorAll('.ldr-mobile-sheet-title') || [])
                    .find(el => el.textContent.includes('Settings'));

                if (!settingsTitle) {
                    return { opened: true, settingsVisible: false, error: 'Settings section not found' };
                }

                const titleRect = settingsTitle.getBoundingClientRect();
                const sheetRect = sheetContent.getBoundingClientRect();

                // Settings should be within the visible sheet area (or scrollable to)
                const isAccessible = titleRect.top < sheetRect.bottom + 200; // Allow some scroll

                return {
                    opened: true,
                    settingsVisible: isAccessible,
                    settingsPosition: titleRect.top,
                    sheetBottom: sheetRect.bottom
                };
            });

            if (!sheetStatus.opened) {
                this.addResult(testName, false, [sheetStatus.error], Date.now() - startTime);
                console.log(`  ❌ SheetMenu - ${sheetStatus.error}`);
            } else if (!sheetStatus.settingsVisible) {
                this.addResult(testName, false, ['Settings section cut off/not accessible'], Date.now() - startTime);
                console.log(`  ❌ SheetMenu - Settings section not accessible`);
            } else {
                this.addResult(testName, true, [], Date.now() - startTime);
                console.log(`  ✅ SheetMenu - Settings section accessible`);
            }

            // Close sheet
            const overlay = await page.$('.ldr-mobile-sheet-overlay');
            if (overlay) await overlay.click();

        } catch (error) {
            this.addResult(testName, false, [error.message], Date.now() - startTime);
            console.log(`  ❌ SheetMenu - Error: ${error.message}`);
        }
    }

    addResult(name, passed, issues, duration) {
        this.results.tests.push({
            name,
            status: passed ? 'passed' : 'failed',
            issues,
            duration: duration / 1000
        });
        this.results.summary.total++;
        this.results.summary[passed ? 'passed' : 'failed']++;
    }

    async outputResults() {
        this.results.endTime = new Date();
        this.results.duration = (this.results.endTime - this.results.startTime) / 1000;

        console.log('\n' + '='.repeat(50));
        console.log('TEST RESULTS');
        console.log('='.repeat(50));
        console.log(`Total: ${this.results.summary.total}`);
        console.log(`Passed: ${this.results.summary.passed}`);
        console.log(`Failed: ${this.results.summary.failed}`);
        console.log(`Duration: ${this.results.duration.toFixed(2)}s`);

        if (this.results.summary.failed > 0) {
            console.log('\n❌ FAILED TESTS:');
            this.results.tests.filter(t => t.status === 'failed').forEach(t => {
                console.log(`  - ${t.name}: ${t.issues.join(', ')}`);
            });
        }

        // Save results
        if (CONFIG.outputFormat === 'json') {
            await fs.writeFile('./mobile-test-results.json', JSON.stringify(this.results, null, 2));
            console.log('\n📁 Results saved to mobile-test-results.json');
        } else if (CONFIG.outputFormat === 'junit') {
            await fs.writeFile('./mobile-test-results.xml', this.toJUnit());
            console.log('\n📁 Results saved to mobile-test-results.xml');
        }
    }

    toJUnit() {
        let xml = `<?xml version="1.0" encoding="UTF-8"?>\n`;
        xml += `<testsuites name="Mobile UI Tests" tests="${this.results.summary.total}" failures="${this.results.summary.failed}" time="${this.results.duration}">\n`;
        xml += `  <testsuite name="MobileAllPages" tests="${this.results.summary.total}" failures="${this.results.summary.failed}">\n`;

        for (const test of this.results.tests) {
            xml += `    <testcase name="${test.name}" time="${test.duration}">\n`;
            if (test.status === 'failed') {
                xml += `      <failure message="${test.issues.join('; ')}">${test.issues.join('\n')}</failure>\n`;
            }
            xml += `    </testcase>\n`;
        }

        xml += `  </testsuite>\n`;
        xml += `</testsuites>`;
        return xml;
    }
}

// Run
const test = new MobileAllPagesTest();
test.run();
