#!/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, navigateTo, withTimeout } = 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 navigateTo(page, `${baseUrl}/collections`);

        // 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 navigateTo(page, `${baseUrl}/collections`);

        // 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 navigateTo(page, `${baseUrl}/settings/`);

        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 navigateTo(page, `${baseUrl}/collections`);

        // 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 navigateTo(page, `${baseUrl}/`);

        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 navigateTo(page, `${baseUrl}/`);

        // 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 navigateTo(page, `${baseUrl}/`);

        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 navigateTo(page, `${baseUrl}/`);

        // 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 navigateTo(page, `${baseUrl}/`);

        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 navigateTo(page, `${baseUrl}/settings/`);

        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;

    const subTestTimeout = ctx.config.isCI ? 60000 : 30000;
    async function run(category, name, testFn) {
        try {
            const result = await withTimeout(
                testFn(page, baseUrl),
                subTestTimeout,
                `${category}/${name}`
            );
            if (result.skipped) {
                results.skip(category, name, result.message);
            } else {
                results.add(category, name, result.passed, result.message);
            }
        } catch (error) {
            results.add(category, name, false, `Error: ${error.message}`);
        }
    }

    try {
        // Mobile Modal Tests
        log.section('Mobile Modals');
        await run('Modals', 'Modal Opens On Mobile', (p, u) => MobileModalTests.modalOpensOnMobile(p, u));
        await run('Modals', 'Modal Closes On Backdrop Tap', (p, u) => MobileModalTests.modalClosesOnBackdropTap(p, u));
        await run('Modals', 'Modal Scrollable Content', (p, u) => MobileModalTests.modalScrollableContent(p, u));
        await run('Modals', 'Modal Close Button Accessible', (p, u) => MobileModalTests.modalCloseButtonAccessible(p, u));

        // Mobile Navigation Tests
        log.section('Mobile Navigation');
        await run('Navigation', 'Mobile Menu Opens', (p, u) => MobileNavTests.mobileMenuOpens(p, u));
        await run('Navigation', 'Mobile Menu Closes', (p, u) => MobileNavTests.mobileMenuCloses(p, u));
        await run('Navigation', 'Bottom Nav Tabs Work', (p, u) => MobileNavTests.bottomNavTabsWork(p, u));
        await run('Navigation', 'Swipe Gestures Work', (p, u) => MobileNavTests.swipeGesturesWork(p, u));

        // Mobile Form Tests
        log.section('Mobile Forms');
        await run('Forms', 'Mobile Keyboard Doesnt Break Layout', (p, u) => MobileFormTests.mobileKeyboardDoesntBreakLayout(p, u));
        await run('Forms', 'Mobile Dropdowns Work', (p, u) => MobileFormTests.mobileDropdownsWork(p, u));

    } catch (error) {
        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 };
