/**
 * Mobile & Accessibility Test Suite
 * 
 * Tests mobile responsiveness and accessibility compliance after CSS consolidation:
 * - Mobile responsiveness with reduced CSS (250+ files → 5 bundles)
 * - Touch interactions and gesture support
 * - Screen reader compatibility (WCAG 2.1 AA compliance)
 * - Keyboard navigation
 * - Color contrast and visual accessibility
 * - Progressive enhancement
 * - Viewport and orientation handling
 * 
 * @package HVAC_Community_Events
 * @version 3.0.0
 * @created 2025-08-20
 */

const { test, expect, authHelpers, devices } = require('../helpers/auth-fixtures');
const path = require('path');

// Test configuration
const BASE_URL = process.env.UPSKILL_STAGING_URL || 'https://upskill-staging.measurequick.com';
const TEST_TIMEOUT = 90000;

// Mobile device configurations
const MOBILE_DEVICES = [
    { name: 'iPhone 12', ...devices['iPhone 12'] },
    { name: 'Pixel 5', ...devices['Pixel 5'] },
    { name: 'iPad Pro', ...devices['iPad Pro'] },
    { name: 'Galaxy S21', viewport: { width: 360, height: 800 } }
];

// Accessibility test criteria (WCAG 2.1 AA)
const ACCESSIBILITY_CRITERIA = {
    colorContrast: {
        normal: 4.5,    // AA standard for normal text
        large: 3.0      // AA standard for large text (18pt+ or 14pt+ bold)
    },
    timing: {
        maxTimeout: 20000,  // 20 seconds max for any timeout
        minResponseTime: 100 // Minimum response time for interactions
    },
    navigation: {
        maxTabStops: 50,    // Reasonable number of tab stops per page
        minTouchTarget: 44  // Minimum touch target size (44x44px)
    }
};

// Test pages for mobile/accessibility testing
const TEST_PAGES = [
    '/trainer/dashboard/',
    '/trainer/profile/',
    '/trainer/events/',
    '/trainer/events/create/',
    '/trainer/certificate-reports/',
    '/find-trainer/'
];

// Helper functions
async function loginAsTrainer(page) {
    await authHelpers.loginAs(page, 'trainer');
}

async function testColorContrast(page) {
    return await page.evaluate((criteria) => {
        // Function to calculate relative luminance
        function getLuminance(r, g, b) {
            const [rs, gs, bs] = [r, g, b].map(c => {
                c = c / 255;
                return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
            });
            return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
        }

        // Function to calculate contrast ratio
        function getContrastRatio(color1, color2) {
            const lum1 = getLuminance(...color1);
            const lum2 = getLuminance(...color2);
            const brightest = Math.max(lum1, lum2);
            const darkest = Math.min(lum1, lum2);
            return (brightest + 0.05) / (darkest + 0.05);
        }

        // Function to parse RGB color
        function parseColor(colorStr) {
            const rgb = colorStr.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
            return rgb ? [parseInt(rgb[1]), parseInt(rgb[2]), parseInt(rgb[3])] : [0, 0, 0];
        }

        const textElements = document.querySelectorAll('p, span, a, button, label, h1, h2, h3, h4, h5, h6');
        const contrastIssues = [];

        textElements.forEach((element, index) => {
            if (index > 50) return; // Limit testing to first 50 elements

            const styles = window.getComputedStyle(element);
            const textColor = parseColor(styles.color);
            const backgroundColor = parseColor(styles.backgroundColor);
            
            // If background is transparent, try to find parent background
            let parentBg = backgroundColor;
            if (backgroundColor.every(c => c === 0)) {
                let parent = element.parentElement;
                while (parent && parentBg.every(c => c === 0)) {
                    const parentStyles = window.getComputedStyle(parent);
                    parentBg = parseColor(parentStyles.backgroundColor);
                    parent = parent.parentElement;
                }
                // Default to white if no background found
                if (parentBg.every(c => c === 0)) {
                    parentBg = [255, 255, 255];
                }
            }

            const contrast = getContrastRatio(textColor, parentBg);
            const fontSize = parseFloat(styles.fontSize);
            const fontWeight = styles.fontWeight;
            
            const isLargeText = fontSize >= 18 || (fontSize >= 14 && (fontWeight === 'bold' || parseInt(fontWeight) >= 700));
            const requiredContrast = isLargeText ? criteria.colorContrast.large : criteria.colorContrast.normal;
            
            if (contrast < requiredContrast) {
                contrastIssues.push({
                    element: element.tagName + (element.className ? '.' + element.className.split(' ')[0] : ''),
                    contrast: contrast.toFixed(2),
                    required: requiredContrast,
                    fontSize: fontSize,
                    isLargeText
                });
            }
        });

        return contrastIssues;
    }, ACCESSIBILITY_CRITERIA);
}

