/**
 * Loading States Manager
 * Manages loading indicators, progress bars, and loading hierarchies throughout the UI
 * Provides comprehensive loading state tracking for async operations
 */

(function() {
    'use strict';

    AppModules.require('notifications');
    AppModules.register('loading-states');

    // Loading state tracking
    const loadingStates = new Map();
    const loadingHierarchy = new Map(); // Parent-child relationships
    const loadingQueue = [];

    // Configuration
    const config = {
        maxConcurrentLoadings: 5,
        defaultFadeDelay: 300,
        skeletonTransitionDuration: 200,
        progressUpdateInterval: 50
    };

    // Loading state manager class
    class LoadingStateManager {
        constructor() {
            this.activeLoadings = new Set();
            this.loadingElements = new WeakMap();
            this.progressTrackers = new Map();
        }

        /**
         * Start a loading operation
         * @param {string} id - Unique loading identifier
         * @param {Object} options - Loading options
         * @returns {LoadingContext} Loading context for management
         */
        start(id, options = {}) {
            const context = new LoadingContext(id, options);
            this.activeLoadings.add(id);
            loadingStates.set(id, context);
            context.start();

            // Check queue if at capacity
            if (this.activeLoadings.size >= config.maxConcurrentLoadings) {
                this.processQueue();
            }

            this.log('Started loading:', id);
            return context;
        }

        /**
         * End a loading operation
         * @param {string} id - Loading identifier
         * @param {boolean} success - Whether loading was successful
         */
        end(id, success = true) {
            const context = loadingStates.get(id);
            if (!context) return;

            context.end(success);
            this.activeLoadings.delete(id);
            loadingStates.delete(id);

            // Process next in queue
            this.processQueue();
            this.log('Ended loading:', id, success ? 'success' : 'failed');
        }

        /**
         * Update loading progress
         * @param {string} id - Loading identifier
         * @param {number} progress - Progress (0-100)
         */
        updateProgress(id, progress) {
            const context = loadingStates.get(id);
            if (context) {
                context.updateProgress(progress);
            }
        }

        /**
         * Process loading queue
         */
        processQueue() {
            while (this.activeLoadings.size < config.maxConcurrentLoadings && loadingQueue.length > 0) {
                const queuedItem = loadingQueue.shift();
                queuedItem.resolve();
            }
        }

        /**
         * Add to loading hierarchy
         * @param {string} parentId - Parent loading ID
         * @param {string} childId - Child loading ID
         */
        addToHierarchy(parentId, childId) {
            if (!loadingHierarchy.has(parentId)) {
                loadingHierarchy.set(parentId, new Set());
            }
            loadingHierarchy.get(parentId).add(childId);
        }

        /**
         * Get loading context by ID
         * @param {string} id - Loading identifier
         * @returns {LoadingContext|null}
         */
        get(id) {
            return loadingStates.get(id) || null;
        }

        /**
         * Get all active loading contexts
         * @returns {Array<LoadingContext>}
         */
        getAllActive() {
            return Array.from(this.activeLoadings).map(id => loadingStates.get(id));
        }

        /**
         * Check if any loading is active
         * @returns {boolean}
         */
        isAnyLoading() {
            return this.activeLoadings.size > 0;
        }

        /**
         * Check if specific loading is active
         * @param {string} id - Loading identifier
         * @returns {boolean}
         */
        isLoading(id) {
            return this.activeLoadings.has(id);
        }

        log(...args) {
            if (window.AppConfig?.debug?.loadingStates) {
                console.log('[LoadingStates]', ...args);
            }
        }
    }

    // Loading context class for individual loading operations
    class LoadingContext {
        constructor(id, options = {}) {
            this.id = id;
            this.options = {
                type: options.type || 'overlay', // overlay, button, inline, skeleton
                element: options.element || null,
                text: options.text || 'Loading...',
                showProgress: options.showProgress || false,
                cancellable: options.cancellable || false,
                timeout: options.timeout || 30000, // Default 30 seconds
                hierarchy: options.hierarchy || null,
                ...options
            };

            this.startTime = null;
            this.endTime = null;
            this.progress = 0;
            this.isActive = false;
            this.timeoutId = null;

            // Create loading element if needed
            if (!this.options.element) {
                this.options.element = this.createLoadingElement();
            }
        }

        start() {
            this.startTime = Date.now();
            this.isActive = true;

            // Show loading UI
            this.show();

            // Set timeout fail-safe
            if (this.options.timeout > 0) {
                this.timeoutId = setTimeout(() => {
                    if (this.isActive) {
                        this.end(false);
                        AppLogger.warn(`Loading operation ${this.id} timed out after ${this.options.timeout}ms`);
                    }
                }, this.options.timeout);
            }

            // Add to hierarchy if specified
            if (this.options.hierarchy) {
                loadingStateManager.addToHierarchy(this.options.hierarchy, this.id);
            }
        }

        end(success = true) {
            if (!this.isActive) return;

            this.endTime = Date.now();
            this.isActive = false;

            // Clear timeout
            if (this.timeoutId) {
                clearTimeout(this.timeoutId);
                this.timeoutId = null;
            }

            // Hide loading UI
            this.hide(success);

            // Log duration
            const duration = this.endTime - this.startTime;
            loadingStateManager.log(`Loading ${this.id} completed in ${duration}ms`);
        }

        updateProgress(progress) {
            this.progress = Math.max(0, Math.min(100, progress));
            this.updateProgressUI();

            // Trigger progress event
            this.trigger('progress', { progress: this.progress });
        }

        show() {
            const element = this.options.element;
            if (!element) return;

            // Add loading class
            element.classList.add('loading');

            // Handle different loading types
            switch (this.options.type) {
                case 'button':
                    this.showButtonLoading(element);
                    break;
                case 'skeleton':
                    this.showSkeletonLoading(element);
                    break;
                case 'inline':
                    this.showInlineLoading(element);
                    break;
                case 'overlay':
                default:
                    this.showOverlayLoading(element);
                    break;
            }

            // Add to DOM if not already present
            if (!element.parentElement && element !== document.body) {
                element.style.display = 'block';
            }

            // Trigger show event
            this.trigger('show');
        }

        hide(success = true) {
            const element = this.options.element;
            if (!element) return;

            // Handle different loading types
            switch (this.options.type) {
                case 'button':
                    this.hideButtonLoading(element, success);
                    break;
                case 'skeleton':
                    this.hideSkeletonLoading(element, success);
                    break;
                case 'inline':
                    this.hideInlineLoading(element, success);
                    break;
                case 'overlay':
                default:
                    this.hideOverlayLoading(element, success);
                    break;
            }

            // Remove loading class after transition
            setTimeout(() => {
                element.classList.remove('loading');
            }, config.defaultFadeDelay);

            // Trigger hide event
            this.trigger('hide', { success });
        }

        createLoadingElement() {
            const element = document.createElement('div');
            element.className = `loading-state loading-state--${this.options.type}`;
            element.setAttribute('data-loading-id', this.id);
            element.setAttribute('aria-live', 'polite');
            element.setAttribute('aria-label', this.options.text);

            switch (this.options.type) {
                case 'button':
                    element.innerHTML = `
                        <span class="loading-spinner spinner-border spinner-border-sm"></span>
                        <span class="loading-text">${this.options.text}</span>
                    `;
                    break;

                case 'skeleton':
                    element.innerHTML = this.createSkeletonHTML();
                    break;

                case 'inline':
                    element.innerHTML = `
                        <div class="loading-inline">
                            <span class="loading-spinner"></span>
                            <span class="loading-text">${this.options.text}</span>
                        </div>
                    `;
                    break;

                case 'overlay':
                default:
                    element.innerHTML = `
                        <div class="loading-overlay">
                            <div class="loading-content">
                                <div class="loading-spinner"></div>
                                ${this.options.showProgress ? '<div class="progress-bar"><div class="progress-fill"></div></div>' : ''}
                                <div class="loading-text">${this.options.text}</div>
                            </div>
                        </div>
                    `;
                    break;
            }

            return element;
        }

        createSkeletonHTML() {
            // Create skeleton based on element content
            return `
                <div class="skeleton-container">
                    <div class="skeleton skeleton-card">
                        <div class="skeleton-header">
                            <div class="skeleton-circle"></div>
                            <div class="skeleton-content">
                                <div class="skeleton-line"></div>
                                <div class="skeleton-line skeleton-line--short"></div>
                            </div>
                        </div>
                        <div class="skeleton-body">
                            <div class="skeleton-line"></div>
                            <div class="skeleton-line"></div>
                            <div class="skeleton-line skeleton-line--short"></div>
                        </div>
                    </div>
                </div>
            `;
        }

        showButtonLoading(button) {
            // Store original content
            const originalHTML = button.innerHTML;
            this.loadingElements.set(button, { originalHTML });

            // Add loading spinner to button
            const loadingContent = `
                <span class="loading-spinner spinner-border spinner-border-sm" aria-hidden="true"></span>
                <span class="visually-hidden">Loading...</span>
            `;

            // Keep button text but add spinner
            const textSpan = button.querySelector('.loading-text') || document.createElement('span');
            textSpan.className = 'loading-text';
            textSpan.textContent = this.options.text;

            button.innerHTML = loadingContent + textSpan.outerHTML;
            button.disabled = true;
            button.setAttribute('aria-busy', 'true');
        }

        hideButtonLoading(button, success) {
            const stored = this.loadingElements.get(button);
            if (stored) {
                // Restore original content or keep success state
                setTimeout(() => {
                    button.innerHTML = stored.originalHTML;
                    button.disabled = false;
                    button.removeAttribute('aria-busy');

                    if (success) {
                        button.classList.add('btn-success-pulse');
                        setTimeout(() => button.classList.remove('btn-success-pulse'), 1000);
                    }
                }, config.defaultFadeDelay);
            }
        }

        showSkeletonLoading(element) {
            // Add skeleton overlay
            element.classList.add('skeleton-loading');

            // Find content areas and replace with skeletons
            const contentAreas = element.querySelectorAll('[data-skeleton]');
            contentAreas.forEach(area => {
                const skeletonType = area.dataset.skeleton || 'line';
                area.innerHTML = this.createSkeletonForType(skeletonType);
            });

            // If no skeleton areas defined, add general skeleton
            if (contentAreas.length === 0) {
                element.innerHTML = this.createSkeletonHTML();
            }
        }

        hideSkeletonLoading(element, success) {
            element.classList.remove('skeleton-loading');

            // Fade out skeletons
            const skeletons = element.querySelectorAll('.skeleton');
            skeletons.forEach(skeleton => {
                skeleton.classList.add('skeleton-exit');
                setTimeout(() => skeleton.remove(), config.skeletonTransitionDuration);
            });
        }

        showOverlayLoading(element) {
            // Position overlay
            const overlay = element.querySelector('.loading-overlay');
            if (overlay) {
                overlay.style.display = 'flex';
                element.classList.add('has-loading-overlay');
            }
        }

        hideOverlayLoading(element, success) {
            const overlay = element.querySelector('.loading-overlay');
            if (overlay) {
                overlay.style.display = 'none';
                element.classList.remove('has-loading-overlay');
            }
        }

        showInlineLoading(element) {
            // Just show the inline loading content
            element.style.display = 'inline-block';
        }

        hideInlineLoading(element, success) {
            element.style.display = 'none';
        }

        updateProgressUI() {
            if (!this.options.showProgress) return;

            const progressFill = this.options.element.querySelector('.progress-fill');
            if (progressFill) {
                progressFill.style.width = `${this.progress}%`;
            }

            const progressText = this.options.element.querySelector('.progress-text');
            if (progressText) {
                progressText.textContent = `${Math.round(this.progress)}%`;
            }
        }

        createSkeletonForType(type) {
            switch (type) {
                case 'circle':
                    return '<div class="skeleton skeleton-circle"></div>';
                case 'rectangle':
                    return '<div class="skeleton skeleton-rectangle"></div>';
                case 'text':
                    return '<div class="skeleton skeleton-line"></div>';
                case 'title':
                    return '<div class="skeleton skeleton-line skeleton-line--title"></div>';
                default:
                    return '<div class="skeleton skeleton-line"></div>';
            }
        }

        trigger(eventName, data = {}) {
            // Trigger loading events
            const event = new CustomEvent(`loading:${eventName}`, {
                detail: {
                    id: this.id,
                    context: this,
                    ...data
                }
            });
            document.dispatchEvent(event);
        }
    }

    // Global loading state manager instance
    const loadingStateManager = new LoadingStateManager();

    // API Functions
    const API = {
        /**
         * Start a loading operation
         */
        startLoading(id, options) {
            return loadingStateManager.start(id, options);
        },

        /**
         * End a loading operation
         */
        endLoading(id, success = true) {
            loadingStateManager.end(id, success);
        },

        /**
         * Update loading progress
         */
        updateProgress(id, progress) {
            loadingStateManager.updateProgress(id, progress);
        },

        /**
         * Check if loading is active
         */
        isLoading(id) {
            return loadingStateManager.isLoading(id);
        },

        /**
         * Check if any loading is active
         */
        isAnyLoading() {
            return loadingStateManager.isAnyLoading();
        },

        /**
         * Create button loading state
         */
        showButtonLoading(button, text = 'Loading...') {
            const loadingId = `button-${Date.now()}-${Math.random()}`;
            const context = loadingStateManager.start(loadingId, {
                type: 'button',
                element: button,
                text: text,
                showProgress: false
            });
            button.setAttribute('data-loading-id', loadingId);
            return context;
        },

        /**
         * Show page-level loading overlay
         */
        showPageLoading(text = 'Loading...') {
            return loadingStateManager.start('page-loading', {
                type: 'overlay',
                element: document.body,
                text: text,
                hierarchy: 'global'
            });
        },

        /**
         * Show section loading with skeleton
         */
        showSectionLoading(element, text = 'Loading...') {
            const loadingId = `section-${Date.now()}`;
            return loadingStateManager.start(loadingId, {
                type: 'skeleton',
                element: element,
                text: text
            });
        },

        /**
         * Show content loading overlay
         */
        showContentLoading(container, text = 'Loading...') {
            const loadingId = `content-${Date.now()}`;
            const overlay = document.createElement('div');
            overlay.className = 'loading-overlay';
            overlay.innerHTML = `
                <div class="loading-content">
                    <div class="loading-spinner"></div>
                    <div class="loading-text">${text}</div>
                </div>
            `;
            container.appendChild(overlay);
            container.classList.add('has-loading-overlay');

            return loadingStateManager.start(loadingId, {
                type: 'overlay',
                element: container,
                text: text,
                customOverlay: true
            });
        },

        /**
         * Show video loading progress
         */
        showVideoLoading(progress = null) {
            return loadingStateManager.start('video-loading', {
                type: 'overlay',
                element: document.getElementById('videoSection'),
                text: 'Loading video...',
                showProgress: progress !== null
            });
        },

        /**
         * Show chat refresh loading
         */
        showChatRefreshLoading() {
            const chatSection = document.getElementById('chatSection');
            return API.showSectionLoading(chatSection, 'Refreshing chat...');
        },

        /**
         * Create loading queue for sequential operations
         */
        createLoadingQueue() {
            return {
                queue: [],
                add(operation, options = {}) {
                    const promise = new Promise((resolve, reject) => {
                        this.queue.push({
                            operation,
                            options,
                            resolve,
                            reject
                        });
                    });
                    return promise;
                },
                process(concurrency = 1) {
                    return Promise.all(
                        Array.from({ length: concurrency }, () => this.processNext())
                    );
                },
                async processNext() {
                    if (this.queue.length === 0) return;

                    const item = this.queue.shift();
                    try {
                        const result = await item.operation();
                        item.resolve(result);
                        return result;
                    } catch (error) {
                        item.reject(error);
                        throw error;
                    }
                }
            };
        }
    };

    // Export API
    window.LoadingStates = API;

    // Initialize when DOM is ready
    document.addEventListener('DOMContentLoaded', () => {
        // Add global loading state CSS if not present
        if (!document.getElementById('loading-states-styles')) {
            const style = document.createElement('style');
            style.id = 'loading-states-styles';
            style.textContent = `
                /* Loading States Styles */
                .loading-state {
                    position: relative;
                }

                .loading-overlay {
                    position: absolute;
                    top: 0;
                    left: 0;
                    right: 0;
                    bottom: 0;
                    background-color: rgba(255, 255, 255, 0.9);
                    backdrop-filter: blur(2px);
                    display: none;
                    justify-content: center;
                    align-items: center;
                    z-index: 1000;
                    transition: opacity 0.3s ease;
                }

                .loading-content {
                    text-align: center;
                    padding: 1rem;
                }

                .loading-text {
                    margin-top: 0.5rem;
                    font-weight: 500;
                    color: var(--dodgers-blue);
                }

                .has-loading-overlay {
                    position: relative;
                }

                .skeleton-loading .skeleton {
                    animation: skeleton-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
                }

                .skeleton-loading .skeleton-exit {
                    opacity: 0;
                    transition: opacity 0.2s ease;
                }

                .btn-success-pulse {
                    animation: pulse 0.5s ease-in-out;
                    background-color: var(--dodgers-blue) !important;
                }

                .loading-inline {
                    display: inline-flex;
                    align-items: center;
                    gap: 0.5rem;
                }

                /* Progress bar in loading states */
                .loading-content .progress-bar {
                    margin-top: 1rem;
                    width: 200px;
                    height: 4px;
                    background-color: var(--dodgers-gray-200);
                    border-radius: 2px;
                    overflow: hidden;
                }

                .loading-content .progress-fill {
                    height: 100%;
                    background: linear-gradient(90deg, var(--dodgers-blue), var(--dodgers-red));
                    width: 0%;
                    transition: width 0.3s ease;
                }

                /* Mobile optimizations */
                @media (max-width: 767px) {
                    .loading-overlay {
                        padding: 0.5rem;
                    }

                    .loading-content .progress-bar {
                        width: 150px;
                    }
                }

                /* Accessibility */
                .visually-hidden {
                    position: absolute !important;
                    width: 1px !important;
                    height: 1px !important;
                    padding: 0 !important;
                    margin: -1px !important;
                    overflow: hidden !important;
                    clip: rect(0, 0, 0, 0) !important;
                    white-space: nowrap !important;
                    border: 0 !important;
                }
            `;
            document.head.appendChild(style);
        }

        AppLogger.log('Loading States module initialized');
    });

    AppLogger.log('Loading States module loaded');

})();
