const video = document.getElementById('js-video-player');

window.hls = null;
let hls = null;

// ===========
// HLS NATIVE
// ===========
function initHLSNative(manifestUrl) {
    if (!manifestUrl) {
        console.error('No HLS manifest URL provided');
        return;
    }

    console.log('Initializing native HLS player with manifest:', manifestUrl);

    if (hls) {
        window.hls = null;
        hls.destroy();
        hls = null;
    }

    if (Hls.isSupported()) {
        hls = new Hls({
            enableWorker: true,
            lowLatencyMode: false,
            maxBufferLength: 30,
            maxMaxBufferLength: 60,
            maxBufferHole: 0.5,
            startLevel: -1,
            // Prevent stalls on quality switch: nudge playback past small gaps
            nudgeMaxRetry: 5,
            // Allow more time for segments coming through our proxy
            fragLoadingTimeOut: 30000,
            fragLoadingMaxRetry: 5,
            fragLoadingRetryDelay: 1000,
            levelLoadingTimeOut: 15000,
            levelLoadingMaxRetry: 4,
            levelLoadingRetryDelay: 1000,
        });

        window.hls = hls;

        hls.loadSource(manifestUrl);
        hls.attachMedia(video);

        hls.on(Hls.Events.MANIFEST_PARSED, function(event, data) {
            console.log('Native manifest parsed');
            console.log('Levels:', data.levels.length);

            const qualitySelect = document.getElementById('quality-select');

            if (qualitySelect && data.levels?.length) {
                qualitySelect.innerHTML = '<option value="-1">Auto</option>';

                const sorted = [...data.levels].sort((a, b) => b.height - a.height);
                const seen = new Set();

                sorted.forEach(level => {
                    if (!seen.has(level.height)) {
                        seen.add(level.height);

                        const i = data.levels.indexOf(level);
                        const opt = document.createElement('option');

                        opt.value = i;
                        opt.textContent = level.height + 'p';

                        qualitySelect.appendChild(opt);
                    }
                });

                // Set initial quality from settings
                if (typeof window.data !== 'undefined' && window.data.settings) {
                    const defaultRes = window.data.settings.default_resolution;
                    if (defaultRes !== 'auto' && defaultRes) {
                        const target = parseInt(defaultRes);
                        let bestLevel = -1;
                        let bestHeight = 0;
                        for (let i = 0; i < hls.levels.length; i++) {
                            const h = hls.levels[i].height;
                            if (h <= target && h > bestHeight) {
                                bestHeight = h;
                                bestLevel = i;
                            }
                        }
                        if (bestLevel !== -1) {
                            hls.currentLevel = bestLevel;
                            qualitySelect.value = bestLevel;
                            console.log('Starting at resolution:', bestHeight + 'p');
                        }
                    }
                }
            }
        });

        hls.on(Hls.Events.ERROR, function(_, data) {
            if (data.fatal) {
                console.error('HLS fatal error:', data.type, data.details);
                switch(data.type) {
                    case Hls.ErrorTypes.NETWORK_ERROR:
                        console.warn('HLS network error, attempting recovery...');
                        hls.startLoad();
                        break;
                    case Hls.ErrorTypes.MEDIA_ERROR:
                        console.warn('HLS media error, attempting recovery...');
                        hls.recoverMediaError();
                        break;
                    default:
                        hls.destroy();
                        break;
                }
            } else {
                // Non-fatal errors can still cause stalls, especially
                // bufferStalledError after a quality switch through our proxy
                console.warn('HLS non-fatal error:', data.type, data.details);
                if (data.details === 'bufferStalledError') {
                    // Buffer ran dry — HLS.js is waiting for data.
                    // Nudge it to retry loading the current fragment.
                    hls.startLoad();
                }
            }
        });

    } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
        video.src = manifestUrl;
    } else {
        console.error('HLS not supported');
    }
}

// ======
// INIT
// ======
function initPlayer() {
    console.log('Init native player');

    if (typeof hls_manifest_url === 'undefined' || !hls_manifest_url) {
        console.error('No manifest URL');
        return;
    }

    initHLSNative(hls_manifest_url);

    const qualitySelect = document.getElementById('quality-select');
    // Set initial Auto option while manifest loads
    if (qualitySelect) {
        qualitySelect.innerHTML = '<option value="-1" selected>Auto</option>';
    }
    if (qualitySelect) {
        qualitySelect.addEventListener('change', function () {
            const level = parseInt(this.value);

            if (hls) {
                const currentTime = video.currentTime;
                const wasPaused = video.paused;

                // Use nextLevel for smoother transition: it waits for the
                // current segment to finish before switching, avoiding an
                // abrupt buffer flush that starves the player.
                if (level === -1) {
                    // Back to auto — re-enable ABR
                    hls.currentLevel = -1;
                    console.log('Quality: Auto (ABR)');
                } else {
                    hls.nextLevel = level;
                    console.log('Quality: switching to',
                                hls.levels[level]?.height + 'p');
                }

                // If the video was already stalled, kick the loader
                // so it starts fetching the new level immediately.
                if (video.readyState < 3) {
                    hls.startLoad(currentTime);
                }
            }
        });
    }
}

// DOM READY
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initPlayer);
} else {
    initPlayer();
}

