#!/usr/bin/env node
/**
 * Mobile Interactions UI Tests
 *
 * Tests for mobile-specific interactions: modals, navigation, forms on touch devices.
 *
 * Run: node test_mobile_interactions_ci.js
 */

const { setupTest, teardownTest, TestResults, log, delay, viewports } = require('./test_lib');

// ============================================================================
// Mobile Modal Tests
// ============================================================================
const MobileModalTests = {
    async modalOpensOnMobile(page, baseUrl) {
        // Set mobile viewport
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/collections`, { waitUntil: 'networkidle2' });

        // Find a button that opens a modal
        const result = await page.evaluate(() => {
            const buttons = Array.from(document.querySelectorAll('button, a.btn, .btn'));
            const modalTrigger = buttons.find(b => {
                const text = b.textContent?.toLowerCase() || '';
                return text.includes('create') || text.includes('new') || text.includes('add');
            });

            if (modalTrigger) {
                modalTrigger.click();
                return { clicked: true };
            }
            return { clicked: false };
        });

        if (!result.clicked) {
            return { passed: null, skipped: true, message: 'No modal trigger button found' };
        }

        await delay(500);

        const modalResult = await page.evaluate(() => {
            const modal = document.querySelector('.modal, .dialog, [role="dialog"], .sheet');
            if (!modal) return { hasModal: false };

            const rect = modal.getBoundingClientRect();
            const isVisible = rect.width > 0 && rect.height > 0;
            const fitsScreen = rect.width <= window.innerWidth && rect.height <= window.innerHeight;

            return {
                hasModal: true,
                isVisible,
                fitsScreen,
                width: rect.width,
                height: rect.height,
                screenWidth: window.innerWidth
            };
        });

        if (!modalResult.hasModal) {
            return { passed: null, skipped: true, message: 'No modal appeared after clicking trigger' };
        }

        return {
            passed: modalResult.isVisible && modalResult.fitsScreen,
            message: modalResult.fitsScreen
                ? `Modal opens on mobile (${modalResult.width}x${modalResult.height})`
                : `Modal exceeds screen (${modalResult.width}px > ${modalResult.screenWidth}px)`
        };
    },

    async modalClosesOnBackdropTap(page, baseUrl) {
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/collections`, { waitUntil: 'networkidle2' });

        // Open modal first
        await page.evaluate(() => {
            const buttons = Array.from(document.querySelectorAll('button, a.btn'));
            const trigger = buttons.find(b => b.textContent?.toLowerCase().includes('create'));
            if (trigger) trigger.click();
        });

        await delay(500);

        // Check if modal is open
        const modalOpen = await page.evaluate(() => {
            return !!document.querySelector('.modal.show, .modal[style*="display: block"], [role="dialog"]');
        });

        if (!modalOpen) {
            return { passed: null, skipped: true, message: 'Could not open modal for backdrop test' };
        }

        // Tap on backdrop
        await page.evaluate(() => {
            const backdrop = document.querySelector('.modal-backdrop, .overlay, .dialog-backdrop');
            if (backdrop) {
                backdrop.click();
            } else {
                // Click outside the modal content
                const modal = document.querySelector('.modal, [role="dialog"]');
                if (modal) {
                    const event = new MouseEvent('click', { bubbles: true });
                    modal.dispatchEvent(event);
                }
            }
        });

        await delay(300);

        const result = await page.evaluate(() => {
            const modal = document.querySelector('.modal.show, .modal[style*="display: block"], [role="dialog"]');
            return {
                modalClosed: !modal || modal.style.display === 'none' || !modal.classList.contains('show')
            };
        });

        return {
            passed: result.modalClosed,
            message: result.modalClosed
                ? 'Modal closes on backdrop tap'
                : 'Modal did not close on backdrop tap'
        };
    },

    async modalScrollableContent(page, baseUrl) {
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/settings/`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            // Look for any scrollable modal content
            const modalContent = document.querySelector('.modal-body, .dialog-content, .sheet-content');
            if (!modalContent) return { hasModalContent: false };

            const style = window.getComputedStyle(modalContent);
            const isScrollable = style.overflowY === 'auto' || style.overflowY === 'scroll' ||
                                 modalContent.scrollHeight > modalContent.clientHeight;

            return {
                hasModalContent: true,
                isScrollable,
                overflowY: style.overflowY,
                scrollHeight: modalContent.scrollHeight,
                clientHeight: modalContent.clientHeight
            };
        });

        if (!result.hasModalContent) {
            return { passed: null, skipped: true, message: 'No modal content found to test scrolling' };
        }

        return {
            passed: result.isScrollable || result.overflowY === 'auto',
            message: `Modal content scrollable: overflow=${result.overflowY}`
        };
    },

    async modalCloseButtonAccessible(page, baseUrl) {
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/collections`, { waitUntil: 'networkidle2' });

        // Open modal
        await page.evaluate(() => {
            const trigger = Array.from(document.querySelectorAll('button, a.btn')).find(b =>
                b.textContent?.toLowerCase().includes('create')
            );
            if (trigger) trigger.click();
        });

        await delay(500);

        const result = await page.evaluate(() => {
            const closeBtn = document.querySelector(
                '.modal .close, ' +
                '.modal .btn-close, ' +
                '.modal button[aria-label*="close"], ' +
                '[role="dialog"] button.close, ' +
                '.dialog-close'
            );

            if (!closeBtn) return { hasCloseBtn: false };

            const rect = closeBtn.getBoundingClientRect();
            // Minimum touch target should be 44x44px for accessibility
            const isTappable = rect.width >= 30 && rect.height >= 30;
            const isVisible = rect.width > 0 && rect.height > 0;

            return {
                hasCloseBtn: true,
                isTappable,
                isVisible,
                size: `${rect.width}x${rect.height}`
            };
        });

        if (!result.hasCloseBtn) {
            return { passed: null, skipped: true, message: 'No close button found in modal' };
        }

        return {
            passed: result.isTappable && result.isVisible,
            message: `Close button accessible (size: ${result.size}, tappable: ${result.isTappable})`
        };
    }
};