async function testKeyboardNavigation(page) {
    const navigationResults = {
        tabStops: 0,
        focusableElements: [],
        skipLinks: false,
        focusTraps: false
    };

    // Test tab navigation
    let currentElement = null;
    let tabCount = 0;
    const maxTabs = ACCESSIBILITY_CRITERIA.navigation.maxTabStops;

    while (tabCount < maxTabs) {
        await page.keyboard.press('Tab');
        tabCount++;

        const focused = await page.evaluate(() => {
            const active = document.activeElement;
            return active ? {
                tagName: active.tagName,
                type: active.type || null,
                text: active.textContent?.trim().substring(0, 50) || '',
                className: active.className || '',
                id: active.id || '',
                role: active.getAttribute('role') || null
            } : null;
        });

        if (focused) {
            navigationResults.focusableElements.push(focused);
        }

        // Break if we've cycled back to the beginning
        if (focused && JSON.stringify(focused) === JSON.stringify(currentElement)) {
            break;
        }

        if (tabCount === 1) {
            currentElement = focused;
        }
    }

    navigationResults.tabStops = tabCount;

    // Check for skip links
    await page.keyboard.press('Tab');
    const skipLink = await page.evaluate(() => {
        const active = document.activeElement;
        return active && (
            active.textContent?.toLowerCase().includes('skip') ||
            active.getAttribute('href') === '#main' ||
            active.className.includes('skip')
        );
    });

    navigationResults.skipLinks = !!skipLink;

    return navigationResults;
}

async function testTouchTargets(page) {
    return await page.evaluate((minSize) => {
        const interactive = document.querySelectorAll('button, a, input, select, textarea, [onclick], [role="button"]');
        const smallTargets = [];

        interactive.forEach(element => {
            const rect = element.getBoundingClientRect();
            if (rect.width > 0 && rect.height > 0) {
                if (rect.width < minSize || rect.height < minSize) {
                    smallTargets.push({
                        element: element.tagName + (element.className ? '.' + element.className.split(' ')[0] : ''),
                        width: Math.round(rect.width),
                        height: Math.round(rect.height),
                        text: element.textContent?.trim().substring(0, 30) || ''
                    });
                }
            }
        });

        return smallTargets;
    }, ACCESSIBILITY_CRITERIA.navigation.minTouchTarget);
}

async function testAriaLabels(page) {
    return await page.evaluate(() => {
        const results = {
            missingLabels: [],
            goodLabels: 0,
            landmarks: []
        };

        // Check interactive elements for proper labeling
        const interactive = document.querySelectorAll('button, a, input, select, textarea');
        interactive.forEach(element => {
            const hasLabel = !!(
                element.getAttribute('aria-label') ||
                element.getAttribute('aria-labelledby') ||
                element.textContent?.trim() ||
                (element.tagName === 'INPUT' && element.type === 'submit' && element.value) ||
                (element.tagName === 'INPUT' && document.querySelector(`label[for="${element.id}"]`))
            );

            if (hasLabel) {
                results.goodLabels++;
            } else {
                results.missingLabels.push({
                    element: element.tagName,
                    type: element.type || null,
                    className: element.className || '',
                    id: element.id || ''
                });
            }
        });

        // Check for landmark roles
        const landmarks = document.querySelectorAll('[role="main"], [role="navigation"], [role="banner"], [role="contentinfo"], main, nav, header, footer');
        results.landmarks = Array.from(landmarks).map(landmark => ({
            tagName: landmark.tagName,
            role: landmark.getAttribute('role') || landmark.tagName.toLowerCase()
        }));

        return results;
    });
}

