/**
 * MapGeo Safety System
 * Prevents MapGeo and third-party map plugins from crashing the page
 * Works in all browsers including Safari and Chrome
 * 
 * @package HVAC_Community_Events
 * @since 2.0.0
 */

(function () {
    'use strict';

    // Safety configuration
    const config = window.HVAC_MapGeo_Config || {
        maxRetries: 3,
        retryDelay: 2000,
        timeout: 30000, // Increased to 30s
        fallbackEnabled: true,
        debugMode: false
    };

    const log = config.debugMode ? console.log.bind(console) : () => { };
    const error = config.debugMode ? console.error.bind(console) : () => { };

    log('[MapGeo Safety] Initializing protection system');

    /**
     * Resource Load Monitor
     * Tracks and manages external script loading
     */
    class ResourceLoadMonitor {
        constructor() {
            this.resources = new Map();
            this.criticalResources = [
                'amcharts',
                'mapgeo',
                'interactive-geo-maps',
                'map-widget'
            ];
            this.setupMonitoring();
        }

        setupMonitoring() {
            // Monitor script loading
            const originalAppendChild = Element.prototype.appendChild;
            const self = this;

            Element.prototype.appendChild = function (element) {
                if (element.tagName === 'SCRIPT' && element.src) {
                    self.monitorScript(element);
                }
                return originalAppendChild.call(this, element);
            };

            // Monitor existing scripts
            document.querySelectorAll('script[src]').forEach(script => {
                this.monitorScript(script);
            });
        }

        monitorScript(script) {
            const src = script.src;
            const isCritical = this.criticalResources.some(resource =>
                src.toLowerCase().includes(resource)
            );

            if (isCritical) {
                log('[MapGeo Safety] Monitoring critical resource:', src);

                // Use Performance API to check if already loaded
                if (performance.getEntriesByName(src).length > 0) {
                    log('[MapGeo Safety] Resource already loaded (Performance API):', src);
                    this.resources.set(src, 'loaded');
                    return;
                }

                const timeoutId = setTimeout(() => {
                    // Double check with Performance API before failing
                    if (performance.getEntriesByName(src).length > 0) {
                        log('[MapGeo Safety] Resource loaded just in time (Performance API):', src);
                        this.resources.set(src, 'loaded');
                    } else {
                        error('[MapGeo Safety] Resource timeout:', src);
                        this.handleResourceFailure(src);
                    }
                }, config.timeout);

                script.addEventListener('load', () => {
                    clearTimeout(timeoutId);
                    log('[MapGeo Safety] Resource loaded:', src);
                    this.resources.set(src, 'loaded');
                });

                script.addEventListener('error', () => {
                    clearTimeout(timeoutId);
                    error('[MapGeo Safety] Resource failed:', src);
                    this.handleResourceFailure(src);
                });
            }
        }

        handleResourceFailure(src) {
            this.resources.set(src, 'failed');

            // Check if this is a MapGeo CDN resource
            if (src.includes('cdn') || src.includes('amcharts')) {
                log('[MapGeo Safety] CDN resource failed, activating fallback');
                this.activateFallback();
            }
        }

        activateFallback() {
            // Hide map container
            const mapContainers = document.querySelectorAll(
                '.igm-map-container, [class*="mapgeo"], [id*="map-"], .map-widget-container'
            );

            mapContainers.forEach(container => {
                container.style.display = 'none';
            });

            // Show fallback content
            const fallback = document.getElementById('hvac-map-fallback');
            if (fallback) {
                fallback.style.display = 'block';
            }

            // Dispatch custom event
            window.dispatchEvent(new CustomEvent('hvac:mapgeo:fallback', {
                detail: { reason: 'resource_failure' }
            }));
        }
    }

    /**
     * MapGeo API Wrapper
     * Safely wraps MapGeo API calls
     */
    class MapGeoAPIWrapper {
        constructor() {
            this.wrapAPIs();
        }

        wrapAPIs() {
            // Wrap potential MapGeo global functions
            const mapGeoAPIs = [
                'MapGeoWidget',
                'InteractiveGeoMaps',
                'IGM',
                'mapWidget'
            ];

            mapGeoAPIs.forEach(api => {
                if (typeof window[api] !== 'undefined') {
                    this.wrapAPI(api);
                }

                // Set up getter to wrap when loaded
                Object.defineProperty(window, `_original_${api}`, {
                    value: window[api],
                    writable: true
                });

                Object.defineProperty(window, api, {
                    get() {
                        return window[`_wrapped_${api}`] || window[`_original_${api}`];
                    },
                    set(value) {
                        window[`_original_${api}`] = value;
                        window[`_wrapped_${api}`] = new Proxy(value, {
                            construct(target, args) {
                                try {
                                    return new target(...args);
                                } catch (e) {
                                    error('[MapGeo Safety] Construction error:', e);
                                    return {};
                                }
                            },
                            apply(target, thisArg, args) {
                                try {
                                    return target.apply(thisArg, args);
                                } catch (e) {
                                    error('[MapGeo Safety] Execution error:', e);
                                    return null;
                                }
                            }
                        });
                    }
                });
            });
        }

        wrapAPI(apiName) {
            const original = window[apiName];

            window[apiName] = new Proxy(original, {
                construct(target, args) {
                    try {
                        log(`[MapGeo Safety] Creating ${apiName} instance`);
                        return new target(...args);
                    } catch (e) {
                        error(`[MapGeo Safety] Failed to create ${apiName}:`, e);
                        return {};
                    }
                },
                apply(target, thisArg, args) {
                    try {
                        log(`[MapGeo Safety] Calling ${apiName}`);
                        return target.apply(thisArg, args);
                    } catch (e) {
                        error(`[MapGeo Safety] Failed to call ${apiName}:`, e);
                        return null;
                    }
                }
            });
        }
    }

    /**
     * DOM Ready Safety
     * Ensures MapGeo only runs when DOM is safe
     */
    class DOMReadySafety {
        constructor() {
            this.setupSafety();
            this.checkjQueryWithRetry();
        }

        setupSafety() {
            // Intercept jQuery ready calls that might contain MapGeo code
            if (typeof jQuery !== 'undefined') {
                this.wrapjQueryReady();
            } else {
                // If jQuery isn't loaded yet, define a property to trap it when it loads
                Object.defineProperty(window, 'jQuery', {
                    configurable: true,
                    enumerable: true,
                    get: function () {
                        return this._jQuery;
                    },
                    set: function (val) {
                        this._jQuery = val;
                        // Once jQuery is set, wrap its ready function
                        if (val && val.fn && val.fn.ready) {
                            DOMReadySafety.prototype.wrapjQueryReady.call(this);
                        }
                    }
                });
            }
        }

        wrapjQueryReady() {
            const originalReady = jQuery.fn.ready;
            // Guard to prevent double wrapping
            if (originalReady._hvacWrapped) return;

            jQuery.fn.ready = function (callback) {
                const wrappedCallback = function () {
                    try {
                        // Check if MapGeo elements exist before running
                        const hasMapElements = document.querySelector(
                            '.igm-map-container, [class*="mapgeo"], [id*="map-"]'
                        );

                        if (hasMapElements || !callback.toString().includes('map')) {
                            return callback.apply(this, arguments);
                        } else {
                            log('[MapGeo Safety] Skipping map-related ready callback - no map elements found');
                        }
                    } catch (e) {
                        error('[MapGeo Safety] Error in ready callback:', e);
                    }
                };
                return originalReady.call(this, wrappedCallback);
            };
            jQuery.fn.ready._hvacWrapped = true;
            log('[MapGeo Safety] jQuery.ready wrapped successfully');
        }

        checkjQueryWithRetry(attempts = 0) {
            if (typeof window.jQuery !== 'undefined') {
                log('[MapGeo Safety] jQuery detected successfully');
                return;
            }

            if (attempts < 20) { // Retry for ~10 seconds (500ms * 20)
                setTimeout(() => this.checkjQueryWithRetry(attempts + 1), 500);
            } else {
                log('[MapGeo Safety] jQuery not detected after multiple retries (might be loaded async later)');
            }
        }
    }

    /**
     * CDN Health Checker
     * Proactively checks AmCharts CDN availability before MapGeo initialization
     */
    class CDNHealthChecker {
        constructor() {
            this.criticalCDNs = [
                'https://cdn.amcharts.com/lib/version/4.10.29/core.js',
                'https://cdn.amcharts.com/lib/version/4.10.29/maps.js',
                'https://cdn.amcharts.com/lib/4/geodata/usaLow.js'
            ];
            this.timeout = 15000; // Increased to 15s
            this.cacheKey = 'hvac_cdn_health';
            this.cacheExpiry = 10 * 60 * 1000; // 10 minutes
        }

        async checkCDNHealth() {
            log('[MapGeo Safety] Checking AmCharts CDN health...');

            // Check cached result first
            const cached = this.getCachedResult();
            if (cached !== null) {
                log('[MapGeo Safety] Using cached CDN status:', cached);
                return cached;
            }

            // Test primary CDN endpoints
            const results = await Promise.allSettled(
                this.criticalCDNs.map(url => this.testCDNEndpoint(url))
            );

            // Consider CDN healthy if at least 2 out of 3 endpoints work
            const successCount = results.filter(r => r.status === 'fulfilled' && r.value).length;
            const isHealthy = successCount >= 2;

            log(`[MapGeo Safety] CDN health check: ${successCount}/${this.criticalCDNs.length} endpoints available`);

            // Cache result
            this.setCachedResult(isHealthy);

            return isHealthy;
        }

        async testCDNEndpoint(url) {
            try {
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), this.timeout);

                const response = await fetch(url, {
                    method: 'HEAD',
                    mode: 'no-cors', // Allow cross-origin requests
                    signal: controller.signal
                });

                clearTimeout(timeoutId);
                return true; // If we get here, endpoint is reachable
            } catch (e) {
                log(`[MapGeo Safety] CDN endpoint failed: ${url} - ${e.message}`);
                return false;
            }
        }

        getCachedResult() {
            try {
                const cached = sessionStorage.getItem(this.cacheKey);
                if (cached) {
                    const data = JSON.parse(cached);
                    if (Date.now() - data.timestamp < this.cacheExpiry) {
                        return data.healthy;
                    }
                }
            } catch (e) {
                log('[MapGeo Safety] Error reading CDN cache:', e.message);
            }
            return null;
        }

        setCachedResult(healthy) {
            try {
                const data = {
                    healthy: healthy,
                    timestamp: Date.now()
                };
                sessionStorage.setItem(this.cacheKey, JSON.stringify(data));
            } catch (e) {
                log('[MapGeo Safety] Error caching CDN status:', e.message);
            }
        }
    }

    /**
     * Initialize all safety systems with proactive CDN checking
     */
    async function initializeSafetySystems() {
        // Only initialize on pages with potential maps
        if (!document.querySelector('[class*="map"], [id*="map"]')) {
            log('[MapGeo Safety] No map elements detected, skipping initialization');
            return;
        }

        // CRITICAL: Check CDN health before allowing MapGeo to initialize
        const cdnChecker = new CDNHealthChecker();
        const cdnHealthy = await cdnChecker.checkCDNHealth();

        if (!cdnHealthy) {
            error('[MapGeo Safety] AmCharts CDN unavailable - activating immediate fallback');

            // Show fallback state
            UIManager.showFallbackState();

            // Dispatch event to notify other systems
            window.dispatchEvent(new CustomEvent('hvac:mapgeo:cdn_unavailable', {
                detail: { reason: 'amcharts_cdn_timeout' }
            }));

            log('[MapGeo Safety] Immediate fallback activated due to CDN unavailability');
            return;
        }

        log('[MapGeo Safety] AmCharts CDN healthy - proceeding with MapGeo initialization');

        // Show map state since CDN is healthy
        UIManager.showMapState();

        // Initialize monitors
        new ResourceLoadMonitor();
        new MapGeoAPIWrapper();
        new DOMReadySafety();

        // Set up periodic health check with shorter timeout now that we pre-checked CDN
        let healthCheckCount = 0;
        const healthCheckInterval = setInterval(() => {
            healthCheckCount++;

            // Check if map loaded successfully
            const mapLoaded = document.querySelector('.igm-map-loaded, .mapgeo-loaded, .map-initialized');

            if (mapLoaded) {
                log('[MapGeo Safety] Map loaded successfully');
                clearInterval(healthCheckInterval);
            } else if (healthCheckCount >= 30) {
                // Increased to 30 seconds to match global timeout
                error('[MapGeo Safety] Map failed to load after 30 seconds');
                clearInterval(healthCheckInterval);

                // Activate fallback if configured
                if (config.fallbackEnabled) {
                    const monitor = new ResourceLoadMonitor();
                    monitor.activateFallback();
                }
            }
        }, 1000);

        log('[MapGeo Safety] All safety systems initialized with CDN pre-check');
    }

    /**
     * Enhanced UI Management for CDN fallbacks
     */
    class UIManager {
        static showLoadingState() {
            const loading = document.getElementById('hvac-map-loading');
            const fallback = document.getElementById('hvac-map-fallback');
            const mapWrapper = document.querySelector('.hvac-mapgeo-wrapper');

            if (loading) loading.style.display = 'block';
            if (fallback) fallback.style.display = 'none';
            if (mapWrapper) mapWrapper.style.display = 'none';

            log('[MapGeo Safety] Loading state activated');
        }

        static showFallbackState() {
            const loading = document.getElementById('hvac-map-loading');
            const fallback = document.getElementById('hvac-map-fallback');
            const mapWrapper = document.querySelector('.hvac-mapgeo-wrapper');

            if (loading) loading.style.display = 'none';
            if (fallback) fallback.style.display = 'block';
            if (mapWrapper) mapWrapper.style.display = 'none';

            log('[MapGeo Safety] Fallback state activated');
        }

        static showMapState() {
            const loading = document.getElementById('hvac-map-loading');
            const fallback = document.getElementById('hvac-map-fallback');
            const mapWrapper = document.querySelector('.hvac-mapgeo-wrapper');

            if (loading) loading.style.display = 'none';
            if (fallback) fallback.style.display = 'none';
            if (mapWrapper) mapWrapper.style.display = 'block';

            log('[MapGeo Safety] Map state activated');
        }

        static setupRetryButton() {
            const retryButton = document.querySelector('.hvac-retry-map');
            if (retryButton) {
                retryButton.addEventListener('click', async () => {
                    retryButton.disabled = true;
                    retryButton.textContent = 'Checking...';

                    try {
                        UIManager.showLoadingState();

                        // Clear CDN health cache
                        const cdnChecker = new CDNHealthChecker();
                        sessionStorage.removeItem(cdnChecker.cacheKey);

                        // Re-check CDN health
                        const isHealthy = await cdnChecker.checkCDNHealth();

                        if (isHealthy) {
                            log('[MapGeo Safety] CDN healthy on retry - reloading page');
                            window.location.reload();
                        } else {
                            UIManager.showFallbackState();
                            retryButton.textContent = 'Still Unavailable';
                            setTimeout(() => {
                                retryButton.textContent = 'Try Loading Map Again';
                                retryButton.disabled = false;
                            }, 3000);
                        }
                    } catch (e) {
                        error('[MapGeo Safety] Error during retry:', e.message);
                        UIManager.showFallbackState();
                        retryButton.textContent = 'Error - Try Again';
                        retryButton.disabled = false;
                    }
                });
            }
        }
    }

    // Initialize when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            UIManager.showLoadingState();
            UIManager.setupRetryButton();
            initializeSafetySystems();
        });
    } else {
        // DOM already loaded
        UIManager.showLoadingState();
        UIManager.setupRetryButton();
        initializeSafetySystems();
    }

    // Enhanced safety API for debugging and manual control
    window.HVACMapGeoSafety = {
        config: config,
        reinitialize: initializeSafetySystems,
        activateFallback: () => {
            const monitor = new ResourceLoadMonitor();
            monitor.activateFallback();
        },
        ui: UIManager,
        checkCDN: async () => {
            const checker = new CDNHealthChecker();
            return await checker.checkCDNHealth();
        },
        clearCDNCache: () => {
            const checker = new CDNHealthChecker();
            sessionStorage.removeItem(checker.cacheKey);
            log('[MapGeo Safety] CDN cache cleared');
        }
    };

})();