/**
 * ThrillWiki Performance Optimization Module
 *
 * Features:
 * - Advanced lazy loading with Intersection Observer
 * - Image preloading and progressive loading
 * - Dynamic module loading (code splitting)
 * - Memory leak prevention utilities
 * - Event listener cleanup management
 */

// =============================================================================
// Event Manager - Memory Leak Prevention
// =============================================================================

/**
 * EventManager class for preventing memory leaks from orphaned event listeners.
 * Use this for dynamic elements that may be removed from the DOM.
 */
class EventManager {
    constructor() {
        this.listeners = new Map();
    }

    /**
     * Add an event listener with automatic cleanup tracking
     * @param {Element} element - The DOM element
     * @param {string} event - Event type (e.g., 'click')
     * @param {Function} handler - Event handler function
     * @param {Object} options - Event listener options
     */
    addEventListener(element, event, handler, options = {}) {
        if (!element) return;

        if (!this.listeners.has(element)) {
            this.listeners.set(element, []);
        }
        this.listeners.get(element).push({ event, handler, options });
        element.addEventListener(event, handler, options);
    }

    /**
     * Remove all tracked event listeners for an element
     * @param {Element} element - The DOM element to clean up
     */
    removeListeners(element) {
        if (!this.listeners.has(element)) return;

        const handlers = this.listeners.get(element);
        handlers.forEach(({ event, handler, options }) => {
            element.removeEventListener(event, handler, options);
        });
        this.listeners.delete(element);
    }

    /**
     * Clean up all tracked event listeners
     */
    cleanup() {
        this.listeners.forEach((handlers, element) => {
            handlers.forEach(({ event, handler, options }) => {
                element.removeEventListener(event, handler, options);
            });
        });
        this.listeners.clear();
    }
}

// Global event manager instance
window.ThrillWikiEventManager = new EventManager();

// =============================================================================
// Advanced Lazy Loading with Intersection Observer
// =============================================================================

/**
 * LazyLoader class for efficient image lazy loading using Intersection Observer.
 * Supports progressive loading with blur-up placeholder technique.
 */
class LazyLoader {
    constructor(options = {}) {
        this.options = {
            rootMargin: options.rootMargin || '50px 0px',
            threshold: options.threshold || 0.01,
            loadingClass: options.loadingClass || 'lazy-loading',
            loadedClass: options.loadedClass || 'lazy-loaded',
            errorClass: options.errorClass || 'lazy-error',
        };

        this.observer = null;
        this.init();
    }

    init() {
        // Check for Intersection Observer support
        if (!('IntersectionObserver' in window)) {
            // Fallback: load all images immediately
            this.loadAllImages();
            return;
        }

        this.observer = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    this.loadImage(entry.target);
                    observer.unobserve(entry.target);
                }
            });
        }, {
            rootMargin: this.options.rootMargin,
            threshold: this.options.threshold,
        });

        // Observe all lazy images
        this.observeImages();
    }

    observeImages() {
        const lazyImages = document.querySelectorAll('img[data-src], img.lazy');
        lazyImages.forEach(img => {
            if (this.observer) {
                this.observer.observe(img);
            }
        });
    }

    loadImage(img) {
        const src = img.dataset.src || img.getAttribute('data-src');
        const srcset = img.dataset.srcset || img.getAttribute('data-srcset');

        if (!src && !srcset) return;

        img.classList.add(this.options.loadingClass);

        // Create a temporary image to preload
        const tempImage = new Image();

        tempImage.onload = () => {
            if (src) img.src = src;
            if (srcset) img.srcset = srcset;

            img.classList.remove(this.options.loadingClass);
            img.classList.add(this.options.loadedClass);
            img.classList.remove('lazy');

            // Trigger custom event for tracking
            img.dispatchEvent(new CustomEvent('lazyloaded', { bubbles: true }));
        };

        tempImage.onerror = () => {
            img.classList.remove(this.options.loadingClass);
            img.classList.add(this.options.errorClass);
            console.warn('Failed to load image:', src);
        };

        // Start loading
        tempImage.src = src || '';
        if (srcset) tempImage.srcset = srcset;
    }

    loadAllImages() {
        const lazyImages = document.querySelectorAll('img[data-src], img.lazy');
        lazyImages.forEach(img => this.loadImage(img));
    }

    // Add new images to observation (for dynamically added content)
    observe(img) {
        if (this.observer) {
            this.observer.observe(img);
        } else {
            this.loadImage(img);
        }
    }

    destroy() {
        if (this.observer) {
            this.observer.disconnect();
            this.observer = null;
        }
    }
}

