// Plyr Player
import Plyr from 'plyr/dist/plyr.polyfilled.min.js';
import 'plyr/dist/plyr.css';

// Vidstack Player
import 'vidstack/player/styles/default/theme.css';
import 'vidstack/player/styles/default/layouts/video.css';
import { VidstackPlayer, VidstackPlayerLayout } from 'vidstack/global/player';

// Dash Support
import dashjs from 'dashjs';

// Subtitle Support
import SubtitlesOctopus from '@jellyfin/libass-wasm';

// Custom JS
import { initMobileWidescreen } from './player-mobile';
import { mobileDoubleClick } from './player-mobile'
import { playNextPlaylistVideo } from './playlist';
import { addVideoTracks } from './player-data';
import { addSubtitleTracks } from './player-data';
import { serverSelectMenuItem, serverSelectSubmenu, serverSelectMenuClickToggle } from './player-server-select';
import { isIOS } from './detect-ios';

// Variables
var player = null;
var av1Supported = (!!document.createElement('video').canPlayType('video/webm; codecs="av01.0.05M.08, opus"'));
var dashSupported = dashjs.supportsMediaSource();
var apiResponse = {};
var volume = 0.5;
var captions = true;
var lastTime = 0.0;
var streamServer = '';
var streamServers = [];
var streamServerIndex = 0;
var streamServerCount = 0;
var ambientMode = true;
var serverFallback = false;
var saveInterval;

var subtitleInstance = null;

var controls = [
    'play-large', // The large play button in the center
    'play', // Play/pause playback
    'progress', // The progress bar and scrubber for playback and buffering
    'current-time', // The current time of playback
    'duration', // The full duration of the media
    'mute', // Toggle mute
    'volume', // Volume control
    'captions', // Toggle captions
    'settings', // Settings menu
    'fullscreen', // Toggle fullscreen
];

// Load Volume from LocalStorage
if (localStorage.hstreamVolume) {
    volume = parseFloat(localStorage.getItem('hstreamVolume')).toFixed(2);
    console.log('Loaded Audio Volume from Local Storage: ' + volume);
}

// Load Captions from LocalStorage
if (localStorage.hstreamCaptions) {
    captions = (localStorage.getItem('hstreamCaptions') == 'true');
    console.log('Loaded Captions Status from Local Storage: ' + captions);
}

// Asia Server Fallback
if (localStorage.hstreamServerFallback) {
    serverFallback = (localStorage.getItem('hstreamServerFallback') == 'true');
    console.log('Loaded Captions Status from Local Storage: ' + captions);
}

// Alert User when AV1 is not supported
if (!av1Supported) {
    document.getElementById("av1-unsupported").classList.remove("hidden");
}

function initDash(data, player) {
    const video = document.querySelector('video');

    data.forEach(function (el) {
        if (el.mode === 'mpd' && el.size === player.config.quality.selected) {
            const dash = dashjs.MediaPlayer().create();
            dash.initialize(video, el.src, true);
            // Expose player and dash so they can be used from the console
            window.player = player;
            window.dash = dash;
        }
    });
}

function setCanvasDimension(canvas, video) {
    canvas.height = video.offsetHeight;
    canvas.width = video.offsetWidth;
}

function paintStaticVideo(ctx, video) {
    if (localStorage.theme == 'light') {
        return;
    }
    if (!ambientMode) {
        return;
    }
    ctx.drawImage(video, 0, 0, video.offsetWidth, video.offsetHeight);
}

function toggleAmbientMode() {
    let canvas = document.getElementById("ambientVideo"), ctx = canvas.getContext("2d"), video = document.getElementsByTagName('video')[0];
    if (ambientMode) {
        ambientMode = false;
        localStorage.ambientMode = 'false';
        setCanvasDimension(canvas, video);
        document.getElementById('ambient-mode-toggle').innerHTML = '<span>Ambient Mode<span class="plyr__menu__value">Off</span></span>';
    } else {
        ambientMode = true;
        localStorage.ambientMode = 'true';
        setCanvasDimension(canvas, video);
        paintStaticVideo(ctx, video);
        document.getElementById('ambient-mode-toggle').innerHTML = '<span>Ambient Mode<span class="plyr__menu__value">On</span></span>';
    }
}

