const AnimePlayer = (function() {

    let _animeId = null;
    let _currentEpisode = 0;
    let _entrySource = 'anilist';
    let _audioMode = 'sub';
    let _isLocal = false;
    let _malId = null;
    let _skipBtn = null;
    let _skipIntervals = [];
    let _progressUpdated = false;

    let _animeTitle = "Anime";
    let _rpcActive = false;

    let _rawVideoData = null;
    let _currentSubtitles = [];

    let _localEntryId = null;
    let _totalEpisodes = 0;

    let plyrInstance = null;
    let hlsInstance = null;

    const els = {
        wrapper: null,
        playerWrapper: null,
        video: null,
        loader: null,
        loaderText: null,
        serverSelect: null,
        extSelect: null,
        subDubToggle: null,
        epTitle: null,
        prevBtn: null,
        nextBtn: null,
        mpvBtn: null
    };

    function init(animeId, initialSource, isLocal, animeData) {
        _animeId = animeId;
        _entrySource = initialSource || 'anilist';
        _isLocal = isLocal;
        _malId = animeData.idMal || null;

        _totalEpisodes = animeData.episodes || 1000;

        if (animeData.title) {
            _animeTitle = animeData.title.romaji || animeData.title.english || animeData.title.native || animeData.title || "Anime";
        }

        _skipIntervals = [];
        _localEntryId = null;

        els.wrapper = document.getElementById('hero-wrapper');
        els.playerWrapper = document.getElementById('player-wrapper');
        els.video = document.getElementById('player');
        els.loader = document.getElementById('player-loading');
        els.loaderText = document.getElementById('player-loading-text');

        els.mpvBtn = document.getElementById('mpv-btn');
        if (els.mpvBtn) els.mpvBtn.addEventListener('click', openInMPV);

        els.serverSelect = document.getElementById('server-select');
        els.extSelect = document.getElementById('extension-select');
        els.subDubToggle = document.getElementById('sd-toggle');
        els.epTitle = document.getElementById('player-episode-title');

        els.prevBtn = document.getElementById('prev-ep-btn');
        els.nextBtn = document.getElementById('next-ep-btn');

        const closeBtn = document.getElementById('close-player-btn');
        if(closeBtn) closeBtn.addEventListener('click', closePlayer);

        if(els.prevBtn) els.prevBtn.addEventListener('click', () => playEpisode(_currentEpisode - 1));
        if(els.nextBtn) els.nextBtn.addEventListener('click', () => playEpisode(_currentEpisode + 1));

        if (!document.getElementById('skip-overlay-btn')) {
            const btn = document.createElement('button');
            btn.id = 'skip-overlay-btn';
            const container = document.querySelector('.player-container');
            if(container) container.appendChild(btn);
            _skipBtn = btn;
        } else {
            _skipBtn = document.getElementById('skip-overlay-btn');
        }
        if(_skipBtn) _skipBtn.onclick = () => handleOverlayClick();

        if(els.subDubToggle) els.subDubToggle.addEventListener('click', toggleAudioMode);
        if(els.serverSelect) els.serverSelect.addEventListener('change', () => loadStream());
        if(els.extSelect) els.extSelect.addEventListener('change', () => handleExtensionChange(true));

        loadExtensionsList();
    }

    async function openInMPV() {
        if (!_rawVideoData) {
            alert("No video loaded yet.");
            return;
        }

        const token = localStorage.getItem('token');
        if (!token) {
            alert("You need to be logged in.");
            return;
        }
        const body = {
            title: `${_animeTitle} - Episode ${_currentEpisode}`,
            video: _rawVideoData,
            subtitles: _currentSubtitles,
            chapters: _skipIntervals,
            animeId: _animeId,
            episode: _currentEpisode,
            entrySource: _entrySource,
            token: localStorage.getItem('token')
        };

        try {
            const res = await fetch('/api/watch/mpv', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(body)
            });

            if (res.ok) {
                console.log("MPV Request Sent");
                closePlayer();
            } else {
                console.error("MPV Request Failed");
            }
        } catch (e) {
            console.error("MPV Error:", e);
        } finally {
            if(els.mpvBtn) {
                els.mpvBtn.innerHTML = originalContent;
                els.mpvBtn.disabled = false;
            }
        }
    }

    function sendRPC({ startTimestamp, endTimestamp, paused = false } = {}) {
        fetch("/api/rpc", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
                details: _animeTitle,
                state: `Episode ${_currentEpisode}`,
                mode: "watching",
                startTimestamp,
                endTimestamp,
                paused
            })
        }).catch(e => console.warn("RPC Error:", e));
    }

    function handleOverlayClick() {
        if (!_skipBtn) return;
        if (_skipBtn.classList.contains('is-next')) {
            playEpisode(_currentEpisode + 1);
        } else if (_skipBtn.dataset.seekTo) {
            els.video.currentTime = parseFloat(_skipBtn.dataset.seekTo);
        }
        _skipBtn.classList.remove('visible');
    }

    async function getLocalEntryId() {
        if (_localEntryId) return _localEntryId;
        try {
            const res = await fetch(`/api/library/anime/${_animeId}`);
            if (!res.ok) return null;
            const data = await res.json();
            _localEntryId = data.id;
            return _localEntryId;
        } catch (e) {
            console.error("Error fetching local ID:", e);
            return null;
        }
    }

    function playEpisode(episodeNumber) {
        const targetEp = parseInt(episodeNumber);
        if (targetEp < 1 || targetEp > _totalEpisodes) return;

        _currentEpisode = targetEp;

        if(els.epTitle) els.epTitle.innerText = `Episode ${targetEp}`;
        if(els.prevBtn) els.prevBtn.disabled = (_currentEpisode <= 1);
        if(els.nextBtn) els.nextBtn.disabled = (_currentEpisode >= _totalEpisodes);

        if(_skipBtn) {
            _skipBtn.classList.remove('visible');
            _skipBtn.classList.remove('is-next');
        }

        const newUrl = new URL(window.location);
        newUrl.searchParams.set('episode', targetEp);
        window.history.pushState({}, '', newUrl);

        if(els.playerWrapper) els.playerWrapper.style.display = 'block';
        document.body.classList.add('stop-scrolling');

        const trailer = document.querySelector('#trailer-player iframe');
        if(trailer) trailer.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');

        _rpcActive = false;

        if (els.extSelect.value === 'local') {
            loadStream();
            return;
        }
        if (els.serverSelect.options.length === 0) {
            handleExtensionChange(true);
        } else {
            loadStream();
        }
    }

    function closePlayer() {
        if (plyrInstance) plyrInstance.destroy();
        if (hlsInstance) hlsInstance.destroy();
        plyrInstance = null;
        hlsInstance = null;

        if(els.playerWrapper) els.playerWrapper.style.display = 'none';

        document.body.classList.remove('stop-scrolling');
        document.body.classList.remove('watch-mode');
        _skipIntervals = [];
        _rpcActive = false;

        sendRPC({ paused: true });

        const newUrl = new URL(window.location);
        newUrl.searchParams.delete('episode');
        window.history.pushState({}, '', newUrl);

        const trailer = document.querySelector('#trailer-player iframe');
        if(trailer) {
            trailer.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
        }
    }

    async function loadExtensionsList() {
        try {
            const res = await fetch('/api/extensions/anime');
            const data = await res.json();
            const extensions = data.extensions || [];

            if (_isLocal && !extensions.includes('local')) extensions.push('local');

            els.extSelect.innerHTML = '';
            extensions.forEach(ext => {
                const opt = document.createElement('option');
                opt.value = ext;
                opt.innerText = ext.charAt(0).toUpperCase() + ext.slice(1);
                els.extSelect.appendChild(opt);
            });

            if (extensions.includes(_entrySource)) {
                els.extSelect.value = _entrySource;
            } else if (extensions.length > 0) {
                els.extSelect.value = extensions[0];
            }

            if (els.extSelect.value === 'local') {
                els.subDubToggle.style.display = 'none';
                els.serverSelect.style.display = 'none';
            } else if (els.extSelect.value) {
                handleExtensionChange(false);
            }
        } catch (e) { console.error("Error loading extensions:", e); }
    }

    async function handleExtensionChange(shouldPlay = true) {
        const selectedExt = els.extSelect.value;
        if (selectedExt === 'local') {
            els.subDubToggle.style.display = 'none';
            els.serverSelect.style.display = 'none';
            if (shouldPlay && _currentEpisode > 0) loadStream();
            return;
        }

        setLoading("Loading Extension Settings...");
        try {
            const res = await fetch(`/api/extensions/${selectedExt}/settings`);
            const settings = await res.json();

            els.subDubToggle.style.display = settings.supportsDub ? 'flex' : 'none';
            setAudioMode('sub');

            els.serverSelect.innerHTML = '';
            if (settings.episodeServers && settings.episodeServers.length > 0) {
                settings.episodeServers.forEach(srv => {
                    const opt = document.createElement('option');
                    opt.value = srv;
                    opt.innerText = srv;
                    els.serverSelect.appendChild(opt);
                });
                els.serverSelect.value = settings.episodeServers[0];
                els.serverSelect.style.display = 'block';
            } else {
                els.serverSelect.style.display = 'none';
            }

            if (shouldPlay && _currentEpisode > 0) {
                loadStream();
            } else {
                if(els.loader) els.loader.style.display = 'none';
            }
        } catch (error) {
            console.error("Failed to load settings:", error);
            setLoading("Failed to load extension settings.");
        }
    }

    function toggleAudioMode() {
        _audioMode = _audioMode === 'sub' ? 'dub' : 'sub';
        setAudioMode(_audioMode);
        loadStream();
    }

    function setAudioMode(mode) {
        _audioMode = mode;
        els.subDubToggle.setAttribute('data-state', mode);
        document.getElementById('opt-sub').classList.toggle('active', mode === 'sub');
        document.getElementById('opt-dub').classList.toggle('active', mode === 'dub');
    }

    function setLoading(msg) {
        if(els.loaderText) els.loaderText.innerText = msg;
        if(els.loader) els.loader.style.display = 'flex';
    }

    async function loadStream() {
        if (!_currentEpisode) return;
        _progressUpdated = false;
        setLoading("Fetching Stream...");

        _rawVideoData = null;
        _currentSubtitles = [];

        if (hlsInstance) { hlsInstance.destroy(); hlsInstance = null; }

        const currentExt = els.extSelect.value;

        if (currentExt === 'local') {
            try {
                const localId = await getLocalEntryId();
                if (!localId) {
                    setLoading("Local entry not found in library.");
                    return;
                }
                const localUrl = `/api/library/stream/anime/${localId}/${_currentEpisode}`;

                _rawVideoData = {
                    url: window.location.origin + localUrl,
                    headers: {}
                };
                _currentSubtitles = [];

                initVideoPlayer(localUrl, 'mp4');
            } catch(e) {
                setLoading("Local Error: " + e.message);
            }
            return;
        }

        const server = els.serverSelect.value || "";
        const sourceParam = `&source=${_entrySource}`;
        const extParam = `&ext=${currentExt}`;
        const url = `/api/watch/stream?animeId=${_animeId}&episode=${_currentEpisode}&server=${encodeURIComponent(server)}&category=${_audioMode}${extParam}${sourceParam}`;

        try {
            const res = await fetch(url);
            const data = await res.json();

            if (data.error || !data.videoSources?.length) {
                setLoading(data.error || "No sources found.");
                return;
            }

            const source = data.videoSources.find(s => s.type === 'm3u8') || data.videoSources[0];
            const headers = data.headers || {};

            _rawVideoData = {
                url: source.url,
                headers: headers
            };

            let proxyUrl = `/api/proxy?url=${encodeURIComponent(source.url)}`;
            if (headers['Referer'] && headers['Referer'] !== "null") proxyUrl += `&referer=${encodeURIComponent(headers['Referer'])}`;
            if (headers['User-Agent']) proxyUrl += `&userAgent=${encodeURIComponent(headers['User-Agent'])}`;

            const subtitles = (source.subtitles || []).map(sub => ({
                label: sub.language,
                srclang: sub.id,
                src: `/api/proxy?url=${encodeURIComponent(sub.url)}`
            }));

            _currentSubtitles = (source.subtitles || []).map(sub => ({
                label: sub.language,
                srclang: sub.id,
                src: sub.url
            }));

            initVideoPlayer(proxyUrl, source.type, subtitles);
        } catch (err) {
            setLoading("Stream Error: " + err.message);
        }
    }

    function initVideoPlayer(url, type, subtitles = []) {
        if (plyrInstance) {
            plyrInstance.destroy();
            plyrInstance = null;
        }
        if (hlsInstance) {
            hlsInstance.destroy();
            hlsInstance = null;
        }

        const container = document.querySelector('.video-frame');

        container.innerHTML = '';

        const newVideo = document.createElement('video');
        newVideo.id = 'player';
        newVideo.controls = true;
        newVideo.crossOrigin = 'anonymous';
        newVideo.playsInline = true;

        container.appendChild(newVideo);
        els.video = newVideo;

        els.video.addEventListener("play", () => {
            if (!els.video.duration) return;
            const elapsed = Math.floor(els.video.currentTime);
            const start = Math.floor(Date.now() / 1000) - elapsed;
            const end = start + Math.floor(els.video.duration);
            sendRPC({ startTimestamp: start, endTimestamp: end });
            _rpcActive = true;
        });

        els.video.addEventListener("pause", () => {
            if (_rpcActive) sendRPC({ paused: true });
        });

        els.video.addEventListener("seeked", () => {
            if (els.video.paused || !_rpcActive) return;
            const elapsed = Math.floor(els.video.currentTime);
            const start = Math.floor(Date.now() / 1000) - elapsed;
            const end = start + Math.floor(els.video.duration);
            sendRPC({ startTimestamp: start, endTimestamp: end });
        });

        if (Hls.isSupported() && (type === 'm3u8' || url.includes('.m3u8'))) {
            hlsInstance = new Hls();
            hlsInstance.attachMedia(els.video);

            hlsInstance.on(Hls.Events.MEDIA_ATTACHED, () => {
                hlsInstance.loadSource(url);
            });

            hlsInstance.on(Hls.Events.MANIFEST_PARSED, () => {
                initPlyr();

                plyrInstance.on('ready', () => {
                    createAudioSelector(hlsInstance);
                    createQualitySelector(hlsInstance);
                });

                els.video.play().catch(() => {});
            });

        } else {
            els.video.src = url;
            attachSubtitles(subtitles);
            initPlyr();
            els.video.play().catch(e => console.log("Autoplay blocked", e));
            els.video.addEventListener('loadedmetadata', () => {
                applyAniSkip(_malId, _currentEpisode);
            }, { once: true });
            if(els.loader) els.loader.style.display = 'none';
        }
    }

    function attachSubtitles(subtitles) {
        subtitles.forEach((sub, i) => {
            const track = document.createElement('track');
            track.kind = 'subtitles';
            track.label = sub.label;
            track.srclang = sub.srclang;
            track.src = sub.src;
            track.default = i === 0;
            els.video.appendChild(track);
        });
    }
    const ICONS = {
        settings: `<svg viewBox="0 0 24 24"><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></svg>`,
        audio: `<svg viewBox="0 0 24 24"><path d="M12,2C6.48,2,2,6.48,2,12v6c0,2.21,1.79,4,4,4h1c1.1,0,2-0.9,2-2v-5c0-1.1-0.9-2-2-2H3v-1c0-4.97,4.03-9,9-9s9,4.03,9,9v1 h-4c-1.1,0-2,0.9-2,2v5c0,1.1,0.9,2,2,2h1c2.21,0,4-1.79,4-4v-6C22,6.48,17.52,2,12,2z"/></svg>`
    };

    function createQualitySelector(hls) {
        const levels = hls.levels;
        if (!levels || !levels.length) return;

        const plyrEl = els.video.closest('.plyr');
        const controls = plyrEl.querySelector('.plyr__controls');
        if (!controls || controls.querySelector('#quality-control-wrapper')) return;

        // 1. Crear el Wrapper
        const wrapper = document.createElement('div');
        wrapper.className = 'plyr__controls__item plyr__custom-select-wrapper';
        wrapper.id = 'quality-control-wrapper';

        // 2. Crear el Botón Visual (Fake)
        const btn = document.createElement('div');
        btn.className = 'plyr__custom-control-btn';
        // Icono + Texto Inicial
        btn.innerHTML = `${ICONS.settings} <span class="label-text">Auto</span>`;

        // 3. Crear el Select Real (Invisible)
        const select = document.createElement('select');
        select.className = 'plyr__sr-only-select'; // Clase auxiliar si quieres depurar, sino usa el CSS wrapper

        // Opción AUTO
        const autoOpt = document.createElement('option');
        autoOpt.value = -1;
        autoOpt.textContent = 'Auto';
        select.appendChild(autoOpt);

        // Opciones de Niveles
        levels.forEach((l, i) => {
            const opt = document.createElement('option');
            opt.value = i;
            opt.textContent = `${l.height}p`; // Texto que sale en el dropdown nativo
            select.appendChild(opt);
        });

        // Sincronizar estado inicial
        select.value = hls.currentLevel;
        updateLabel(select.value);

        // Evento Change
        select.onchange = () => {
            hls.currentLevel = Number(select.value);
            updateLabel(select.value);
        };

        function updateLabel(val) {
            const index = Number(val);
            let text = 'Auto';
            if (index !== -1 && levels[index]) {
                // Solo el número + p (ej: 720p)
                text = `${levels[index].height}p`;
            }
            btn.innerHTML = `<span class="label-text">${text}</span>`;
        }

        wrapper.appendChild(select);
        wrapper.appendChild(btn);

        // Insertar en controles Plyr (antes del botón de pantalla completa o ajustes)
        // Insertamos antes del 5º elemento (usualmente settings o fullscreen)
        const insertIndex = controls.children.length > 4 ? 4 : controls.children.length - 1;
        controls.insertBefore(wrapper, controls.children[insertIndex]);
    }

    function createAudioSelector(hls) {
        if (!hls.audioTracks || hls.audioTracks.length < 2) return;

        const plyrEl = els.video.closest('.plyr');
        const controls = plyrEl.querySelector('.plyr__controls');
        if (!controls || controls.querySelector('#audio-control-wrapper')) return;

        // 1. Wrapper
        const wrapper = document.createElement('div');
        wrapper.className = 'plyr__controls__item plyr__custom-select-wrapper';
        wrapper.id = 'audio-control-wrapper';

        // 2. Botón Visual
        const btn = document.createElement('div');
        btn.className = 'plyr__custom-control-btn';
        btn.innerHTML = `<span class="label-text">Audio 1</span>`;

        // 3. Select Invisible
        const select = document.createElement('select');

        hls.audioTracks.forEach((t, i) => {
            const opt = document.createElement('option');
            opt.value = i;
            opt.textContent = t.name || t.lang || `Audio ${i + 1}`;
            select.appendChild(opt);
        });

        select.value = hls.audioTrack;
        updateLabel(select.value);

        select.onchange = () => {
            hls.audioTrack = Number(select.value);
            updateLabel(select.value);
        };

        function updateLabel(val) {
            const index = Number(val);
            const track = hls.audioTracks[index];

            // Priorizamos el idioma (lang), luego el nombre
            let rawText = track.lang || track.name || `A${index + 1}`;

            // Tomamos solo las 2 primeras letras y las pasamos a Mayúsculas
            let shortText = rawText.substring(0, 2).toUpperCase();

            btn.querySelector('.label-text').innerText = shortText;
        }

        wrapper.appendChild(select);
        wrapper.appendChild(btn);

        // Insertar antes del selector de calidad si existe, o en la posición 4
        const qualityWrapper = controls.querySelector('#quality-control-wrapper');
        if(qualityWrapper) {
            controls.insertBefore(wrapper, qualityWrapper);
        } else {
            const insertIndex = controls.children.length > 4 ? 4 : controls.children.length - 1;
            controls.insertBefore(wrapper, controls.children[insertIndex]);
        }
    }

    function initPlyr(enableAudio = false) {
        if (plyrInstance) return;

        const settings = ['captions', 'quality', 'speed'];
        if (enableAudio) settings.unshift('audio');

        plyrInstance = new Plyr(els.video, {
            captions: {
                active: true,
                update: true,
                language: els.video.querySelector('track')?.srclang || 'en'
            },
            fullscreen: {
                enabled: true,
                fallback: true,
                iosNative: true,
                container: '.player-container'
            },
            controls: [
                'play-large', 'play', 'progress', 'current-time',
                'mute', 'volume', 'captions', 'settings',
                'fullscreen', 'airplay'
            ],
            settings
        });

        const container = document.querySelector('.player-container');
        plyrInstance.on('controlshidden', () => container.classList.add('ui-hidden'));
        plyrInstance.on('controlsshown', () => container.classList.remove('ui-hidden'));

        const tracks = els.video.textTracks;
        if (tracks && tracks.length) tracks[0].mode = 'showing';

        plyrInstance.on('ready', () => {
            if (hlsInstance) createAudioSelector(hlsInstance);
        });

        plyrInstance.on('timeupdate', (event) => {
            const instance = event.detail.plyr;
            if (!instance.duration || _progressUpdated) return;
            const percentage = instance.currentTime / instance.duration;
            if (percentage >= 0.8) {
                updateProgress();
                _progressUpdated = true;
            }
        });
    }

    function toVtt(sec) {
        const h = String(Math.floor(sec / 3600)).padStart(2, '0');
        const m = String(Math.floor(sec % 3600 / 60)).padStart(2, '0');
        const s = (sec % 60).toFixed(3).padStart(6, '0');
        return `${h}:${m}:${s}`;
    }

    function injectAniSkipChapters(intervals) {
        const vtt = ['WEBVTT', ''];
        intervals.forEach(skip => {
            const label = skip.type === 'op' ? 'Opening' : 'Ending';
            vtt.push(`${toVtt(skip.startTime)} --> ${toVtt(skip.endTime)}`, label, '');
        });
        const blob = new Blob([vtt.join('\n')], { type: 'text/vtt' });
        const url = URL.createObjectURL(blob);
        const track = document.createElement('track');
        track.kind = 'chapters';
        track.label = 'Chapters';
        track.srclang = 'en';
        track.src = url;
        els.video.appendChild(track);
    }

    function waitForDuration(video) {
        return new Promise(resolve => {
            if (video.duration && video.duration > 0) return resolve(video.duration);
            const check = () => {
                if (video.duration && video.duration > 0) {
                    video.removeEventListener('timeupdate', check);
                    resolve(video.duration);
                }
            };
            video.addEventListener('timeupdate', check);
        });
    }

    async function applyAniSkip(malId, episodeNumber) {
        if (!malId) return;
        const duration = await waitForDuration(els.video);
        try {
            const url = `https://api.aniskip.com/v2/skip-times/${malId}/${episodeNumber}` +
                `?types[]=op&types[]=ed&episodeLength=${Math.floor(duration)}`;
            const res = await fetch(url);
            if (!res.ok) return;
            const data = await res.json();
            if (!data.found) return;

            _skipIntervals = data.results.map(item => ({
                startTime: item.interval.startTime,
                endTime: item.interval.endTime,
                type: item.skipType
            }));
            injectAniSkipChapters(_skipIntervals);
            requestAnimationFrame(() => renderSkipMarkers(_skipIntervals));
        } catch (e) { console.error('AniSkip Error:', e); }
    }

    function renderSkipMarkers(intervals) {
        const progressContainer = els.video.closest('.plyr')?.querySelector('.plyr__progress');
        if (!progressContainer || !els.video.duration) return;

        progressContainer.querySelectorAll('.skip-marker').forEach(e => e.remove());

        intervals.forEach(skip => {
            const el = document.createElement('div');
            el.className = `skip-marker ${skip.type}`;
            const startPct = (skip.startTime / els.video.duration) * 100;
            const endPct = (skip.endTime / els.video.duration) * 100;
            el.style.left = `${startPct}%`;
            el.style.width = `${endPct - startPct}%`;
            progressContainer.appendChild(el);
        });
        monitorSkipButton(intervals);
    }

    function monitorSkipButton(intervals) {
        if (!_skipBtn) return;
        els.video.removeEventListener('timeupdate', checkTime);
        els.video.addEventListener('timeupdate', checkTime);

        els.video.addEventListener('ended', () => {
            if (_currentEpisode < _totalEpisodes) playEpisode(_currentEpisode + 1);
        }, { once: true });

        function checkTime() {
            const ct = els.video.currentTime;
            const duration = els.video.duration;
            const activeInterval = intervals.find(i => ct >= i.startTime && ct <= i.endTime);

            if (activeInterval) {
                if (activeInterval.type === 'op') {
                    showSkipButton('Skip Intro', activeInterval.endTime, false);
                    return;
                } else if (activeInterval.type === 'ed') {
                    if (_currentEpisode < _totalEpisodes) {
                        showSkipButton('Next Episode', null, true);
                    } else {
                        showSkipButton('Skip Ending', activeInterval.endTime, false);
                    }
                    return;
                }
            }

            if (_currentEpisode < _totalEpisodes && (duration - ct) < 90 && (duration - ct) > 0) {
                if (!activeInterval) {
                    showSkipButton('Next Episode', null, true);
                    return;
                }
            }
            _skipBtn.classList.remove('visible');
        }
    }

    function showSkipButton(text, seekTime, isNextAction) {
        if (!_skipBtn) return;
        _skipBtn.innerHTML = `${text} <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M13 17l5-5-5-5M6 17l5-5-5-5"/></svg>`;
        if (isNextAction) {
            _skipBtn.classList.add('is-next');
            _skipBtn.dataset.seekTo = '';
        } else {
            _skipBtn.classList.remove('is-next');
            _skipBtn.dataset.seekTo = seekTime;
        }
        _skipBtn.classList.add('visible');
    }

    async function updateProgress() {
        const token = localStorage.getItem('token');
        if (!token) return;
        try {
            await fetch('/api/list/entry', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
                body: JSON.stringify({
                    entry_id: _animeId,
                    source: _entrySource,
                    entry_type: "ANIME",
                    status: 'CURRENT',
                    progress: _currentEpisode
                })
            });
        } catch (e) { console.error("Progress update failed", e); }
    }

    return {
        init,
        playEpisode,
        getCurrentEpisode: () => _currentEpisode
    };
})();