async function testScreenReaderContent(page) {
    return await page.evaluate(() => {
        const results = {
            headingStructure: [],
            altTexts: { missing: 0, present: 0 },
            hiddenContent: []
        };

        // Check heading structure
        const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
        headings.forEach(heading => {
            results.headingStructure.push({
                level: parseInt(heading.tagName.charAt(1)),
                text: heading.textContent?.trim().substring(0, 50) || '',
                id: heading.id || ''
            });
        });

        // Check image alt texts
        const images = document.querySelectorAll('img');
        images.forEach(img => {
            if (img.getAttribute('alt') !== null) {
                results.altTexts.present++;
            } else {
                results.altTexts.missing++;
            }
        });

        // Check for screen reader only content
        const srOnly = document.querySelectorAll('.sr-only, .screen-reader-text, [aria-hidden="true"]');
        results.hiddenContent = Array.from(srOnly).map(element => ({
            tagName: element.tagName,
            className: element.className || '',
            text: element.textContent?.trim().substring(0, 30) || ''
        }));

        return results;
    });
}

async function takeMobileScreenshot(page, name, device) {
    const screenshotDir = path.join(__dirname, '../../screenshots/mobile-accessibility');
    await require('fs').promises.mkdir(screenshotDir, { recursive: true });
    
    await page.screenshot({ 
        path: path.join(screenshotDir, `${name}-${device}-${Date.now()}.png`),
        fullPage: true 
    });
}