function toggleAsiaServer() {
    if (serverFallback) {
        serverFallback = false;
        localStorage.hstreamServerFallback = 'false';
        document.getElementById('server-fallback-toggle').innerHTML = '<span>Fallback Server<span class="plyr__menu__value">Off</span></span>';
        streamServers = apiResponse.stream_domains;
    } else {
        serverFallback = true;
        localStorage.hstreamServerFallback = 'true';
        document.getElementById('server-fallback-toggle').innerHTML = '<span>Fallback Server<span class="plyr__menu__value">On</span></span>';
        streamServers = apiResponse.asia_stream_domains;
    }

    streamServerCount = streamServers.length;
    streamServerIndex = Math.floor(Math.random() * streamServerCount);
    streamServer = streamServers[streamServerIndex];
    console.log('Selected Server: ' + streamServer);

    if (player) {
        clearInterval(saveInterval);
        player.destroy();
    }
    initPlayer();
}

function initSubtitles(lang) {
    if (isIOS()) {
        return;
    }

    // Dispose old instance
    if (subtitleInstance != null && subtitleInstance instanceof SubtitlesOctopus) {
        subtitleInstance.dispose();
    }

    let newSubUrl = streamServer + '/' + apiResponse.stream_url + '/';

    if (lang != 'en') {
        newSubUrl += 'autotrans/' + lang + '.ass';
    }
    else {
        newSubUrl += 'eng.ass'
    }

    let subFont = '/fonts/Figtree-ExtraBold.woff2';
    // Hindi font
    if (lang == 'hi') {
        subFont = '/fonts/Hind-SemiBold.ttf';
    }

    // Subtitles
    var options = {
        video: document.getElementsByTagName('video')[0], // HTML5 video element
        subUrl: newSubUrl, // Link to subtitles
        workerUrl: '/build/js/subtitles-octopus-worker.js', // Link to WebAssembly-based file "libassjs-worker.js"
        legacyWorkerUrl: '/build/js/subtitles-octopus-worker-legacy.js', // Link to non-WebAssembly worker
        fonts: [subFont],
        renderMode: 'wasm-blend',
    };

    subtitleInstance = new SubtitlesOctopus(options);
}