// ============================================================================
// Mobile Navigation Tests
// ============================================================================
const MobileNavTests = {
    async mobileMenuOpens(page, baseUrl) {
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const hamburger = document.querySelector(
                '.hamburger, ' +
                '.mobile-menu-toggle, ' +
                '.navbar-toggler, ' +
                'button[aria-label*="menu"], ' +
                '.menu-toggle, ' +
                '[class*="hamburger"]'
            );

            if (!hamburger) return { hasHamburger: false };

            hamburger.click();

            return new Promise(resolve => {
                setTimeout(() => {
                    const menu = document.querySelector(
                        '.mobile-menu, ' +
                        '.navbar-collapse.show, ' +
                        '.nav-menu.open, ' +
                        '.sidebar.open, ' +
                        '[class*="mobile-nav"]'
                    );

                    const isVisible = menu && (
                        menu.style.display !== 'none' &&
                        !menu.classList.contains('collapsed')
                    );

                    resolve({
                        hasHamburger: true,
                        menuOpened: !!menu,
                        isVisible
                    });
                }, 300);
            });
        });

        if (!result.hasHamburger) {
            // Check if using bottom nav instead
            const hasBottomNav = await page.evaluate(() => {
                return !!document.querySelector('.bottom-nav, .mobile-nav-tabs, .tab-bar');
            });

            if (hasBottomNav) {
                return { passed: true, message: 'Using bottom navigation instead of hamburger menu' };
            }

            return { passed: null, skipped: true, message: 'No hamburger menu found (may use different nav pattern)' };
        }

        return {
            passed: result.menuOpened,
            message: result.menuOpened
                ? 'Mobile menu opens on tap'
                : 'Mobile menu did not open'
        };
    },

    async mobileMenuCloses(page, baseUrl) {
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/`, { waitUntil: 'networkidle2' });

        // Open menu first
        await page.evaluate(() => {
            const hamburger = document.querySelector('.hamburger, .mobile-menu-toggle, .navbar-toggler');
            if (hamburger) hamburger.click();
        });

        await delay(300);

        // Click a menu item
        const result = await page.evaluate(() => {
            const menuLinks = document.querySelectorAll('.mobile-menu a, .navbar-collapse a, .nav-link');
            if (menuLinks.length === 0) return { hasLinks: false };

            const link = menuLinks[0];
            link.click();

            return new Promise(resolve => {
                setTimeout(() => {
                    const menu = document.querySelector('.mobile-menu, .navbar-collapse.show');
                    const isClosed = !menu || menu.style.display === 'none' || !menu.classList.contains('show');

                    resolve({
                        hasLinks: true,
                        menuClosed: isClosed
                    });
                }, 300);
            });
        });

        if (!result.hasLinks) {
            return { passed: null, skipped: true, message: 'No menu links found' };
        }

        return {
            passed: result.menuClosed,
            message: result.menuClosed
                ? 'Menu closes after selection'
                : 'Menu did not close after selection'
        };
    },

    async bottomNavTabsWork(page, baseUrl) {
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const bottomNav = document.querySelector('.bottom-nav, .mobile-nav-tabs, .tab-bar, .mobile-tabs');
            if (!bottomNav) return { hasBottomNav: false };

            const tabs = bottomNav.querySelectorAll('a, button, .tab');
            if (tabs.length === 0) return { hasBottomNav: true, hasTabs: false };

            const tabInfo = Array.from(tabs).map(tab => ({
                text: tab.textContent?.trim(),
                href: tab.href || tab.dataset?.href
            }));

            // Click the second tab if available
            if (tabs.length > 1) {
                tabs[1].click();
            }

            return {
                hasBottomNav: true,
                hasTabs: true,
                tabCount: tabs.length,
                tabs: tabInfo.slice(0, 5)
            };
        });

        if (!result.hasBottomNav) {
            return { passed: null, skipped: true, message: 'No bottom navigation found' };
        }

        if (!result.hasTabs) {
            return { passed: false, message: 'Bottom nav has no tabs' };
        }

        return {
            passed: true,
            message: `Bottom nav has ${result.tabCount} tabs: ${result.tabs.map(t => t.text).join(', ')}`
        };
    },

    async swipeGesturesWork(page, baseUrl) {
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/`, { waitUntil: 'networkidle2' });

        // Check if there are swipeable elements
        const result = await page.evaluate(() => {
            const swipeableElements = document.querySelectorAll(
                '.swipeable, ' +
                '[data-swipe], ' +
                '.carousel, ' +
                '.slider, ' +
                '[class*="swipe"]'
            );

            const hasTouchSupport = 'ontouchstart' in window || navigator.maxTouchPoints > 0;

            return {
                hasSwipeableElements: swipeableElements.length > 0,
                elementCount: swipeableElements.length,
                hasTouchSupport
            };
        });

        if (!result.hasSwipeableElements) {
            return { passed: null, skipped: true, message: 'No swipeable elements found' };
        }

        return {
            passed: true,
            message: `${result.elementCount} swipeable elements found`
        };
    }
};

