(function() {
    const menuTemplate = `
    <div class="ytMenuStyle" id="enhancerMenuID" style="display: block;">
        <div id="ytThumbnailBttn" class="imageStyle" title="Video Thumbnails..."></div>
        <div id="ytLoopBttn" class="imageStyle" title="Start Loop..."/></div>
        <div id="ytFloatBttn" class="imageStyle" title="Float Video Container"/></div>
        <div id="ytDownloadBttn" class="imageStyle" title="Download Video..."/></div>
    </div>
    `
    const slugTemplate = `
    <div id="enhancerMenuID2">
        <div id="volumeContainerID" style="">
            Volume <label id="volumeValueLbl"></label>
        </div>
        <input id="slugCopyZone" type="text">
        <label>Loop Range Start:&nbsp;&nbsp;</label>
        <input type="text" id="rangeStartID"/>
        <label>Loop Range End:&nbsp;&nbsp;</label>
        <input id="rangeEndID" type="text"/>
        <label for="endlessPlayID">Endless Play</label>
        <input type="checkbox" checked id="endlessPlayID" name="endlessPlayID"/>
    </div>
    `
    const thumbnailTemplate = `
    <div id="ytThumbMenuID" class="ytThumbMenuStyle" style="display: none;">
    <a id="ytAMaxDefaultImgID" target="_blank" href=""><img id="ytMaxDefaultImgID" class="thumbImageStyle" src="" title="Max Resolution Default"/></a>
    <a id="ytAHqDefaultImgID"  target="_blank" href=""><img id="ytHqDefaultImgID" class="thumbImageStyle" src="" title="High Quality Default"/></a>
    <a id="ytAMedDefaultImgID" target="_blank" href=""><img id="ytMqDefaultImgID" class="thumbImageStyle" src="" title="Medium Quality Default"></a>
    <a id="ytASdDefaultImgID"  target="_blank" href=""><img id="ytSdDefaultImgID" class="thumbImageStyle" src="" title="Standard Quality Default"/></a>
    </div>
    `
    const popedContainerTemplate = `
    <div id="draggable" style="display:none; block; top: 114px; left: 408px;">
        <iframe id="popIframe" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
        autoplay="" allowfullscreen="true" width="650px" height="400px" frameborder="0" src="" />
        </iframe>
    </div>
    `

    // Declare other variables
    let ytThumbImgMenu, ytEnhancerMenu, ytEnhancerMenu2;                    // Menu systems
    let ytThumbnailBttn, ytLoopBttn, ytFloatBttn, ytDownloadBttn;           // Menu Buttons
    let ytMaxDefaultImg, ytHqDefaultImg, ytAMaxDefaultImg, ytAHqDefaultImg; // Thumbnail images
    let mainContentArea, playerWindow, containerOfPlyrWndow, video;         // Youtube Player container
    let videoTimeLength, videoTimeCurent, ytRangeStart, ytRangeEnd,
        slugInputTag, endlessPlayTag, ytVideoIntervalLoop, loopingInterval;

    let	poppedContainer, videoSlug, volumeLbl, part;
    let modalHasBeenClosed = false;
    // Default to false b/c if tag checked it sets this in setupProcess and elsewhere.
    let isEndlessWatch     = false;
    let shouldHideVol      = true;
    let OSName             = "";
    let count              = 0;

    // confirm dialog elm
    const isYoutubeMusic      = window.location.hostname === 'music.youtube.com';
    let dialogElementQueryRef = isYoutubeMusic ? 'ytmusic-you-there-renderer' : 'yt-confirm-dialog-renderer';

    // Options for the observer (which mutations to observe)
    let observer, observer2;
    const observerConfig  = { attributes: true };
    const observerConfig2 = { childList: true, subtree: true };


    // Start init
    let existCondition = setInterval(function() {
        if (document.getElementById("masthead-container")) {
            clearInterval(existCondition);
            setupProcess();
            count = 0;
        } else {
            if (count == 12) {  // ~ 6 sec through half sec loops
                count = 0;
                clearInterval(existCondition);
                setupProcess();
            } else {
                count++;
            }
        }
    }, 500); // check every 500ms

    const setupProcess = () => {
        loadUI();
        setupVariables();
        fillUIAndSetupEvents();
        setupObservers();
    }

    const loadUI = () => {
        // Look to add saving image from video elm.
        // path = "/html/body/ytd-app/div/ytd-page-manager/ytd-watch-flexy/div[4]/div[1]/div/div[1]/div/div/div/ytd-player/div/div/div[1]/video"
        // elm = document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
        if (navigator.appVersion.indexOf("Win")!=-1) OSName   = "Windows";
        if (navigator.appVersion.indexOf("Mac")!=-1) OSName   = "MacOS";
        if (navigator.appVersion.indexOf("X11")!=-1) OSName   = "UNIX";
        if (navigator.appVersion.indexOf("Linux")!=-1) OSName = "Linux";

        // Check if we've loaded elements already...
        if (!document.getElementById("slugCopyZone")) {
            document.body.insertAdjacentHTML( 'beforeend', slugTemplate );
            document.body.insertAdjacentHTML( 'beforeend', menuTemplate );
            document.body.insertAdjacentHTML( 'beforeend', thumbnailTemplate );
            document.body.insertAdjacentHTML( 'beforeend', popedContainerTemplate );
            controlsAreLoaded = false;
        } else {
            controlsAreLoaded = true;
        }

        // Remove download button if system doesn't support youtube-dl functionality
        ytEnhancerMenu = document.getElementById("enhancerMenuID");
        if (!OSName.includes("MacOS") && !OSName.includes("UNIX") && !OSName.includes("Linux")) {
            console.log("System does not support downloader...");
            ytEnhancerMenu.removeChild(ytDownloadBttn);
        }
    }

    const setupVariables = () => {
        ytEnhancerMenu2  = document.getElementById("enhancerMenuID2");
        ytThumbnailBttn  = document.getElementById("ytThumbnailBttn");
        ytLoopBttn       = document.getElementById("ytLoopBttn");
        ytRangeEnd       = document.getElementById("rangeEndID");
        ytRangeStart     = document.getElementById("rangeStartID");
        ytFloatBttn      = document.getElementById("ytFloatBttn");
        ytDownloadBttn   = document.getElementById("ytDownloadBttn");
        volumeContainer  = document.getElementById("volumeContainerID");
        volumeLbl        = document.getElementById("volumeValueLbl");
        endlessPlayTag   = document.getElementById("endlessPlayID");

        ytThumbImgMenu   = document.getElementById("ytThumbMenuID");
        ytAMaxDefaultImg = document.getElementById("ytAMaxDefaultImgID");
        ytAHqDefaultImg  = document.getElementById("ytAHqDefaultImgID");
        ytAMedDefaultImg = document.getElementById("ytAMedDefaultImgID");
        ytASdDefaultImg  = document.getElementById("ytASdDefaultImgID");
        ytMaxDefaultImg  = document.getElementById("ytMaxDefaultImgID");
        ytHqDefaultImg   = document.getElementById("ytHqDefaultImgID");
        ytMqDefaultImg   = document.getElementById("ytMqDefaultImgID");
        ytSdDefaultImg   = document.getElementById("ytSdDefaultImgID");

        poppedContainer  = document.getElementById("draggable");
        ytIfrm           = document.getElementById("popIframe");
        slugInputTag     = document.getElementById("slugCopyZone");

        // Video Controler
        video = document.getElementsByTagName("video")[0];
        // Container of actual player (Used for floating window)
        containerOfPlyrWndow = document.getElementById("player-container");

        part = "https://img.youtube.com/vi/";
    }

    const fillUIAndSetupEvents = () => {
        slugInputTag.value = video.baseURI.slice(32, 32+11);
        ytRangeStart.value = "0:00";

        // We need to wait for info to load before getting full duration
        setTimeout(function () {
            videoTimeLength  = document.getElementsByClassName("ytp-time-duration")[0].innerText;
            ytRangeEnd.value = videoTimeLength;
        }, 2000);

        // Only setting these up if we need to load controls' info
        if (!controlsAreLoaded) {
            setbuttonImage(ytThumbnailBttn, "/icons/thumbnailOff.png");
            setbuttonImage(ytLoopBttn,      "/icons/loopFalse.png");
            setbuttonImage(ytFloatBttn,     "/icons/floatPlayer.png");
            setbuttonImage(ytDownloadBttn,  "/icons/downloadVid.png");

            // Set onclick actions
            ytThumbnailBttn.addEventListener("click", showThumbImageVew);
            ytLoopBttn.addEventListener("click", setVideoLoopState);
            ytFloatBttn.addEventListener("click", toggleFloat);
            endlessPlayTag.addEventListener("click", toggleEndlessPlay);
            ytDownloadBttn.addEventListener("click", downloadVideo);
            video.addEventListener("wheel", manageVolume);
            // Dragable window for floating video event setup
            dragVideo(poppedContainer);
        }
    }

    const setupObservers = () => {
        // ----  Hide controls if fullscreen using obsever  ----
        // Observer target for fullscreen action...
        let targetNode = document.getElementsByTagName('ytd-app')[0];
        // Create an observer instance linked to the callback function
        observer = new MutationObserver(mutationCallback);
        // Start observing the target node for configured mutations
        observer.observe(targetNode, observerConfig);

        // ----  Endless play obsever  ----
        // Create an observer instance linked to the callback function
        observer2 = new MutationObserver(mutationCallback);
        // Start observing the target node for configured mutations
        if (endlessPlayTag.checked == true) {
            this.isEndlessWatch = true;
            console.log("Endless play checked. Starting observer...");
            observer2.observe(document, observerConfig2);
        }
    }

    // Functions
    // Callback function to execute when mutations are observed
    const mutationCallback = (mutationsList, observer) => {
        for(let mutation of mutationsList) {
            if (mutation.type === 'attributes') {
                controlsShowHideToggle(mutation.target);
            } else if (mutation.type === 'childList') {
                if (this.isEndlessWatch) {
                    let elm = document.querySelector(dialogElementQueryRef).parentElement;
                    elmDisplayState = elm.style.display;
                    if (elmDisplayState !== 'none' && modalHasBeenClosed == false) {
                        modalHasBeenClosed = true;
                        clickDialog();
                        setTimeout(function () {
                            modalHasBeenClosed = false;
                        }, 5000);
                    }
                }
            }
        }
    };

    const controlsShowHideToggle = (elm) => {
        attrib = elm.getAttribute('masthead-hidden_');
        if (attrib == null) { // if out of fullscreen
            ytEnhancerMenu.style.display  = "block";
            ytEnhancerMenu2.style.display = "block";
        } else {  // if fullscreen
            ytEnhancerMenu.style.display  = "none";
            ytEnhancerMenu2.style.display = "none";
        }
    }

    const clickDialog = () => {
        console.log("Clicking dialog confirm to continue playing...");
        document.querySelector(dialogElementQueryRef)
                .querySelector('yt-button-renderer[dialog-confirm]')
                .click();
    }

    const toggleEndlessPlay = () => {
        if (this.isEndlessWatch) {
            endlessPlayTag.setAttribute("checked", false);
            this.isEndlessWatch = false;
            console.log("Stopping endless play...");
            observer2.disconnect();
        } else {
            endlessPlayTag.setAttribute("checked", true);
            this.isEndlessWatch = true;
            console.log("Starting endless play...");
            observer2.observe(confirmDialogElement, observerConfig2);
        }
    }

    const showThumbImageVew = (e) => {
        videoSlug = video.baseURI.slice(32, 32+11);  // Used for setting up thumbnails

        if (ytThumbImgMenu.style.display == "block") {
            ytThumbImgMenu.style.display = "none";
            setbuttonImage(ytThumbnailBttn, "/icons/thumbnailOff.png");
        } else {
            ytAMaxDefaultImg.href        = part + videoSlug + "/maxresdefault.jpg";
            ytAHqDefaultImg.href         = part + videoSlug + "/hqdefault.jpg";
            ytAMedDefaultImg.href        = part + videoSlug + "/mqdefault.jpg";
            ytASdDefaultImg.href         = part + videoSlug + "/sddefault.jpg";
            ytMaxDefaultImg.src          = part + videoSlug + "/maxresdefault.jpg";
            ytHqDefaultImg.src           = part + videoSlug + "/hqdefault.jpg";
            ytMqDefaultImg.src           = part + videoSlug + "/mqdefault.jpg";
            ytSdDefaultImg.src           = part + videoSlug + "/sddefault.jpg";
            setbuttonImage(ytThumbnailBttn, "/icons/thumbnailOn.png");
            ytThumbImgMenu.style.display = "block";
        }
        return;
    }

    const setVideoLoopState = (e) => {
        let start = ytRangeStart.value.trim();
        let end   = ytRangeEnd.value.trim();

        if (loopingInterval) {
            console.log("Unsetting interval for loop check...");
            clearInterval(ytVideoIntervalLoop);
            loopingInterval   = false;
            ytLoopBttn.title  = "Start Loop...";
            let ipath = browser.extension.getURL("/icons/loopFalse.png");
            setbuttonImage(ytLoopBttn, ipath);
            return ;
        }

        if (start.includes("0:00") && end.includes(videoTimeLength)) {
            if (video.loop == false) {
                console.log("Setting default loop marker...");
                video.loop        = true;
                ytLoopBttn.title  = "Stop Loop...";
                let ipath = browser.extension.getURL("/icons/loopTrue.png");
                setbuttonImage(ytLoopBttn, ipath);
            } else {
                console.log("Unsetting default loop marker...");
                video.loop        = false;
                ytLoopBttn.title  = "Start Loop...";
                let ipath = browser.extension.getURL("/icons/loopFalse.png");
                setbuttonImage(ytLoopBttn, ipath);
            }
            return ;
        } else {
            const getTotalSize = (array) => {
                let size    = 0.0;
                let hours   = 0.0;
                let minutes = 0.0;
                let seconds = 0.0;

                if (array.length === 2) {
                    minutes = parseFloat(array[0]) * 60.0;
                    seconds = parseFloat(array[1]);
                    size    = minutes + seconds;
                } else if (array.length === 3) {
                    hours   = parseFloat(array[0]) * 3600.0;
                    minutes = parseFloat(array[1]) * 60.0;
                    seconds = parseFloat(array[2]);
                    size    = hours + minutes + seconds;
                }
                return size;
            }

            const checkLoopStuff = () => {
                videoTimeCurent = video.currentTime;
                if (videoTimeCurent > totalEnd ||
                    videoTimeCurent < totalStart) {
                        video.currentTime = totalStart;
                }
            }


            // Make sure start and end are proper
            let totalStart = getTotalSize(start.split(":"));
            let totalEnd   = getTotalSize(end.split(":"));
            if (totalStart < 0.0 || totalStart > video.duration) { return ; }
            if (totalEnd < 0.0   || totalEnd > video.duration)   { return ; }

            // Setup interval check for 1 sec and compare value of current pos to end
            ytLoopBttn.title = "Stop Loop...";
            let ipath = browser.extension.getURL("/icons/loopTrue.png");
            setbuttonImage(ytLoopBttn, ipath);
            loopingInterval  = true;

            console.log("Setting interval for loop check...");
            ytVideoIntervalLoop = setInterval(checkLoopStuff, 1000);
        }
    }

    const toggleFloat = () => {
        let mainPlayer = document.getElementById("player-container-outer");
        var ifrmBody   = (ytIfrm.contentWindow || ytIfrm.contentDocument);
        if (ifrmBody.document) ifrmBody = ifrmBody.document;

        if (poppedContainer.style.display == "none"){
            video.pause();
            mainPlayer.style.display = "none";
            ytIfrm.src = "https://www.youtube.com/embed/" + video.baseURI.slice(32, 32+11) +
                                 "?autoplay=1&amp;start=" + Math.floor(video.currentTime);
            poppedContainer.style.display = "block";
        } else {
            video.currentTime = ifrmBody.getElementsByTagName("video")[0].currentTime;
            poppedContainer.style.display = "none";
            mainPlayer.style.display      = "";
            ytIfrm.src                    = "";
            video.play();
        }
    }

    const setVideoStyle = (w, h, pr) => {
        let elm = document.getElementsByClassName("ytp-right-controls")[0];
        video.style.width  = w;
        video.style.height = h;
        elm.style.paddingRight = pr;
        console.log("W: " + w + "\nH: " + h + "\npr: " + pr);
        console.log(video.style);
    }

    const manageVolume = (e) => {
        let delta;
        e.preventDefault(); // Keep page from scrolling while in video area

        shouldHideVol = false;
        volumeContainer.style.display = "block";

        // Detect scroll direction
        let incramentType = "+";
        if (e.wheelDelta) delta = e.wheelDelta; else delta = -1 * e.deltaY;
        // Vol UP || Vol DOWN
        let tmpVol = video.volume.toFixed(2);
        let volume = Math.round((tmpVol * 100), 2).toFixed(0);

        if (delta > 0) {
            incramentType = "+";
            while ((volume % 5) !== 0) { volume += 1; }
            video.volume = (volume/100) + 0.05;
        } else if (delta < 0) {
            incramentType = "-";
            while ((volume % 5) !== 0) { volume -= 1; }
            video.volume  = (volume/100) - 0.05;
        }

        volumeLbl.innerText = incramentType + Math.round((video.volume * 100), 1).toFixed(0);
        setTimeout(function () {
            if (shouldHideVol) {
                volumeContainer.style.display = "none";
            }
        }, 1000);
        shouldHideVol = true;
    }

    const dragVideo = (elmnt) => {
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        elmnt.onmousedown = dragMouseDown;

        function dragMouseDown(e) {
            e = e || window.event;
            pauseEvent(e);
            // get the mouse cursor position at startup:
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDragElement;
            // call a function whenever the cursor moves:
            document.onmousemove = elementDrag;
        }

        const elementDrag = (e) => {
            e = e || window.event;
            pauseEvent(e);
            // calculate the new cursor position:
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            // set the element's new position:
            elmnt.style.top  = (elmnt.offsetTop - pos2) + "px";
            elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
        }

        const closeDragElement = (e) => {
            // stop moving when mouse button is released:
            document.onmouseup   = null;
            document.onmousemove = null;
        }

        const pauseEvent = (e) => {
            if(e.stopPropagation) e.stopPropagation();
            if(e.preventDefault)  e.preventDefault();
            e.cancelBubble = true;
            e.returnValue  = false;
        return false;
        }
    }

    const downloadVideo = () => {
        console.log("Downloading: " + video.baseURI);
        browser.runtime.sendMessage( { "url": video.baseURI } );
    }

    const setbuttonImage = (elm, path) => {
        elm.style.backgroundImage = "url('" + browser.extension.getURL(path); + "')";
    }
}());