function initPlayer() {
    player = new Plyr('#player', {
        controls,
        quality: {
            default: 720,
            options: [2161, 2160, 1081, 1080, 720]
        },
        i18n: {
            qualityLabel: {
                2161: "2160p48",
                2160: "2160p",
                1081: "1080p48",
                1080: "1080p",
                720: "720p"
            },
            qualityBadge: {
                2161: "UHD@48",
                1081: "FHD@48",
                1080: "FHD",
            },
        },
        fullscreen: { enabled: true, fallback: true, iosNative: true }
    });

    // Player Track Data
    var data = addVideoTracks(streamServer, apiResponse, av1Supported, dashSupported);

    player.source = {
        type: 'video',
        title: apiResponse.title,
        poster: apiResponse.poster,
        previewThumbnails: {
            enabled: true,
            src: streamServer + '/' + apiResponse.stream_url + '/thumbs.vtt',
        },
        sources: data,
        tracks: addSubtitleTracks(streamServer, apiResponse)
    };

    player.volume = volume;
    //player.captions.languages = ['en'];
    player.captions.language = 'en';
    player.captions.active = captions;

    if (dashSupported && !apiResponse.legacy) {
        player.on('qualitychange', () => {
            initDash(data, player);
        });

        initDash(data, player);
    }

    // Ambient Mode
    let canvas = document.getElementById("ambientVideo"), ctx = canvas.getContext("2d"), video = document.getElementsByTagName('video')[0];
    setCanvasDimension(canvas, video);
    paintStaticVideo(ctx, video);

    var allItems = document.getElementsByClassName('plyr__control--forward');
    var lastItem = allItems[allItems.length - 1];
    lastItem.insertAdjacentHTML('afterend', '<button id="ambient-mode-toggle" type="button" class="plyr__control" role="menuitem" aria-haspopup="true"><span>Ambient Mode<span class="plyr__menu__value">On</span></span></button>');
    document.getElementById('ambient-mode-toggle').addEventListener('click', toggleAmbientMode);

    if (localStorage.ambientMode == 'false') {
        toggleAmbientMode();
    }

    // Server select (Asia)
    lastItem = allItems[allItems.length - 1];
    let value = 'Off';
    if (serverFallback) { value = 'On'; }
    lastItem.insertAdjacentHTML('afterend', '<button id="server-fallback-toggle" type="button" class="plyr__control" role="menuitem" aria-haspopup="true"><span>Fallback Server<span class="plyr__menu__value">' + value + '</span></span></button>');
    document.getElementById('server-fallback-toggle').addEventListener('click', toggleAsiaServer);

    var clickedPlay = false;

    player.on('play', () => {
        if (!clickedPlay) {
            player.stop();
            console.log("Stopped video, because user didn't click play.")
        }

        setCanvasDimension(canvas, video);
        console.log('Play => Function Loop()');
        var $this = video;
        (function loop() {
            if (!player.paused && !player.ended && localStorage.theme == 'dark' && ambientMode) {
                ctx.drawImage($this, 0, 0, $this.offsetWidth, $this.offsetHeight);
                setTimeout(loop, 24000 / 1001); // drawing at 30fps
            }
        })();
    });

    player.on('seeked', () => {
        paintStaticVideo(ctx, video);
        if (player.currentTime > 0) {
            lastTime = player.currentTime;
        }
        console.log('Seeked => paintStaticVideo() at ' + player.currentTime);
    });

    window.addEventListener("resize", () => {
        setCanvasDimension(canvas, video);
        if (player.paused) {
            paintStaticVideo(ctx, video);
        }
    });

    player.on('captionsenabled', () => {
        document.getElementsByClassName('libassjs-canvas-parent')[0].style.visibility = 'visible';
        localStorage.setItem('hstreamCaptions', 'true');
        console.log('Set Captions Status to Local Storage: true');
    });

    player.on('captionsdisabled', () => {
        document.getElementsByClassName('libassjs-canvas-parent')[0].style.visibility = 'hidden';
        localStorage.setItem('hstreamCaptions', 'false');
        console.log('Set Captions Status to Local Storage: false');
    });

    player.on('volumechange', () => {
        console.log('Saving Audio Volume to Local Storage: ' + player.volume);
        localStorage.setItem('hstreamVolume', player.volume.toString())
    });

    player.on('ended', () => {
        playNextPlaylistVideo();
    });

    player.on('languagechange', (event) => {
        let lang = event.detail.plyr.captions.language;

        console.log('Subtitle Event ' + lang);
        initSubtitles(lang);
    });

    function playerPlayTemp() {
        clickedPlay = true;
    }

    document.querySelectorAll('[data-plyr="play"]').forEach(play =>
        play.addEventListener('click', playerPlayTemp)
    );

    document.getElementsByClassName('plyr--video')[0].addEventListener('click', playerPlayTemp);

    initMobileWidescreen();

    // Start time
    setTimeout(function () {
        const params = new URLSearchParams(window.location.search);
        const time = parseInt(params.get("t"));
        if (!isNaN(time)) {
            player.currentTime = time;
            console.log("Skipping to " + time)
        }
        if (lastTime > 0) {
            player.currentTime = lastTime;
            console.log("Skipping to " + lastTime)
        }
    }, 500);

    player.on('ready', () => {
        mobileDoubleClick(player);
    });

    // Server Select 
    // I hate this...
    var settingElements = document.getElementsByClassName('plyr__control--forward');
    if (settingElements.length == 3) {
        settingElements[2].insertAdjacentHTML('afterend', serverSelectMenuItem(streamServerIndex));

        var settingNodes = document.getElementsByClassName('plyr__menu__container')[0].childNodes[0].childNodes;
        if (settingNodes.length == 4) {
            document.getElementsByClassName('plyr__menu__container')[0].childNodes[0].childNodes[3].insertAdjacentHTML('afterend', serverSelectSubmenu(streamServerIndex, streamServerCount));
        }

        // Event Listeners
        document.getElementById('server-select').addEventListener('click', serverSelectMenuClickToggle);
        document.getElementById('server-select-list-back-btn').addEventListener('click', serverSelectMenuClickToggle);
        let serverSelects = document.getElementsByClassName('change_server');
        for (let i = 0; i < serverSelects.length; i++) {
            serverSelects[i].addEventListener('click', function() {
                streamServerIndex = Number(this.value);
                streamServer = streamServers[streamServerIndex];
                console.log('Selected Server: ' + streamServer);

                if (player) {
                    clearInterval(saveInterval);
                    player.destroy();
                }
                initPlayer();
            });
        }
    }

    // Periodically save last timestamp
    saveInterval = setInterval(function () {
        lastTime = player.currentTime;
        console.log("Last Player Position: " + lastTime);
    }, 10000);
}