test.describe('Mobile & Accessibility Tests', () => {
    test.setTimeout(TEST_TIMEOUT);

    test.describe('Mobile Responsiveness Tests', () => {
        MOBILE_DEVICES.forEach(device => {
            test(`should display correctly on ${device.name}`, async ({ browser }) => {
                const context = await browser.newContext({
                    ...device,
                    // Override locale and timezone if needed
                    locale: 'en-US',
                    timezoneId: 'America/New_York'
                });
                
                const page = await context.newPage();
                
                try {
                    await loginAsTrainer(page);
                    
                    // Test key pages on this device
                    for (const pagePath of TEST_PAGES.slice(0, 4)) { // Test subset for speed
                        await page.goto(`${BASE_URL}${pagePath}`);
                        await page.waitForLoadState('domcontentloaded');
                        
                        // Check viewport utilization
                        const layoutInfo = await page.evaluate(() => {
                            const viewport = {
                                width: window.innerWidth,
                                height: window.innerHeight
                            };
                            
                            const content = document.querySelector('.hvac-page-wrapper, .hvac-content, main');
                            const contentRect = content ? content.getBoundingClientRect() : null;
                            
                            return {
                                viewport,
                                contentWidth: contentRect ? contentRect.width : 0,
                                hasHorizontalScroll: document.documentElement.scrollWidth > viewport.width,
                                hasOverflow: contentRect ? contentRect.width > viewport.width : false
                            };
                        });
                        
                        // Should not have horizontal scroll
                        expect(layoutInfo.hasHorizontalScroll).toBeFalsy();
                        
                        // Content should fit within viewport
                        expect(layoutInfo.hasOverflow).toBeFalsy();
                        
                        // Content should use reasonable amount of viewport width
                        const widthUtilization = layoutInfo.contentWidth / layoutInfo.viewport.width;
                        expect(widthUtilization).toBeGreaterThan(0.8); // At least 80% width usage
                        expect(widthUtilization).toBeLessThanOrEqual(1.0); // Not exceeding viewport
                        
                        console.log(`${device.name} - ${pagePath}: width utilization ${(widthUtilization * 100).toFixed(1)}%`);
                    }
                    
                    await takeMobileScreenshot(page, 'responsive-test', device.name.toLowerCase().replace(/\s+/g, '-'));
                    
                } finally {
                    await context.close();
                }
            });
        });

        test('should handle orientation changes gracefully', async ({ browser }) => {
            const device = devices['iPad Pro'];
            
            // Test portrait
            const portraitContext = await browser.newContext({
                ...device,
                viewport: { width: device.viewport.height, height: device.viewport.width } // Swap dimensions
            });
            const portraitPage = await portraitContext.newPage();
            
            await loginAsTrainer(portraitPage);
            await portraitPage.goto(`${BASE_URL}/trainer/dashboard/`);
            
            const portraitLayout = await portraitPage.evaluate(() => {
                const nav = document.querySelector('.hvac-nav-menu, .hvac-trainer-nav');
                const content = document.querySelector('.hvac-content, main');
                
                return {
                    navVisible: nav ? window.getComputedStyle(nav).display !== 'none' : false,
                    contentWidth: content ? content.offsetWidth : 0,
                    viewportWidth: window.innerWidth
                };
            });
            
            // Test landscape
            const landscapeContext = await browser.newContext(device);
            const landscapePage = await landscapeContext.newPage();
            
            await loginAsTrainer(landscapePage);
            await landscapePage.goto(`${BASE_URL}/trainer/dashboard/`);
            
            const landscapeLayout = await landscapePage.evaluate(() => {
                const nav = document.querySelector('.hvac-nav-menu, .hvac-trainer-nav');
                const content = document.querySelector('.hvac-content, main');
                
                return {
                    navVisible: nav ? window.getComputedStyle(nav).display !== 'none' : false,
                    contentWidth: content ? content.offsetWidth : 0,
                    viewportWidth: window.innerWidth
                };
            });
            
            // Both orientations should work
            expect(portraitLayout.contentWidth).toBeGreaterThan(0);
            expect(landscapeLayout.contentWidth).toBeGreaterThan(0);
            
            console.log('Orientation testing:', {
                portrait: portraitLayout,
                landscape: landscapeLayout
            });
            
            await portraitContext.close();
            await landscapeContext.close();
        });

        test('should handle touch interactions properly', async ({ browser }) => {
            const context = await browser.newContext(devices['iPhone 12']);
            const page = await context.newPage();
            
            await loginAsTrainer(page);
            await page.goto(`${BASE_URL}/trainer/dashboard/`);
            
            // Test touch targets
            const touchTargets = await testTouchTargets(page);
            
            console.log(`Small touch targets found: ${touchTargets.length}`);
            if (touchTargets.length > 0) {
                console.log('Small targets sample:', touchTargets.slice(0, 3));
            }
            
            // Should have minimal small touch targets
            expect(touchTargets.length).toBeLessThan(5);
            
            // Test mobile navigation
            const hamburger = await page.$('.hvac-menu-toggle, .menu-toggle, .hamburger');
            if (hamburger) {
                // Test touch interaction
                await hamburger.tap();
                await page.waitForTimeout(500);
                
                const menuOpened = await page.evaluate(() => {
                    const menu = document.querySelector('.hvac-nav-menu');
                    return menu ? window.getComputedStyle(menu).display !== 'none' : false;
                });
                
                expect(menuOpened).toBeTruthy();
                
                // Test closing
                await hamburger.tap();
                await page.waitForTimeout(500);
            }
            
            await context.close();
        });
    });

    test.describe('Accessibility Compliance Tests', () => {
        test('should meet WCAG 2.1 AA color contrast requirements', async ({ page }) => {
            await loginAsTrainer(page);
            
            const pagesToTest = TEST_PAGES.slice(0, 4); // Test subset
            const allContrastIssues = [];
            
            for (const pagePath of pagesToTest) {
                await page.goto(`${BASE_URL}${pagePath}`);
                await page.waitForLoadState('domcontentloaded');
                
                const contrastIssues = await testColorContrast(page);
                allContrastIssues.push(...contrastIssues);
                
                console.log(`Contrast issues on ${pagePath}: ${contrastIssues.length}`);
            }
            
            // Should have minimal contrast issues
            expect(allContrastIssues.length).toBeLessThan(10);
            
            if (allContrastIssues.length > 0) {
                console.log('Contrast issues sample:', allContrastIssues.slice(0, 3));
            }
        });

        test('should support keyboard navigation', async ({ page }) => {
            await loginAsTrainer(page);
            await page.goto(`${BASE_URL}/trainer/dashboard/`);
            
            const navigationResults = await testKeyboardNavigation(page);
            
            console.log('Keyboard navigation results:', {
                tabStops: navigationResults.tabStops,
                focusableElements: navigationResults.focusableElements.length,
                hasSkipLinks: navigationResults.skipLinks
            });
            
            // Should have reasonable number of tab stops
            expect(navigationResults.tabStops).toBeGreaterThan(3);
            expect(navigationResults.tabStops).toBeLessThan(ACCESSIBILITY_CRITERIA.navigation.maxTabStops);
            
            // Should have focusable elements
            expect(navigationResults.focusableElements.length).toBeGreaterThan(3);
            
            // Test specific keyboard interactions
            await page.keyboard.press('Space'); // Should activate focused element
            await page.keyboard.press('Enter'); // Should activate focused element
            await page.keyboard.press('Escape'); // Should close modals/menus
            
            // Page should remain functional after keyboard interaction
            const stillFunctional = await page.evaluate(() => {
                return document.body.style.display !== 'none';
            });
            expect(stillFunctional).toBeTruthy();
        });

        test('should have proper ARIA labels and landmarks', async ({ page }) => {
            await loginAsTrainer(page);
            
            const pagesToTest = TEST_PAGES.slice(0, 3);
            const allAriaResults = [];
            
            for (const pagePath of pagesToTest) {
                await page.goto(`${BASE_URL}${pagePath}`);
                await page.waitForLoadState('domcontentloaded');
                
                const ariaResults = await testAriaLabels(page);
                allAriaResults.push({ page: pagePath, ...ariaResults });
                
                // Should have good labeling ratio
                const totalInteractive = ariaResults.goodLabels + ariaResults.missingLabels.length;
                const labelingRatio = totalInteractive > 0 ? ariaResults.goodLabels / totalInteractive : 1;
                
                expect(labelingRatio).toBeGreaterThan(0.8); // 80% properly labeled
                
                // Should have basic landmarks
                expect(ariaResults.landmarks.length).toBeGreaterThan(0);
                
                console.log(`ARIA compliance on ${pagePath}:`, {
                    labelingRatio: (labelingRatio * 100).toFixed(1) + '%',
                    landmarks: ariaResults.landmarks.length,
                    missingLabels: ariaResults.missingLabels.length
                });
            }
        });

        test('should support screen readers', async ({ page }) => {
            await loginAsTrainer(page);
            await page.goto(`${BASE_URL}/trainer/dashboard/`);
            
            const screenReaderResults = await testScreenReaderContent(page);
            
            console.log('Screen reader compliance:', screenReaderResults);
            
            // Should have proper heading structure
            expect(screenReaderResults.headingStructure.length).toBeGreaterThan(0);
            
            // Should have more images with alt text than without
            const totalImages = screenReaderResults.altTexts.present + screenReaderResults.altTexts.missing;
            if (totalImages > 0) {
                const altTextRatio = screenReaderResults.altTexts.present / totalImages;
                expect(altTextRatio).toBeGreaterThan(0.7); // 70% of images should have alt text
            }
            
            // Check heading hierarchy
            const headingLevels = screenReaderResults.headingStructure.map(h => h.level);
            if (headingLevels.length > 1) {
                // Should start with h1 or h2
                expect(headingLevels[0]).toBeLessThanOrEqual(2);
                
                // Should not skip levels dramatically
                const maxJump = Math.max(...headingLevels.slice(1).map((level, i) => 
                    level - headingLevels[i]
                ));
                expect(maxJump).toBeLessThanOrEqual(2); // No skipping more than 1 level
            }
        });

        test('should handle focus management properly', async ({ page }) => {
            await loginAsTrainer(page);
            await page.goto(`${BASE_URL}/trainer/events/create/`);
            
            // Test focus on form elements
            const formFocus = await page.evaluate(() => {
                const inputs = Array.from(document.querySelectorAll('input, select, textarea, button'));
                const focusableInputs = inputs.filter(input => {
                    const style = window.getComputedStyle(input);
                    return style.display !== 'none' && 
                           style.visibility !== 'hidden' && 
                           !input.disabled &&
                           input.tabIndex !== -1;
                });
                
                return {
                    totalInputs: inputs.length,
                    focusableInputs: focusableInputs.length,
                    firstFocusable: focusableInputs[0] ? {
                        tagName: focusableInputs[0].tagName,
                        type: focusableInputs[0].type || null,
                        id: focusableInputs[0].id || ''
                    } : null
                };
            });
            
            expect(focusableInputs.length).toBeGreaterThan(0);
            
            // Test focus trapping in modals (if any)
            const modals = await page.$$('.modal, .overlay, [role="dialog"]');
            if (modals.length > 0) {
                // Test focus trap
                for (let i = 0; i < 20; i++) {
                    await page.keyboard.press('Tab');
                }
                
                // Focus should still be within modal
                const focusInModal = await page.evaluate(() => {
                    const active = document.activeElement;
                    const modal = document.querySelector('.modal, .overlay, [role="dialog"]');
                    return modal ? modal.contains(active) : true;
                });
                
                expect(focusInModal).toBeTruthy();
            }
            
            console.log('Focus management:', focusableInputs);
        });
    });

    test.describe('Progressive Enhancement Tests', () => {
        test('should work without JavaScript', async ({ browser }) => {
            const context = await browser.newContext({
                javaScriptEnabled: false
            });
            const page = await context.newPage();
            
            // Test basic functionality without JS
            await page.goto(`${BASE_URL}/trainer/dashboard/`);
            
            const basicFunctionality = await page.evaluate(() => {
                return {
                    hasContent: document.body.textContent.length > 100,
                    hasNavigation: !!document.querySelector('nav, .navigation, .hvac-nav'),
                    hasLinks: document.querySelectorAll('a').length > 0,
                    hasForms: document.querySelectorAll('form').length > 0
                };
            });
            
            // Should have basic content and navigation
            expect(basicFunctionality.hasContent).toBeTruthy();
            expect(basicFunctionality.hasNavigation).toBeTruthy();
            
            console.log('No-JS functionality:', basicFunctionality);
            
            await context.close();
        });

        test('should degrade gracefully with slow connections', async ({ page }) => {
            // Simulate slow 3G connection
            await page.route('**/*', route => {
                setTimeout(() => route.continue(), 1000); // 1 second delay
            });
            
            await loginAsTrainer(page);
            
            const startTime = Date.now();
            await page.goto(`${BASE_URL}/trainer/dashboard/`);
            const loadTime = Date.now() - startTime;
            
            // Should still load within reasonable time
            expect(loadTime).toBeLessThan(30000); // 30 seconds max
            
            // Should show content even if some resources fail
            const hasContent = await page.evaluate(() => {
                return document.body.textContent.length > 100;
            });
            
            expect(hasContent).toBeTruthy();
            
            console.log(`Slow connection load time: ${loadTime}ms`);
        });

        test('should handle reduced motion preferences', async ({ browser }) => {
            const context = await browser.newContext({
                reducedMotion: 'reduce'
            });
            const page = await context.newPage();
            
            await loginAsTrainer(page);
            await page.goto(`${BASE_URL}/trainer/dashboard/`);
            
            // Check for animations that respect reduced motion
            const animationInfo = await page.evaluate(() => {
                const animatedElements = document.querySelectorAll('*');
                let animationsFound = 0;
                let respectsReducedMotion = 0;
                
                Array.from(animatedElements).forEach(element => {
                    const styles = window.getComputedStyle(element);
                    if (styles.animationName !== 'none' || styles.transitionProperty !== 'none') {
                        animationsFound++;
                        
                        // Check if animation is disabled with prefers-reduced-motion
                        if (styles.animationPlayState === 'paused' || 
                            styles.animationDuration === '0s' ||
                            styles.transitionDuration === '0s') {
                            respectsReducedMotion++;
                        }
                    }
                });
                
                return {
                    animationsFound,
                    respectsReducedMotion,
                    compliance: animationsFound > 0 ? respectsReducedMotion / animationsFound : 1
                };
            });
            
            console.log('Reduced motion compliance:', animationInfo);
            
            // Should respect reduced motion preferences
            if (animationInfo.animationsFound > 0) {
                expect(animationInfo.compliance).toBeGreaterThan(0.7); // 70% compliance
            }
            
            await context.close();
        });
    });
});

// Export mobile accessibility test configuration
module.exports = {
    testDir: __dirname,
    timeout: TEST_TIMEOUT,
    retries: 1,
    workers: 1, // Sequential for consistent mobile testing
    use: {
        baseURL: BASE_URL,
        screenshot: 'only-on-failure',
        video: 'retain-on-failure',
        trace: 'on-first-retry'
    }
};