// =============================================================================
// Dynamic Module Loading (Code Splitting)
// =============================================================================

/**
 * ModuleLoader for lazy loading JavaScript modules only when needed.
 * Reduces initial bundle size and improves page load time.
 */
class ModuleLoader {
    constructor() {
        this.loadedModules = new Set();
        this.loadingPromises = new Map();
    }

    /**
     * Dynamically load a JavaScript module
     * @param {string} modulePath - Path to the module
     * @returns {Promise} - Resolves when module is loaded
     */
    async load(modulePath) {
        // Return cached if already loaded
        if (this.loadedModules.has(modulePath)) {
            return Promise.resolve();
        }

        // Return existing promise if currently loading
        if (this.loadingPromises.has(modulePath)) {
            return this.loadingPromises.get(modulePath);
        }

        // Create loading promise
        const loadPromise = new Promise((resolve, reject) => {
            const script = document.createElement('script');
            script.src = modulePath;
            script.async = true;

            script.onload = () => {
                this.loadedModules.add(modulePath);
                this.loadingPromises.delete(modulePath);
                resolve();
            };

            script.onerror = () => {
                this.loadingPromises.delete(modulePath);
                reject(new Error(`Failed to load module: ${modulePath}`));
            };

            document.head.appendChild(script);
        });

        this.loadingPromises.set(modulePath, loadPromise);
        return loadPromise;
    }

    /**
     * Conditionally load a module if an element exists
     * @param {string} selector - CSS selector to check
     * @param {string} modulePath - Path to the module to load
     */
    async loadIfNeeded(selector, modulePath) {
        if (document.querySelector(selector)) {
            await this.load(modulePath);
        }
    }
}

// Global module loader instance
window.ThrillWikiModuleLoader = new ModuleLoader();

// =============================================================================
// Lightbox Functionality (Alpine.js Component)
// =============================================================================

document.addEventListener('alpine:init', () => {
    Alpine.data('lightbox', () => ({
        isOpen: false,
        imgSrc: '',
        imgAlt: '',

        open(event) {
            const img = event.target.tagName === 'IMG' ? event.target : event.target.querySelector('img');
            if (img) {
                // Use full-size image if available via data-full-src
                this.imgSrc = img.dataset.fullSrc || img.src;
                this.imgAlt = img.alt;
                this.isOpen = true;
                document.body.style.overflow = 'hidden';
            }
        },

        close() {
            this.isOpen = false;
            this.imgSrc = '';
            this.imgAlt = '';
            document.body.style.overflow = '';
        },

        // Cleanup method to prevent memory leaks
        destroy() {
            this.close();
        }
    }));
});

// =============================================================================
// Initialization
// =============================================================================

// Global lazy loader instance
let lazyLoader = null;

document.addEventListener('DOMContentLoaded', () => {
    // Initialize lazy loader
    lazyLoader = new LazyLoader();
    window.ThrillWikiLazyLoader = lazyLoader;

    // Add native lazy loading to images that don't have it
    const images = document.querySelectorAll('img:not([loading])');
    images.forEach(img => {
        // Set eager for above-the-fold images (first 3 visible images)
        const rect = img.getBoundingClientRect();
        const isAboveFold = rect.top < window.innerHeight && rect.top >= 0;
        img.setAttribute('loading', isAboveFold ? 'eager' : 'lazy');
    });

    // Handle HTMX content updates
    document.body.addEventListener('htmx:afterSwap', (event) => {
        // Re-observe any new lazy images after HTMX updates
        if (lazyLoader) {
            const newImages = event.detail.target.querySelectorAll('img[data-src], img.lazy');
            newImages.forEach(img => lazyLoader.observe(img));
        }
    });
});

// Cleanup on page unload
window.addEventListener('beforeunload', () => {
    if (window.ThrillWikiEventManager) {
        window.ThrillWikiEventManager.cleanup();
    }
    if (lazyLoader) {
        lazyLoader.destroy();
    }
});

// =============================================================================
// Export for use in other modules
// =============================================================================

window.ThrillWikiOptimization = {
    EventManager,
    LazyLoader,
    ModuleLoader,
};