// ============================================================================
// Mobile Form Tests
// ============================================================================
const MobileFormTests = {
    async mobileKeyboardDoesntBreakLayout(page, baseUrl) {
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const input = document.querySelector('input[type="text"], input[type="search"], textarea');
            if (!input) return { hasInput: false };

            // Focus the input (simulates keyboard appearing)
            input.focus();

            // Check if important elements are still visible
            const header = document.querySelector('header, .navbar, .page-header');
            const submitBtn = document.querySelector('button[type="submit"], .btn-primary');

            const headerVisible = header ? header.getBoundingClientRect().top >= 0 : true;

            return {
                hasInput: true,
                headerVisible,
                hasSubmitBtn: !!submitBtn
            };
        });

        if (!result.hasInput) {
            return { passed: null, skipped: true, message: 'No input field found' };
        }

        return {
            passed: result.headerVisible,
            message: result.headerVisible
                ? 'Layout stable when input focused'
                : 'Header pushed off-screen when input focused'
        };
    },

    async mobileDropdownsWork(page, baseUrl) {
        await page.setViewport({ width: 375, height: 667, isMobile: true, hasTouch: true });
        await page.goto(`${baseUrl}/settings/`, { waitUntil: 'networkidle2' });

        const result = await page.evaluate(() => {
            const selects = document.querySelectorAll('select, .custom-dropdown, .ldr-dropdown');
            if (selects.length === 0) return { hasDropdowns: false };

            const firstSelect = selects[0];
            const rect = firstSelect.getBoundingClientRect();

            // Check if dropdown is within screen bounds
            const isAccessible = rect.right <= window.innerWidth && rect.left >= 0;

            // Check touch target size
            const isTappable = rect.height >= 44; // iOS minimum touch target

            return {
                hasDropdowns: true,
                dropdownCount: selects.length,
                isAccessible,
                isTappable,
                height: rect.height
            };
        });

        if (!result.hasDropdowns) {
            return { passed: null, skipped: true, message: 'No dropdowns found' };
        }

        return {
            passed: result.isAccessible && result.isTappable,
            message: `Dropdowns: ${result.dropdownCount} found (accessible: ${result.isAccessible}, height: ${result.height}px)`
        };
    }
};

