/**
 * RSL Video Player Component
 * Version: 1.0.0
 *
 * A fully accessible video player supporting YouTube, Vimeo,
 * and self-hosted videos with custom controls, lazy loading,
 * captions, and full keyboard navigation.
 *
 * WCAG 2.1 AA Compliant:
 * - Full keyboard navigation (Space, arrows, M, F, C, 0-9)
 * - Screen reader announcements via aria-live
 * - Role="application" for keyboard capture
 * - Visible focus indicators
 * - Respects prefers-reduced-motion
 *
 * @namespace RSL.VideoPlayer
 */

(function() {
    'use strict';

    // Namespace
    window.RSL = window.RSL || {};

    // Track initialized instances
    const instances = new Map();

    // SVG Icons
    const ICONS = {
        play: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M8 5v14l11-7z"/></svg>',
        pause: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>',
        volumeHigh: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/></svg>',
        volumeLow: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"/></svg>',
        volumeMute: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>',
        fullscreen: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>',
        fullscreenExit: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/></svg>',
        captions: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 7H9.5v-.5h-2v3h2V13H11v1c0 .55-.45 1-1 1H7c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v1zm7 0h-1.5v-.5h-2v3h2V13H18v1c0 .55-.45 1-1 1h-3c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v1z"/></svg>',
        replay: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z"/></svg>',
        error: '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>'
    };

    /**
     * Default configuration
     */
    const DEFAULTS = {
        autoplay: false,
        muted: false,
        loop: false,
        controls: true,
        lazy: true,
        aspect: '16:9',
        size: null,
        start: 0,
        end: null,
        preload: 'metadata'
    };

    /**
     * Parse video URL to determine type and extract ID
     * @param {string} url - Video URL
     * @returns {Object} { type, id, url }
     */
    function parseVideoUrl(url) {
        if (!url) return { type: null, id: null, url: null };

        // YouTube patterns
        const youtubePatterns = [
            /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/,
            /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/
        ];

        for (const pattern of youtubePatterns) {
            const match = url.match(pattern);
            if (match) {
                return { type: 'youtube', id: match[1], url: url };
            }
        }

        // Vimeo patterns
        const vimeoPatterns = [
            /vimeo\.com\/(\d+)/,
            /player\.vimeo\.com\/video\/(\d+)/
        ];

        for (const pattern of vimeoPatterns) {
            const match = url.match(pattern);
            if (match) {
                return { type: 'vimeo', id: match[1], url: url };
            }
        }

        // Self-hosted (MP4, WebM, etc.)
        if (url.match(/\.(mp4|webm|ogg|mov)(\?.*)?$/i)) {
            return { type: 'self', id: null, url: url };
        }

        // Default to self-hosted if we can't determine
        return { type: 'self', id: null, url: url };
    }

    /**
     * Format time in seconds to MM:SS or HH:MM:SS
     * @param {number} seconds - Time in seconds
     * @returns {string} Formatted time string
     */
    function formatTime(seconds) {
        if (isNaN(seconds) || !isFinite(seconds)) return '0:00';

        const hours = Math.floor(seconds / 3600);
        const minutes = Math.floor((seconds % 3600) / 60);
        const secs = Math.floor(seconds % 60);

        if (hours > 0) {
            return `${hours}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
        }
        return `${minutes}:${String(secs).padStart(2, '0')}`;
    }

    /**
     * Format time for screen readers
     * @param {number} seconds - Time in seconds
     * @returns {string} Human-readable time string
     */
    function formatTimeForSR(seconds) {
        if (isNaN(seconds) || !isFinite(seconds)) return '0 seconds';

        const hours = Math.floor(seconds / 3600);
        const minutes = Math.floor((seconds % 3600) / 60);
        const secs = Math.floor(seconds % 60);

        const parts = [];
        if (hours > 0) parts.push(`${hours} hour${hours !== 1 ? 's' : ''}`);
        if (minutes > 0) parts.push(`${minutes} minute${minutes !== 1 ? 's' : ''}`);
        if (secs > 0 || parts.length === 0) parts.push(`${secs} second${secs !== 1 ? 's' : ''}`);

        return parts.join(' ');
    }

    /**
     * Get configuration from data attributes
     * @param {HTMLElement} element - The video player element
     * @returns {Object} Configuration object
     */
    function getConfig(element) {
        const src = element.dataset.videoSrc || element.dataset.src || '';
        const videoInfo = parseVideoUrl(src);

        return {
            src: src,
            type: element.dataset.videoType || videoInfo.type,
            videoId: videoInfo.id,
            poster: element.dataset.videoPoster || element.dataset.poster || null,
            title: element.dataset.videoTitle || element.dataset.title || 'Video',
            autoplay: element.dataset.videoAutoplay === 'true',
            muted: element.dataset.videoMuted === 'true',
            loop: element.dataset.videoLoop === 'true',
            controls: element.dataset.videoControls !== 'false',
            lazy: element.dataset.videoLazy !== 'false',
            aspect: element.dataset.videoAspect || DEFAULTS.aspect,
            size: element.dataset.videoSize || DEFAULTS.size,
            start: parseInt(element.dataset.videoStart, 10) || DEFAULTS.start,
            end: element.dataset.videoEnd ? parseInt(element.dataset.videoEnd, 10) : DEFAULTS.end,
            captions: element.dataset.videoCaptions || null,
            category: element.dataset.videoCategory || null,
            preload: element.dataset.videoPreload || DEFAULTS.preload
        };
    }

    /**
     * Create the video player structure
     * @param {HTMLElement} container - The container element
     * @param {Object} config - Configuration object
     * @returns {Object} Structure references
     */
    function createStructure(container, config) {
        // Clear existing content
        container.innerHTML = '';

        // Set up container attributes
        container.setAttribute('role', 'application');
        container.setAttribute('aria-label', `Video player: ${config.title}`);
        container.setAttribute('tabindex', '0');
        container.setAttribute('data-state', 'unloaded');

        if (config.aspect) {
            container.setAttribute('data-video-aspect', config.aspect);
        }
        if (config.size) {
            container.setAttribute('data-video-size', config.size);
        }

        // Create aspect ratio wrapper
        const aspectWrapper = document.createElement('div');
        aspectWrapper.className = 'rsl-video-aspect';

        // Create video container
        const videoContainer = document.createElement('div');
        videoContainer.className = 'rsl-video-container';
        videoContainer.setAttribute('aria-hidden', 'true');

        // Create poster overlay
        const poster = document.createElement('div');
        poster.className = 'rsl-video-poster';

        if (config.poster) {
            const posterImg = document.createElement('img');
            posterImg.src = config.poster;
            posterImg.alt = `Video thumbnail: ${config.title}`;
            posterImg.loading = 'lazy';
            poster.appendChild(posterImg);
        }

        // Play overlay button
        const playOverlay = document.createElement('button');
        playOverlay.className = 'rsl-video-play-overlay';
        playOverlay.setAttribute('aria-label', `Play video: ${config.title}`);
        playOverlay.innerHTML = ICONS.play;
        poster.appendChild(playOverlay);

        // Loading spinner
        const loading = document.createElement('div');
        loading.className = 'rsl-video-loading';
        loading.setAttribute('role', 'status');
        loading.setAttribute('aria-label', 'Loading video');
        loading.innerHTML = '<div class="rsl-video-spinner"></div>';

        // Error display
        const error = document.createElement('div');
        error.className = 'rsl-video-error';
        error.setAttribute('role', 'alert');
        error.innerHTML = `
            <div class="rsl-video-error-icon">${ICONS.error}</div>
            <p class="rsl-video-error-message">Unable to load video. Please try again.</p>
            <button class="rsl-video-error-retry" type="button">Retry</button>
        `;

        // Screen reader instructions
        const srInstructions = document.createElement('div');
        srInstructions.className = 'rsl-video-sr-only';
        srInstructions.id = `video-instructions-${Date.now()}`;
        srInstructions.textContent = 'Press Space to play or pause. Use arrow keys to seek. Press M to mute, F for fullscreen, C for captions.';

        // Live region for announcements
        const announcer = document.createElement('div');
        announcer.className = 'rsl-video-sr-only rsl-video-announcer';
        announcer.setAttribute('aria-live', 'polite');
        announcer.setAttribute('aria-atomic', 'true');

        container.setAttribute('aria-describedby', srInstructions.id);

        // Build structure
        aspectWrapper.appendChild(videoContainer);
        aspectWrapper.appendChild(poster);
        aspectWrapper.appendChild(loading);
        aspectWrapper.appendChild(error);
        container.appendChild(aspectWrapper);
        container.appendChild(srInstructions);
        container.appendChild(announcer);

        // Create controls if enabled
        let controls = null;
        if (config.controls) {
            controls = createControls(container, config);
            aspectWrapper.appendChild(controls.element);

            // Title bar
            if (config.title) {
                const titleBar = document.createElement('div');
                titleBar.className = 'rsl-video-title-bar';
                const titleText = document.createElement('h2');
                titleText.className = 'rsl-video-title';
                titleText.textContent = config.title;
                titleBar.appendChild(titleText);
                aspectWrapper.appendChild(titleBar);
            }
        }

        return {
            container,
            aspectWrapper,
            videoContainer,
            poster,
            playOverlay,
            loading,
            error,
            announcer,
            controls,
            video: null
        };
    }

    /**
     * Create custom controls
     * @param {HTMLElement} container - The container element
     * @param {Object} config - Configuration object
     * @returns {Object} Controls structure
     */
    function createControls(container, config) {
        const controlsEl = document.createElement('div');
        controlsEl.className = 'rsl-video-controls';

        // Progress bar
        const progressContainer = document.createElement('div');
        progressContainer.className = 'rsl-video-progress-container';

        const progress = document.createElement('div');
        progress.className = 'rsl-video-progress';
        progress.setAttribute('role', 'slider');
        progress.setAttribute('aria-label', 'Video progress');
        progress.setAttribute('aria-valuemin', '0');
        progress.setAttribute('aria-valuemax', '100');
        progress.setAttribute('aria-valuenow', '0');
        progress.setAttribute('aria-valuetext', '0 seconds of 0 seconds');
        progress.setAttribute('tabindex', '0');

        const progressBuffered = document.createElement('div');
        progressBuffered.className = 'rsl-video-progress-buffered';

        const progressFill = document.createElement('div');
        progressFill.className = 'rsl-video-progress-fill';

        const progressThumb = document.createElement('div');
        progressThumb.className = 'rsl-video-progress-thumb';

        progress.appendChild(progressBuffered);
        progress.appendChild(progressFill);
        progress.appendChild(progressThumb);
        progressContainer.appendChild(progress);

        // Controls row
        const controlsRow = document.createElement('div');
        controlsRow.className = 'rsl-video-controls-row';

        // Left controls
        const controlsLeft = document.createElement('div');
        controlsLeft.className = 'rsl-video-controls-left';

        // Play/Pause button
        const playBtn = document.createElement('button');
        playBtn.className = 'rsl-video-btn rsl-video-btn-play';
        playBtn.setAttribute('aria-label', 'Play');
        playBtn.innerHTML = ICONS.play;

        // Volume controls
        const volumeContainer = document.createElement('div');
        volumeContainer.className = 'rsl-video-volume-container';

        const volumeBtn = document.createElement('button');
        volumeBtn.className = 'rsl-video-btn rsl-video-btn-volume';
        volumeBtn.setAttribute('aria-label', 'Mute');
        volumeBtn.innerHTML = ICONS.volumeHigh;

        const volumeSliderContainer = document.createElement('div');
        volumeSliderContainer.className = 'rsl-video-volume-slider-container';

        const volumeSlider = document.createElement('input');
        volumeSlider.type = 'range';
        volumeSlider.className = 'rsl-video-volume-slider';
        volumeSlider.min = '0';
        volumeSlider.max = '1';
        volumeSlider.step = '0.1';
        volumeSlider.value = '1';
        volumeSlider.setAttribute('aria-label', 'Volume');

        volumeSliderContainer.appendChild(volumeSlider);
        volumeContainer.appendChild(volumeBtn);
        volumeContainer.appendChild(volumeSliderContainer);

        controlsLeft.appendChild(playBtn);
        controlsLeft.appendChild(volumeContainer);

        // Center - Time display
        const controlsCenter = document.createElement('div');
        controlsCenter.className = 'rsl-video-controls-center';

        const time = document.createElement('div');
        time.className = 'rsl-video-time';
        time.innerHTML = `
            <span class="rsl-video-time-current">0:00</span>
            <span class="rsl-video-time-separator">/</span>
            <span class="rsl-video-time-duration">0:00</span>
        `;

        controlsCenter.appendChild(time);

        // Right controls
        const controlsRight = document.createElement('div');
        controlsRight.className = 'rsl-video-controls-right';

        // Captions button (only for self-hosted with captions)
        let captionsBtn = null;
        if (config.captions && config.type === 'self') {
            captionsBtn = document.createElement('button');
            captionsBtn.className = 'rsl-video-btn rsl-video-btn-captions';
            captionsBtn.setAttribute('aria-label', 'Toggle captions');
            captionsBtn.setAttribute('aria-pressed', 'false');
            captionsBtn.innerHTML = ICONS.captions;
            controlsRight.appendChild(captionsBtn);
        }

        // Fullscreen button
        const fullscreenBtn = document.createElement('button');
        fullscreenBtn.className = 'rsl-video-btn rsl-video-btn-fullscreen';
        fullscreenBtn.setAttribute('aria-label', 'Enter fullscreen');
        fullscreenBtn.innerHTML = ICONS.fullscreen;

        controlsRight.appendChild(fullscreenBtn);

        // Assemble controls
        controlsRow.appendChild(controlsLeft);
        controlsRow.appendChild(controlsCenter);
        controlsRow.appendChild(controlsRight);

        controlsEl.appendChild(progressContainer);
        controlsEl.appendChild(controlsRow);

        return {
            element: controlsEl,
            progress,
            progressBuffered,
            progressFill,
            progressThumb,
            playBtn,
            volumeBtn,
            volumeSlider,
            captionsBtn,
            fullscreenBtn,
            timeCurrent: time.querySelector('.rsl-video-time-current'),
            timeDuration: time.querySelector('.rsl-video-time-duration')
        };
    }

    /**
     * Load and create video element
     * @param {Object} structure - Structure references
     * @param {Object} config - Configuration object
     * @param {Object} state - State object
     */
    function loadVideo(structure, config, state) {
        const { container, videoContainer, poster, announcer } = structure;

        container.setAttribute('data-state', 'loading');

        if (config.type === 'youtube') {
            loadYouTubeVideo(structure, config, state);
        } else if (config.type === 'vimeo') {
            loadVimeoVideo(structure, config, state);
        } else {
            loadSelfHostedVideo(structure, config, state);
        }

        // Hide poster
        poster.classList.add('hidden');
        announcer.textContent = 'Loading video';
    }

    /**
     * Load YouTube video via iframe
     */
    function loadYouTubeVideo(structure, config, state) {
        const { videoContainer, container } = structure;

        // Build YouTube embed URL - use standard youtube.com for better compatibility
        let embedUrl = `https://www.youtube.com/embed/${config.videoId}?`;
        const params = new URLSearchParams({
            autoplay: '1',
            rel: '0',
            modestbranding: '1',
            playsinline: '1'
        });

        // Only add origin if we're on a real domain (not file://)
        if (window.location.protocol !== 'file:' && window.location.origin) {
            params.set('enablejsapi', '1');
            params.set('origin', window.location.origin);
        }

        if (config.start) params.set('start', config.start);
        if (config.end) params.set('end', config.end);
        if (config.muted) params.set('mute', '1');
        if (config.loop) {
            params.set('loop', '1');
            params.set('playlist', config.videoId);
        }

        embedUrl += params.toString();

        const iframe = document.createElement('iframe');
        iframe.src = embedUrl;
        iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share';
        iframe.allowFullscreen = true;
        iframe.title = config.title;

        iframe.addEventListener('load', function() {
            container.setAttribute('data-state', 'playing');
            state.isPlaying = true;
            updatePlayButton(structure, state);
            structure.announcer.textContent = 'Video playing';
        });

        videoContainer.appendChild(iframe);
        structure.video = iframe;

        // YouTube iframes have their own controls - hide ours completely
        if (structure.controls && structure.controls.element) {
            structure.controls.element.style.display = 'none';
        }
    }

    /**
     * Load Vimeo video via iframe
     */
    function loadVimeoVideo(structure, config, state) {
        const { videoContainer, container } = structure;

        let embedUrl = `https://player.vimeo.com/video/${config.videoId}?`;
        const params = new URLSearchParams({
            autoplay: '1',
            byline: '0',
            portrait: '0',
            title: '0',
            transparent: '0'
        });

        if (config.muted) params.set('muted', '1');
        if (config.loop) params.set('loop', '1');
        if (config.start) params.set('t', config.start + 's');

        embedUrl += params.toString();

        const iframe = document.createElement('iframe');
        iframe.src = embedUrl;
        iframe.allow = 'autoplay; fullscreen; picture-in-picture';
        iframe.allowFullscreen = true;
        iframe.title = config.title;

        iframe.addEventListener('load', function() {
            container.setAttribute('data-state', 'playing');
            state.isPlaying = true;
            updatePlayButton(structure, state);
            structure.announcer.textContent = 'Video playing';
        });

        videoContainer.appendChild(iframe);
        structure.video = iframe;

        // Vimeo iframes have their own controls - hide ours completely
        if (structure.controls && structure.controls.element) {
            structure.controls.element.style.display = 'none';
        }
    }

    /**
     * Load self-hosted video
     */
    function loadSelfHostedVideo(structure, config, state) {
        const { videoContainer, container, controls, announcer } = structure;

        const video = document.createElement('video');
        video.src = config.src;
        video.preload = config.preload;
        video.playsInline = true;

        if (config.poster) video.poster = config.poster;
        if (config.muted) video.muted = true;
        if (config.loop) video.loop = true;

        // Add caption track if provided
        if (config.captions) {
            const track = document.createElement('track');
            track.kind = 'captions';
            track.src = config.captions;
            track.srclang = 'en';
            track.label = 'English';
            track.default = false;
            video.appendChild(track);
        }

        // Video events
        video.addEventListener('loadedmetadata', function() {
            state.duration = video.duration;
            if (controls) {
                controls.timeDuration.textContent = formatTime(video.duration);
                controls.progress.setAttribute('aria-valuemax', Math.floor(video.duration));
            }

            // Set start time if specified
            if (config.start) {
                video.currentTime = config.start;
            }
        });

        video.addEventListener('canplay', function() {
            container.setAttribute('data-state', 'ready');

            // Auto-play after loading
            video.play().then(function() {
                container.setAttribute('data-state', 'playing');
                state.isPlaying = true;
                updatePlayButton(structure, state);
                announcer.textContent = 'Video playing';
            }).catch(function(err) {
                // Autoplay blocked - that's fine, show as ready
                container.setAttribute('data-state', 'paused');
                state.isPlaying = false;
                updatePlayButton(structure, state);
            });
        });

        video.addEventListener('play', function() {
            container.setAttribute('data-state', 'playing');
            state.isPlaying = true;
            updatePlayButton(structure, state);
            announcer.textContent = 'Video playing';
        });

        video.addEventListener('pause', function() {
            if (!video.ended) {
                container.setAttribute('data-state', 'paused');
                state.isPlaying = false;
                updatePlayButton(structure, state);
                announcer.textContent = 'Video paused';
            }
        });

        video.addEventListener('ended', function() {
            container.setAttribute('data-state', 'ended');
            state.isPlaying = false;
            updatePlayButton(structure, state, true);
            announcer.textContent = 'Video ended';
        });

        video.addEventListener('timeupdate', function() {
            updateProgress(structure, video, state);

            // Check for end time
            if (config.end && video.currentTime >= config.end) {
                video.pause();
                if (config.loop) {
                    video.currentTime = config.start || 0;
                    video.play();
                }
            }
        });

        video.addEventListener('progress', function() {
            updateBuffered(structure, video);
        });

        video.addEventListener('volumechange', function() {
            updateVolumeUI(structure, video);
        });

        video.addEventListener('error', function() {
            container.setAttribute('data-state', 'error');
            announcer.textContent = 'Video failed to load';
        });

        videoContainer.appendChild(video);
        structure.video = video;

        // Start loading
        video.load();
    }

    /**
     * Update play button icon and label
     */
    function updatePlayButton(structure, state, ended = false) {
        if (!structure.controls) return;

        const { playBtn } = structure.controls;

        if (ended) {
            playBtn.innerHTML = ICONS.replay;
            playBtn.setAttribute('aria-label', 'Replay');
        } else if (state.isPlaying) {
            playBtn.innerHTML = ICONS.pause;
            playBtn.setAttribute('aria-label', 'Pause');
        } else {
            playBtn.innerHTML = ICONS.play;
            playBtn.setAttribute('aria-label', 'Play');
        }
    }

    /**
     * Update progress bar
     */
    function updateProgress(structure, video, state) {
        if (!structure.controls || !video.duration) return;

        const { progress, progressFill, progressThumb, timeCurrent } = structure.controls;
        const percent = (video.currentTime / video.duration) * 100;

        progressFill.style.width = `${percent}%`;
        progressThumb.style.left = `${percent}%`;

        timeCurrent.textContent = formatTime(video.currentTime);

        progress.setAttribute('aria-valuenow', Math.floor(video.currentTime));
        progress.setAttribute('aria-valuetext', `${formatTimeForSR(video.currentTime)} of ${formatTimeForSR(video.duration)}`);
    }

    /**
     * Update buffered progress
     */
    function updateBuffered(structure, video) {
        if (!structure.controls || !video.buffered.length) return;

        const { progressBuffered } = structure.controls;
        const bufferedEnd = video.buffered.end(video.buffered.length - 1);
        const percent = (bufferedEnd / video.duration) * 100;

        progressBuffered.style.width = `${percent}%`;
    }

    /**
     * Update volume UI
     */
    function updateVolumeUI(structure, video) {
        if (!structure.controls) return;

        const { volumeBtn, volumeSlider } = structure.controls;

        volumeSlider.value = video.muted ? 0 : video.volume;

        if (video.muted || video.volume === 0) {
            volumeBtn.innerHTML = ICONS.volumeMute;
            volumeBtn.setAttribute('aria-label', 'Unmute');
        } else if (video.volume < 0.5) {
            volumeBtn.innerHTML = ICONS.volumeLow;
            volumeBtn.setAttribute('aria-label', 'Mute');
        } else {
            volumeBtn.innerHTML = ICONS.volumeHigh;
            volumeBtn.setAttribute('aria-label', 'Mute');
        }
    }

    /**
     * Set up event listeners
     */
    function setupEventListeners(structure, config, state) {
        const { container, poster, playOverlay, controls, error } = structure;

        // Play overlay click
        playOverlay.addEventListener('click', function(e) {
            e.preventDefault();
            loadVideo(structure, config, state);
        });

        // Poster click
        poster.addEventListener('click', function(e) {
            if (e.target !== playOverlay && !playOverlay.contains(e.target)) {
                loadVideo(structure, config, state);
            }
        });

        // Error retry
        const retryBtn = error.querySelector('.rsl-video-error-retry');
        retryBtn.addEventListener('click', function() {
            loadVideo(structure, config, state);
        });

        // Control events
        if (controls) {
            setupControlEvents(structure, config, state);
        }

        // Keyboard navigation
        container.addEventListener('keydown', function(e) {
            handleKeyboard(e, structure, config, state);
        });

        // Show/hide controls on interaction
        let controlsTimeout;
        container.addEventListener('mousemove', function() {
            container.setAttribute('data-controls-visible', 'true');
            clearTimeout(controlsTimeout);
            if (state.isPlaying) {
                controlsTimeout = setTimeout(function() {
                    container.removeAttribute('data-controls-visible');
                }, 3000);
            }
        });

        // FilterBus integration
        if (config.category && window.RSL.FilterBus) {
            window.RSL.FilterBus.subscribe(`video-player-${Date.now()}`, function(filterState) {
                const categoryFilter = filterState.category || filterState['video-category'];
                if (categoryFilter) {
                    const matches = categoryFilter === config.category ||
                                   (Array.isArray(categoryFilter) && categoryFilter.includes(config.category));
                    container.style.display = matches ? '' : 'none';
                } else {
                    container.style.display = '';
                }
            });
        }
    }

    /**
     * Set up control button events
     */
    function setupControlEvents(structure, config, state) {
        const { controls, container, announcer } = structure;
        const { playBtn, volumeBtn, volumeSlider, captionsBtn, fullscreenBtn, progress } = controls;

        // Play/Pause
        playBtn.addEventListener('click', function() {
            togglePlay(structure, state);
        });

        // Volume button (toggle mute)
        volumeBtn.addEventListener('click', function() {
            if (structure.video && structure.video.tagName === 'VIDEO') {
                structure.video.muted = !structure.video.muted;
                announcer.textContent = structure.video.muted ? 'Muted' : 'Unmuted';
            }
        });

        // Volume slider
        volumeSlider.addEventListener('input', function() {
            if (structure.video && structure.video.tagName === 'VIDEO') {
                structure.video.volume = parseFloat(volumeSlider.value);
                structure.video.muted = volumeSlider.value === '0';
            }
        });

        // Progress bar click/drag
        let isDragging = false;

        progress.addEventListener('mousedown', function(e) {
            isDragging = true;
            seekToPosition(e, structure);
        });

        document.addEventListener('mousemove', function(e) {
            if (isDragging) {
                seekToPosition(e, structure);
            }
        });

        document.addEventListener('mouseup', function() {
            isDragging = false;
        });

        progress.addEventListener('click', function(e) {
            seekToPosition(e, structure);
        });

        // Captions toggle
        if (captionsBtn) {
            captionsBtn.addEventListener('click', function() {
                if (structure.video && structure.video.tagName === 'VIDEO') {
                    const track = structure.video.textTracks[0];
                    if (track) {
                        const isShowing = track.mode === 'showing';
                        track.mode = isShowing ? 'hidden' : 'showing';
                        captionsBtn.setAttribute('aria-pressed', !isShowing);
                        announcer.textContent = isShowing ? 'Captions off' : 'Captions on';
                    }
                }
            });
        }

        // Fullscreen
        fullscreenBtn.addEventListener('click', function() {
            toggleFullscreen(structure, announcer);
        });

        // Fullscreen change event
        document.addEventListener('fullscreenchange', function() {
            updateFullscreenButton(structure);
        });
    }

    /**
     * Seek to position based on click
     */
    function seekToPosition(e, structure) {
        if (!structure.video || structure.video.tagName !== 'VIDEO') return;

        const { controls } = structure;
        const rect = controls.progress.getBoundingClientRect();
        const percent = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
        const time = percent * structure.video.duration;

        structure.video.currentTime = time;
        structure.announcer.textContent = `Seeking to ${formatTimeForSR(time)}`;
    }

    /**
     * Toggle play/pause
     */
    function togglePlay(structure, state) {
        const { video, container, announcer } = structure;

        if (!video) {
            // Video not loaded yet - this shouldn't happen if poster is shown
            return;
        }

        if (video.tagName === 'VIDEO') {
            if (video.paused || video.ended) {
                if (video.ended) {
                    video.currentTime = 0;
                }
                video.play();
            } else {
                video.pause();
            }
        }
        // For iframes (YouTube/Vimeo), we can't easily control playback
    }

    /**
     * Toggle fullscreen
     */
    function toggleFullscreen(structure, announcer) {
        const { container } = structure;

        if (document.fullscreenElement) {
            document.exitFullscreen();
            announcer.textContent = 'Exited fullscreen';
        } else {
            container.requestFullscreen().catch(function(err) {
                console.warn('Fullscreen not supported:', err);
            });
            announcer.textContent = 'Entered fullscreen';
        }
    }

    /**
     * Update fullscreen button
     */
    function updateFullscreenButton(structure) {
        if (!structure.controls) return;

        const { fullscreenBtn } = structure.controls;
        const isFullscreen = !!document.fullscreenElement;

        fullscreenBtn.innerHTML = isFullscreen ? ICONS.fullscreenExit : ICONS.fullscreen;
        fullscreenBtn.setAttribute('aria-label', isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen');
    }

    /**
     * Handle keyboard navigation
     */
    function handleKeyboard(e, structure, config, state) {
        const { video, announcer } = structure;

        // Only handle for self-hosted videos
        if (!video || video.tagName !== 'VIDEO') {
            // Allow Space/Enter on unloaded state to trigger play
            if ((e.key === ' ' || e.key === 'Enter') && !structure.video) {
                e.preventDefault();
                loadVideo(structure, config, state);
            }
            return;
        }

        let handled = true;

        switch (e.key) {
            case ' ':
            case 'k':
            case 'K':
                togglePlay(structure, state);
                break;

            case 'ArrowLeft':
                video.currentTime = Math.max(0, video.currentTime - 5);
                announcer.textContent = `Seeking back 5 seconds to ${formatTimeForSR(video.currentTime)}`;
                break;

            case 'ArrowRight':
                video.currentTime = Math.min(video.duration, video.currentTime + 5);
                announcer.textContent = `Seeking forward 5 seconds to ${formatTimeForSR(video.currentTime)}`;
                break;

            case 'j':
            case 'J':
                video.currentTime = Math.max(0, video.currentTime - 10);
                announcer.textContent = `Seeking back 10 seconds to ${formatTimeForSR(video.currentTime)}`;
                break;

            case 'l':
            case 'L':
                video.currentTime = Math.min(video.duration, video.currentTime + 10);
                announcer.textContent = `Seeking forward 10 seconds to ${formatTimeForSR(video.currentTime)}`;
                break;

            case 'ArrowUp':
                video.volume = Math.min(1, video.volume + 0.1);
                video.muted = false;
                announcer.textContent = `Volume ${Math.round(video.volume * 100)}%`;
                break;

            case 'ArrowDown':
                video.volume = Math.max(0, video.volume - 0.1);
                announcer.textContent = `Volume ${Math.round(video.volume * 100)}%`;
                break;

            case 'm':
            case 'M':
                video.muted = !video.muted;
                announcer.textContent = video.muted ? 'Muted' : 'Unmuted';
                break;

            case 'f':
            case 'F':
                toggleFullscreen(structure, announcer);
                break;

            case 'c':
            case 'C':
                if (structure.controls && structure.controls.captionsBtn) {
                    structure.controls.captionsBtn.click();
                }
                break;

            case 'Home':
                video.currentTime = 0;
                announcer.textContent = 'Seeking to beginning';
                break;

            case 'End':
                video.currentTime = video.duration;
                announcer.textContent = 'Seeking to end';
                break;

            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                const percent = parseInt(e.key, 10) * 10;
                video.currentTime = (percent / 100) * video.duration;
                announcer.textContent = `Seeking to ${percent}%`;
                break;

            default:
                handled = false;
        }

        if (handled) {
            e.preventDefault();
            e.stopPropagation();
        }
    }

    /**
     * Initialize a single video player
     * @param {HTMLElement} element - The video player element
     * @returns {Object} Player instance
     */
    function initializePlayer(element) {
        if (instances.has(element)) {
            return instances.get(element);
        }

        const config = getConfig(element);
        const state = {
            isPlaying: false,
            duration: 0,
            currentTime: 0,
            volume: 1,
            muted: config.muted
        };

        const structure = createStructure(element, config);
        setupEventListeners(structure, config, state);

        // Check for reduced motion preference
        const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

        // Auto-load if autoplay is enabled (and not reduced motion)
        if (config.autoplay && !config.lazy && !prefersReducedMotion) {
            loadVideo(structure, config, state);
        }

        const instance = {
            element,
            config,
            state,
            structure,
            play: function() {
                if (!structure.video) {
                    loadVideo(structure, config, state);
                } else if (structure.video.tagName === 'VIDEO') {
                    structure.video.play();
                }
            },
            pause: function() {
                if (structure.video && structure.video.tagName === 'VIDEO') {
                    structure.video.pause();
                }
            },
            seek: function(time) {
                if (structure.video && structure.video.tagName === 'VIDEO') {
                    structure.video.currentTime = time;
                }
            },
            setVolume: function(vol) {
                if (structure.video && structure.video.tagName === 'VIDEO') {
                    structure.video.volume = Math.max(0, Math.min(1, vol));
                }
            },
            mute: function() {
                if (structure.video && structure.video.tagName === 'VIDEO') {
                    structure.video.muted = true;
                }
            },
            unmute: function() {
                if (structure.video && structure.video.tagName === 'VIDEO') {
                    structure.video.muted = false;
                }
            },
            getState: function() {
                return { ...state };
            },
            destroy: function() {
                if (structure.video) {
                    if (structure.video.tagName === 'VIDEO') {
                        structure.video.pause();
                        structure.video.src = '';
                    }
                    structure.video.remove();
                }
                instances.delete(element);
            }
        };

        instances.set(element, instance);
        return instance;
    }

    /**
     * Public API
     */
    window.RSL.VideoPlayer = {

        /**
         * Initialize all video players on the page
         */
        init: function() {
            const players = document.querySelectorAll('[data-rsl-video], .rsl-video-player[data-video-src]');
            players.forEach(function(element) {
                if (!instances.has(element)) {
                    initializePlayer(element);
                }
            });
        },

        /**
         * Create a video player for a specific element
         * @param {HTMLElement|string} element - Element or selector
         * @param {Object} options - Configuration options
         * @returns {Object} Player instance
         */
        create: function(element, options) {
            if (typeof element === 'string') {
                element = document.querySelector(element);
            }

            if (!element) {
                console.error('[RSL.VideoPlayer] Element not found');
                return null;
            }

            // Apply options as data attributes
            if (options) {
                if (options.src) element.dataset.videoSrc = options.src;
                if (options.poster) element.dataset.videoPoster = options.poster;
                if (options.title) element.dataset.videoTitle = options.title;
                if (options.type) element.dataset.videoType = options.type;
                if (options.aspect) element.dataset.videoAspect = options.aspect;
                if (options.autoplay) element.dataset.videoAutoplay = 'true';
                if (options.muted) element.dataset.videoMuted = 'true';
                if (options.loop) element.dataset.videoLoop = 'true';
                if (options.captions) element.dataset.videoCaptions = options.captions;
                if (options.category) element.dataset.videoCategory = options.category;
            }

            element.classList.add('rsl-video-player');
            return initializePlayer(element);
        },

        /**
         * Get instance for an element
         * @param {HTMLElement|string} element - Element or selector
         * @returns {Object|null} Player instance
         */
        getInstance: function(element) {
            if (typeof element === 'string') {
                element = document.querySelector(element);
            }
            return instances.get(element) || null;
        },

        /**
         * Destroy a video player
         * @param {HTMLElement|string} element - Element or selector
         */
        destroy: function(element) {
            if (typeof element === 'string') {
                element = document.querySelector(element);
            }
            const instance = instances.get(element);
            if (instance) {
                instance.destroy();
            }
        },

        /**
         * Destroy all video players
         */
        destroyAll: function() {
            instances.forEach(function(instance) {
                instance.destroy();
            });
            instances.clear();
        }
    };

    // Auto-initialize on DOMContentLoaded
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function() {
            window.RSL.VideoPlayer.init();
        });
    } else {
        window.RSL.VideoPlayer.init();
    }

})();