async function initVidstackPlayer() {
    const videoSource = streamServer + '/' + apiResponse.stream_url + '/x264.720p.mp4';
    const videoThumbs = streamServer + '/' + apiResponse.stream_url + '/thumbs.vtt';
    const videoCaption = streamServer + '/' + apiResponse.stream_url + '/eng.vtt';

    player = await VidstackPlayer.create({
        target: '#player',
        title: apiResponse.title,
        src: videoSource,
        poster: apiResponse.poster,
        layout: new VidstackPlayerLayout({
            thumbnails: videoThumbs,
        }),
        tracks: [
            {
                src: videoCaption,
                label: 'English',
                language: 'en-US',
                kind: 'subtitles',
                type: 'vtt',
                default: true,
            }
        ]
    });

    // Ambient Mode
    let canvas = document.getElementById("ambientVideo"), ctx = canvas.getContext("2d"), video = document.getElementsByTagName('video')[0];
    setCanvasDimension(canvas, video);
    paintStaticVideo(ctx, video);

    player.addEventListener('play', () => {
        setCanvasDimension(canvas, video);
        console.log('Play => Function Loop()');
        var $this = video;
        (function loop() {
            if (!player.paused && !player.ended && localStorage.theme == 'dark' && ambientMode) {
                ctx.drawImage($this, 0, 0, $this.offsetWidth, $this.offsetHeight);
                setTimeout(loop, 24000 / 1001); // drawing at 30fps
            }
        })();
    });
}

// Get Data from API
window.axios.post('/player/api', {
    episode_id: document.getElementById('e_id').value
}).then(function (response) {
    if (response.status == 200) {
        apiResponse = response.data;
        streamServers = apiResponse.stream_domains;

        if (serverFallback) {
            streamServers = apiResponse.asia_stream_domains;
        }

        streamServerCount = streamServers.length;
        streamServerIndex = Math.floor(Math.random() * streamServerCount);
        streamServer = streamServers[streamServerIndex];
        console.log('Selected Server: ' + streamServer + ' with Index: ' + streamServerIndex);

        if (!isIOS()) {
            initPlayer();
        }
        else {
            console.log("Detected Apple Shit. Using different player.")
            initVidstackPlayer();
        }

    }
}).catch(function (error) {
    var alert = document.getElementById("player-alert");
    alert.innerText = 'The player encountered a problem: ' + error;
    alert.classList.remove("hidden");
});