// =============
// AUDIO TRACKS
// =============
document.addEventListener('DOMContentLoaded', function() {
    const audioTrackSelect = document.getElementById('audio-track-select');

    if (audioTrackSelect) {
        audioTrackSelect.addEventListener('change', function() {
            const trackIdx = parseInt(this.value);

            if (!isNaN(trackIdx) && hls && hls.audioTracks && trackIdx >= 0 && trackIdx < hls.audioTracks.length) {
                hls.audioTrack = trackIdx;
                console.log('Audio track changed to:', hls.audioTracks[trackIdx].name || trackIdx);
            }
        });
    }

    if (hls) {
        hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, (_, data) => {
            console.log('Audio tracks:', data.audioTracks);

            // Populate audio track select if needed
            if (audioTrackSelect && data.audioTracks.length > 0) {
                audioTrackSelect.innerHTML = '<option value="">Select audio track</option>';
                let originalIdx = -1;
                data.audioTracks.forEach((track, idx) => {
                    // Find "original" track
                    if (originalIdx === -1 && (track.name || '').toLowerCase().includes('original')) {
                        originalIdx = idx;
                    }
                    const option = document.createElement('option');
                    option.value = String(idx);
                    option.textContent = track.name || track.lang || `Track ${idx}`;
                    audioTrackSelect.appendChild(option);
                });
                audioTrackSelect.disabled = false;

                // Auto-select "original" audio track
                if (originalIdx !== -1) {
                    hls.audioTrack = originalIdx;
                    audioTrackSelect.value = String(originalIdx);
                    console.log('Auto-selected original audio track:', data.audioTracks[originalIdx].name);
                }
            }
        });
    }
});

// ============
// START TIME
// ============
if (typeof data !== 'undefined' && data.time_start != 0 && video) {
    video.addEventListener('loadedmetadata', function() {
        video.currentTime = data.time_start;
    });
}

// ==============
// SPEED CONTROL
// ==============
let speedInput = document.getElementById('speed-control');

if (speedInput) {
    speedInput.addEventListener('keyup', (event) => {
        if (event.key === 'Enter') {
            let speed = parseFloat(speedInput.value);
            if(!isNaN(speed)){
                video.playbackRate = speed;
            }
        }
    });
}

// =========
// Autoplay
// =========
(function() {
    if (typeof data === 'undefined' || (data.settings.related_videos_mode === 0 && data.playlist === null)) {
        return;
    }

    let playability_error = !!data.playability_error;
    let isPlaylist = false;
    if (data.playlist !== null && data.playlist['current_index'] !== null)
        isPlaylist = true;

    // read cookies on whether to autoplay
    // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie
    let cookieValue;
    let playlist_id;
    if (isPlaylist) {
        // from https://stackoverflow.com/a/6969486
        function escapeRegExp(string) {
            // $& means the whole matched string
            return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        }
        playlist_id = data.playlist['id'];
        playlist_id = escapeRegExp(playlist_id);

        cookieValue = document.cookie.replace(new RegExp(
            '(?:(?:^|.*;\\s*)autoplay_'
            + playlist_id + '\\s*\\=\\s*([^;]*).*$)|^.*$'
        ), '$1');
    } else {
        cookieValue = document.cookie.replace(new RegExp(
            '(?:(?:^|.*;\\s*)autoplay\\s*\\=\\s*([^;]*).*$)|^.*$'
        ),'$1');
    }

    let autoplayEnabled = 0;
    if(cookieValue.length === 0){
        autoplayEnabled = 0;
    } else {
        autoplayEnabled = Number(cookieValue);
    }

    // check the checkbox if autoplay is on
    let checkbox = document.querySelector('.autoplay-toggle');
    if(autoplayEnabled){
        checkbox.checked = true;
    }

    // listen for checkbox to turn autoplay on and off
    let cookie = 'autoplay'
    if (isPlaylist)
        cookie += '_' + playlist_id;

    checkbox.addEventListener( 'change', function() {
        if(this.checked) {
            autoplayEnabled = 1;
            document.cookie = cookie + '=1; SameSite=Strict';
        } else {
            autoplayEnabled = 0;
            document.cookie = cookie + '=0; SameSite=Strict';
        }
    });

    if(!playability_error){
        // play the video if autoplay is on
        if(autoplayEnabled){
            video.play().catch(function(e) {
                // Autoplay blocked by browser - ignore silently
                console.log('Autoplay blocked:', e.message);
            });
        }
    }

    // determine next video url
    let nextVideoUrl;
    if (isPlaylist) {
        let currentIndex = data.playlist['current_index'];
        if (data.playlist['current_index']+1 == data.playlist['items'].length)
            nextVideoUrl = null;
        else
            nextVideoUrl = data.playlist['items'][data.playlist['current_index']+1]['url'];

        // scroll playlist to proper position
        // item height + gap == 100
        let pl = document.querySelector('.playlist-videos');
        pl.scrollTop = 100*currentIndex;
    } else {
        if (data.related.length === 0)
            nextVideoUrl = null;
        else
            nextVideoUrl = data.related[0]['url'];
    }
    let nextVideoDelay = 1000;

    // go to next video when video ends
    // https://stackoverflow.com/a/2880950
    if (nextVideoUrl) {
        if(playability_error){
            videoEnded();
        } else {
            video.addEventListener('ended', videoEnded, false);
        }
        function nextVideo(){
            if(autoplayEnabled){
                window.location.href = nextVideoUrl;
            }
        }
        function videoEnded(e) {
            window.setTimeout(nextVideo, nextVideoDelay);
        }
    }
})();