// ============================================================================
// Main Test Runner
// ============================================================================
async function main() {
    log.section('Mobile Interactions Tests');

    const ctx = await setupTest({ authenticate: true });
    const results = new TestResults('Mobile Interactions Tests');
    const { page } = ctx;
    const { baseUrl } = ctx.config;

    try {
        // Mobile Modal Tests
        log.section('Mobile Modals');
        const modalOpenResult = await MobileModalTests.modalOpensOnMobile(page, baseUrl);
        if (modalOpenResult.skipped) {
            results.skip('Modals', 'Modal Opens On Mobile', modalOpenResult.message);
        } else {
            results.add('Modals', 'Modal Opens On Mobile', modalOpenResult.passed, modalOpenResult.message);
        }

        const backdropResult = await MobileModalTests.modalClosesOnBackdropTap(page, baseUrl);
        if (backdropResult.skipped) {
            results.skip('Modals', 'Modal Closes On Backdrop Tap', backdropResult.message);
        } else {
            results.add('Modals', 'Modal Closes On Backdrop Tap', backdropResult.passed, backdropResult.message);
        }

        const scrollResult = await MobileModalTests.modalScrollableContent(page, baseUrl);
        if (scrollResult.skipped) {
            results.skip('Modals', 'Modal Scrollable Content', scrollResult.message);
        } else {
            results.add('Modals', 'Modal Scrollable Content', scrollResult.passed, scrollResult.message);
        }

        const closeResult = await MobileModalTests.modalCloseButtonAccessible(page, baseUrl);
        if (closeResult.skipped) {
            results.skip('Modals', 'Modal Close Button Accessible', closeResult.message);
        } else {
            results.add('Modals', 'Modal Close Button Accessible', closeResult.passed, closeResult.message);
        }

        // Mobile Navigation Tests
        log.section('Mobile Navigation');
        const menuOpenResult = await MobileNavTests.mobileMenuOpens(page, baseUrl);
        if (menuOpenResult.skipped) {
            results.skip('Navigation', 'Mobile Menu Opens', menuOpenResult.message);
        } else {
            results.add('Navigation', 'Mobile Menu Opens', menuOpenResult.passed, menuOpenResult.message);
        }

        const menuCloseResult = await MobileNavTests.mobileMenuCloses(page, baseUrl);
        if (menuCloseResult.skipped) {
            results.skip('Navigation', 'Mobile Menu Closes', menuCloseResult.message);
        } else {
            results.add('Navigation', 'Mobile Menu Closes', menuCloseResult.passed, menuCloseResult.message);
        }

        const bottomNavResult = await MobileNavTests.bottomNavTabsWork(page, baseUrl);
        if (bottomNavResult.skipped) {
            results.skip('Navigation', 'Bottom Nav Tabs Work', bottomNavResult.message);
        } else {
            results.add('Navigation', 'Bottom Nav Tabs Work', bottomNavResult.passed, bottomNavResult.message);
        }

        const swipeResult = await MobileNavTests.swipeGesturesWork(page, baseUrl);
        if (swipeResult.skipped) {
            results.skip('Navigation', 'Swipe Gestures Work', swipeResult.message);
        } else {
            results.add('Navigation', 'Swipe Gestures Work', swipeResult.passed, swipeResult.message);
        }

        // Mobile Form Tests
        log.section('Mobile Forms');
        const keyboardResult = await MobileFormTests.mobileKeyboardDoesntBreakLayout(page, baseUrl);
        if (keyboardResult.skipped) {
            results.skip('Forms', 'Mobile Keyboard Doesnt Break Layout', keyboardResult.message);
        } else {
            results.add('Forms', 'Mobile Keyboard Doesnt Break Layout', keyboardResult.passed, keyboardResult.message);
        }

        const dropdownResult = await MobileFormTests.mobileDropdownsWork(page, baseUrl);
        if (dropdownResult.skipped) {
            results.skip('Forms', 'Mobile Dropdowns Work', dropdownResult.message);
        } else {
            results.add('Forms', 'Mobile Dropdowns Work', dropdownResult.passed, dropdownResult.message);
        }

    } catch (error) {
        // Check if this is a navigation/browser error (not a real test failure)
        const isNavigationError = error.message &&
            (error.message.includes('context was destroyed') ||
             error.message.includes('Target closed') ||
             error.message.includes('Protocol error') ||
             error.message.includes('Session closed') ||
             error.message.includes('page has been closed'));

        if (isNavigationError) {
            log.warn(`Browser navigation error (test infrastructure issue): ${error.message}`);
            // Don't count as failure - this is a flaky test issue
        } else {
            log.error(`Fatal error: ${error.message}`);
            console.error(error.stack);
        }
    } finally {
        results.print();
        results.save();
        await teardownTest(ctx);
        process.exit(results.exitCode());
    }
}

// Run if executed directly
if (require.main === module) {
    main().catch(error => {
        console.error('Test runner failed:', error);
        process.exit(1);
    });
}

module.exports = { MobileModalTests, MobileNavTests, MobileFormTests };
