/**
 * Mamba Hover Prefetch
 * 
 * Prefetches likely next pages on hover/touch for faster navigation.
 * Works on catalog pages, cart, and checkout. Respects data saver settings.
 * 
 * Features:
 * - Speculation Rules API for Chrome/Edge 109+ (best performance)
 * - <link rel="prefetch"> for Firefox and older browsers
 * - fetch() fallback for Safari (universal compatibility)
 * 
 * Note: Speculation Rules prefetches don't appear in the Network tab.
 * To verify they're working in Chrome: DevTools → Application → Speculative loads
 * 
 * @version 2.1.0
 */

(function() {
    'use strict';
    
    // Debug mode - only log when mambaDebug is set or in development
    var debugMode = (typeof window.mambaDebug !== 'undefined' && window.mambaDebug) ||
                    (typeof window.MambaHoverPrefetch !== 'undefined' && window.MambaHoverPrefetch.debug);
    
    // Debug logging function - only logs when debug mode is enabled
    function debugLog(message, data) {
        if (debugMode && typeof console !== 'undefined' && console.log) {
            console.log('Mamba Prefetch:', message, data || '');
        }
    }
    
    // Feature detection
    var features = {
        // Speculation Rules API (Chrome/Edge 109+)
        speculationRules: (function() {
            try {
                return HTMLScriptElement.supports && HTMLScriptElement.supports('speculationrules');
            } catch (e) {
                return false;
            }
        })(),
        
        // Native <link rel="prefetch"> support (Firefox, Chrome, Edge - NOT Safari)
        prefetchLink: (function() {
            var link = document.createElement('link');
            return link.relList && link.relList.supports && link.relList.supports('prefetch');
        })(),
        
        // fetch() API (universal fallback)
        fetch: typeof fetch === 'function'
    };
    
    debugLog('Feature detection:', features);
    
    // Track if speculation rules have failed (browser disabled speculative loading)
    var speculationFailed = false;
    
    // Determine prefetch method (will be updated if speculation fails)
    var prefetchMethod = features.speculationRules ? 'speculation' : 
                         features.prefetchLink ? 'link' : 
                         features.fetch ? 'fetch' : null;
    
    // Fallback method if speculation is disabled by browser
    var fallbackMethod = features.prefetchLink ? 'link' : 
                         features.fetch ? 'fetch' : null;
    
    debugLog('Using prefetch method:', prefetchMethod);
    debugLog('Fallback method available:', fallbackMethod);
    
    // Note: If you see "Failure - speculative loading was disabled" in DevTools,
    // this means Chrome has disabled the Speculation Rules API. Common causes:
    // 1. Data Saver mode is enabled
    // 2. chrome://flags/#enable-prerender2 is disabled
    // 3. Low memory conditions
    // 4. Enterprise policy restrictions
    // The script will automatically fall back to <link rel="prefetch"> or fetch().
    
    // Exit if no prefetch method available
    if (!prefetchMethod) {
        debugLog('Exiting: No prefetch method available');
        return;
    }
    
    // Check for slow connections or data-saving mode
    var connection = navigator.connection || {};
    var slowConnection = connection.saveData || /2g/.test(connection.effectiveType);
    
    debugLog('Connection info:', {
        saveData: connection.saveData,
        effectiveType: connection.effectiveType,
        slowConnection: slowConnection
    });
    
    // Exit if the user is on a slow connection
    if (slowConnection) {
        debugLog('Exiting: Slow connection detected');
        return;
    }
    
    // Configuration
    var config = {
        maxPrefetches: 10,          // Maximum prefetches per page
        hoverDelay: 65,             // Delay before prefetch (ms) - slightly increased for better UX
        maxConcurrent: 3,           // Maximum concurrent prefetches
        rateLimitDelay: 500,        // Minimum delay between prefetches (ms) - reduced for faster response
        speculationEagerness: 'moderate' // Speculation Rules eagerness: conservative, moderate, eager
    };
    
    debugLog('Configuration loaded:', config);
    
    // State tracking
    var prefetchedUrls = new Set();   // To prevent duplicate prefetches
    var timeoutId = null;             // Used to delay prefetching
    var prefetchCount = 0;            // Current prefetch count
    var activePrefetches = 0;         // Current concurrent prefetches
    var lastPrefetchTime = 0;         // Rate limiting
    var speculationScript = null;     // Reference to speculation rules script element
    var speculationUrls = [];         // URLs added to speculation rules
    
    debugLog('State initialized');
    
    /**
     * Check if a URL is safe to prefetch
     */
    function isPrefetchable(url) {
        try {
            var urlObj = new URL(url, window.location.origin);
            
            // Must be same origin
            if (urlObj.origin !== window.location.origin) {
                return false;
            }
            
            // Must not be current page
            if (urlObj.href === window.location.href) {
                return false;
            }
            
            // Must not be admin or login pages
            if (urlObj.pathname.startsWith('/wp-admin') || urlObj.pathname.startsWith('/wp-login')) {
                return false;
            }
            
            // Must not be API endpoints
            if (urlObj.pathname.startsWith('/wp-json') || urlObj.pathname.startsWith('/wc-ajax')) {
                return false;
            }
            
            // Must not be WooCommerce AJAX actions
            var ajaxActions = ['/add-to-cart', '/remove-item', '/apply-coupon', '/remove-coupon', '/update-order-review', '/get_refreshed_fragments'];
            for (var i = 0; i < ajaxActions.length; i++) {
                if (urlObj.pathname.includes(ajaxActions[i])) {
                    return false;
                }
            }
            
            // Only block session-specific parameters
            if (urlObj.search) {
                var searchParams = urlObj.searchParams;
                var sessionParams = ['cart', 'checkout', 'order', 'session', 'token', 'nonce'];
                for (var j = 0; j < sessionParams.length; j++) {
                    if (searchParams.has(sessionParams[j])) {
                        return false;
                    }
                }
            }
            
            return true;
        } catch (e) {
            return false;
        }
    }
    
    /**
     * Prefetch using Speculation Rules API (Chrome/Edge 109+)
     * Best performance - browser handles prefetch/prerender intelligently
     * 
     * Note: If browser has disabled speculative loading, this will show as
     * "Failure - speculative loading was disabled" in DevTools. In that case,
     * we automatically fall back to link prefetch or fetch on subsequent calls.
     */
    function prefetchWithSpeculation(url) {
        // If speculation has previously failed, use fallback immediately
        if (speculationFailed && fallbackMethod) {
            debugLog('Speculation disabled, using fallback method:', fallbackMethod);
            if (fallbackMethod === 'link') {
                activePrefetches++;
                prefetchWithLink(url);
            } else {
                activePrefetches++;
                prefetchWithFetch(url);
            }
            return;
        }
        
        // Add URL to speculation list
        speculationUrls.push(url);
        
        // Remove old script if exists
        if (speculationScript && speculationScript.parentNode) {
            speculationScript.parentNode.removeChild(speculationScript);
        }
        
        // Create new speculation rules script
        speculationScript = document.createElement('script');
        speculationScript.type = 'speculationrules';
        
        var rules = {
            prefetch: [{
                source: 'list',
                urls: speculationUrls,
                eagerness: config.speculationEagerness
            }]
        };
        
        speculationScript.textContent = JSON.stringify(rules);
        document.head.appendChild(speculationScript);
        
        debugLog('Speculation rule added for:', url);
        debugLog('(View in DevTools: Application → Speculative loads)', '');
        
        // Check if speculation rules are actually working after a short delay
        // by monitoring the PerformanceObserver for speculation failures
        if (!speculationFailed && typeof PerformanceObserver !== 'undefined') {
            try {
                var observer = new PerformanceObserver(function(list) {
                    list.getEntries().forEach(function(entry) {
                        // Check for speculation rule failures
                        if (entry.initiatorType === 'speculation-rules' && 
                            entry.deliveryType === 'failure') {
                            speculationFailed = true;
                            debugLog('Speculation rules disabled by browser, switching to fallback');
                            observer.disconnect();
                        }
                    });
                });
                observer.observe({ type: 'resource', buffered: true });
                // Auto-disconnect after 5 seconds to avoid memory leaks
                setTimeout(function() { observer.disconnect(); }, 5000);
            } catch (e) {
                // PerformanceObserver not fully supported, continue without monitoring
            }
        }
    }
    
    /**
     * Prefetch using <link rel="prefetch"> (Firefox, older Chrome/Edge)
     * Good browser cache integration
     */
    function prefetchWithLink(url) {
        var link = document.createElement('link');
        link.rel = 'prefetch';
        link.href = url;
        link.as = 'document';
        
        link.onload = function() {
            activePrefetches--;
            debugLog('Link prefetch successful:', url);
        };
        
        link.onerror = function() {
            activePrefetches--;
            debugLog('Link prefetch failed:', url);
        };
        
        document.head.appendChild(link);
        debugLog('Link prefetch initiated:', url);
    }
    
    /**
     * Prefetch using fetch() API (Safari fallback)
     * Universal compatibility but less efficient cache integration
     */
    function prefetchWithFetch(url) {
        fetch(url, {
            method: 'GET',
            mode: 'no-cors',
            cache: 'force-cache',
            credentials: 'omit',
            headers: {
                'Purpose': 'prefetch',
                'Sec-Purpose': 'prefetch'
            }
        }).then(function() {
            activePrefetches--;
            debugLog('Fetch prefetch successful:', url);
        }).catch(function(error) {
            activePrefetches--;
            debugLog('Fetch prefetch failed:', error.message);
        });
        
        debugLog('Fetch prefetch initiated:', url);
    }
    
    /**
     * Main prefetch function - uses best available method
     */
    function prefetch(url) {
        // Check budget limits
        if (prefetchCount >= config.maxPrefetches) {
            debugLog('Budget exhausted, skipping:', url);
            return;
        }
        
        // Check concurrent limit (not applicable to speculation rules)
        if (prefetchMethod !== 'speculation' && activePrefetches >= config.maxConcurrent) {
            debugLog('Max concurrent reached, skipping:', url);
            return;
        }
        
        // Rate limiting
        var now = Date.now();
        if (now - lastPrefetchTime < config.rateLimitDelay) {
            debugLog('Rate limited, skipping:', url);
            return;
        }
        
        // Check if already prefetched
        if (prefetchedUrls.has(url)) {
            debugLog('Already prefetched, skipping:', url);
            return;
        }
        
        // Check if URL is safe to prefetch
        if (!isPrefetchable(url)) {
            debugLog('Not prefetchable, skipping:', url);
            return;
        }
        
        // Track prefetch
        prefetchedUrls.add(url);
        prefetchCount++;
        lastPrefetchTime = now;
        
        // Execute prefetch using best available method
        try {
            if (prefetchMethod === 'speculation') {
                prefetchWithSpeculation(url);
            } else if (prefetchMethod === 'link') {
                activePrefetches++;
                prefetchWithLink(url);
            } else {
                activePrefetches++;
                prefetchWithFetch(url);
            }
        } catch (e) {
            debugLog('Prefetch error:', e.message);
            if (prefetchMethod !== 'speculation') {
                activePrefetches--;
            }
        }
    }
    
    /**
     * Handle mouse hover event
     */
    function onMouseOver(event) {
        var link = event.target.closest("a");
        if (link && link.href) {
            debugLog('Mouse over detected:', link.href);
            
            // Clear any existing timeout
            if (timeoutId) {
                clearTimeout(timeoutId);
                debugLog('Cleared existing timeout');
            }
            
            timeoutId = setTimeout(function() {
                debugLog('Hover timeout triggered, prefetching:', link.href);
                prefetch(link.href);
            }, config.hoverDelay);
        }
    }
    
    /**
     * Handle touchstart event (for mobile users)
     */
    function onTouchStart(event) {
        var link = event.target.closest("a");
        if (link && link.href) {
            debugLog('Touch detected, prefetching:', link.href);
            prefetch(link.href);
        }
    }
    
    /**
     * Cancel pending prefetch if user moves away before hover delay completes
     */
    function onMouseOut(event) {
        var link = event.target.closest("a");
        if (link && link.href) {
            if (timeoutId) {
                clearTimeout(timeoutId);
                timeoutId = null;
                debugLog('Mouse out before hover delay, prefetch not triggered for:', link.href);
            }
        }
    }
    
    /**
     * Initialize prefetch functionality
     */
    function init() {
        debugLog('Initializing hover prefetch');
        
        // Attach event listeners with passive option for performance
        document.addEventListener("mouseover", onMouseOver, { capture: true, passive: true });
        document.addEventListener("mouseout", onMouseOut, { capture: true, passive: true });
        document.addEventListener("touchstart", onTouchStart, { capture: true, passive: true });
        
        debugLog('Event listeners attached');
        
        debugLog('Hover prefetch initialized successfully');
    }
    
    // Initialize when DOM is ready
    if (document.readyState === 'loading') {
        debugLog('DOM loading, waiting for DOMContentLoaded');
        document.addEventListener('DOMContentLoaded', init);
    } else {
        debugLog('DOM already ready, initializing immediately');
        init();
    }
    
})();
