(function (win, doc) {
    let cAdminPage, cPlacementTable, cPlacementTableBody, cPopup;
    let cInputListData;


    if (doc.readyState === "complete" || doc.readyState === "interactive") {
        init();
    } else {
        doc.addEventListener('DOMContentLoaded', init);
    }

    function init() {
        cAdminPage = doc.querySelector('.r2b2-options');
        cPlacementTable = doc.querySelector('#r2b2-placement-table');
        cInputListData = doc.querySelector('#r2b2_settings_list_data');

        if (!isElement(cPlacementTable) ||
            !isElement(cInputListData)) {
            setTimeout(init, 3000);
            console.warn('[R2B2] Essential elements not found. Next try in 3 seconds. Contact R2B2 support in case of problems.');
            return;
        }

        displayPlacementTable();

        window.addEventListener('keydown', function (ev) {
            if (ev.code === "Escape") {
                closePopup();
            }
        });

        win.r2b2 = {
            displayPopupAddPlacements
        }
    }

    /*  Display */
    function displayPlacementTable() {
        if (!cPlacementTable) throw Error('Table not found');
        cPlacementTableBody = cPlacementTable.querySelector('tbody');
        if (cPlacementTableBody) {
            cPlacementTableBody.remove();
        }

        cPlacementTableBody = doc.createElement('tbody');
        cPlacementTable.appendChild(cPlacementTableBody);

        const placements = getPlacementData();
        if (placements.length === 0) {
            for (let i = 0; i < 3; i++) {
                let tr = doc.createElement('tr');
                let td1 = doc.createElement('td');
                let td2 = doc.createElement('td');
                let td3 = doc.createElement('td');
                let td4 = doc.createElement('td');
                let td5 = doc.createElement('td');
                let td6 = doc.createElement('td');
                tr.appendChild(td1);
                tr.appendChild(td2);
                tr.appendChild(td3);
                tr.appendChild(td4);
                tr.appendChild(td5);
                tr.appendChild(td6);
                cPlacementTableBody.appendChild(tr);
            }
        } else {
            for (const placementData of placements) {
                let tr = doc.createElement('tr');
                let tdName = doc.createElement('td');
                let tdType = doc.createElement('td');
                let tdState = doc.createElement('td');
                let tdParagraphIndex = doc.createElement('td');
                let tdDemo = doc.createElement('td');
                let tdAction = doc.createElement('td');

                tdName.className = 'r2b2-pltab-name';
                tdType.className = 'r2b2-pltab-mt';
                tdState.className = 'r2b2-pltab-status';
                tdParagraphIndex.className = 'r2b2-pltab-paragraph';
                tdDemo.className = 'r2b2-pltab-demo';
                tdAction.className = 'r2b2-pltab-action';

                tdName.textContent = getAYMPlacementName(placementData.dgpm);
                tdType.textContent = getMediaType(placementData.dgpm.p);
                const randomText = Math.round(Math.random() * 1000);
                tdState.appendChild(createToggle('delivery-' + randomText, 'delivery-' + randomText, placementData.delivery_enabled, createCheckboxListenerDelivery(placementData.dgpm)));
                tdDemo.appendChild(createToggle('demo-' + randomText, 'demo-' + randomText, placementData.demo, createCheckboxListenerDemo(placementData.dgpm)));

                const textParagraphIndex = doc.createElement('span');
                textParagraphIndex.textContent = placementData.paragraph_index ?? '-';
                tdParagraphIndex.appendChild(textParagraphIndex);

                const buttonEditPlacement = createButton('Edit');
                if (!isPlacementWithContainer(placementData.dgpm)) {
                    buttonEditPlacement.classList.add('button-disabled');
                    buttonEditPlacement.disabled = true;
                }
                buttonEditPlacement.addEventListener('click', () => displayPopupEditPlacement(placementData.dgpm));
                tdAction.appendChild(buttonEditPlacement);

                tr.appendChild(tdName);
                tr.appendChild(tdType);
                tr.appendChild(tdState);
                tr.appendChild(tdParagraphIndex);
                tr.appendChild(tdDemo);
                tr.appendChild(tdAction);
                cPlacementTableBody.appendChild(tr);
            }
        }
    }

    function displayPopupAddPlacements() {
        if (cPopup) closePopup();

        cPopup = doc.createElement('div');
        const cBack = doc.createElement('div');
        const cFront = doc.createElement('div');
        const cCloser = doc.createElement('button');
        const cHeadline = doc.createElement('h1');
        const cText1 = doc.createElement('p');
        const cText2 = doc.createElement('p');
        const cTextArea = doc.createElement('textarea');
        const cButtonContainer = doc.createElement('div');
        const cSave = doc.createElement('button');

        cPopup.className = 'r2b2-popup';
        cFront.className = 'r2b2-popup-foreground';
        cBack.className = 'r2b2-popup-background';
        cBack.addEventListener('click', closePopup);

        cCloser.className = 'r2b2-popup-closer';
        cCloser.textContent = '⨯';
        cCloser.title = 'Close popup';
        cCloser.addEventListener('click', closePopup);
        cCloser.focus();

        cHeadline.textContent = 'Add placements';
        cText1.innerHTML = 'Insert the source codes, which you have acquired from R2B2, in this format:' + '<br><code>&lt;script type="text/javascript" src="//delivery.r2b2.io/get/example.com/generic/sticky"&gt;&lt;/script&gt;</code>';
        cText2.textContent = 'Or copy and paste all the content from the source code file which you have acquired in the R2B2 e-mail.';

        cTextArea.style.width = '100%';
        cTextArea.setAttribute('rows', '8');

        cButtonContainer.style.textAlign = 'right';

        cSave.className = 'button button__primary button--sm';
        cSave.innerHTML = '<span class="text-block text-block--bold text-block--md">Add</span>';
        cSave.addEventListener('click', () => processPopupAddPlacements(cTextArea.value));


        cFront.appendChild(cCloser);
        cFront.appendChild(cHeadline);
        cFront.appendChild(cText1);
        cFront.appendChild(cText2);
        cFront.appendChild(cTextArea);
        cButtonContainer.appendChild(cSave);
        cFront.appendChild(cButtonContainer);
        cPopup.appendChild(cFront);
        cPopup.appendChild(cBack);
        cAdminPage.appendChild(cPopup);
        cTextArea.focus();
    }

    function displayPopupEditPlacement(dgpm, callbackAfterSave) {
        if (cPopup) closePopup();
        let plData = getPlacementDataSingle(dgpm);

        cPopup = doc.createElement('div');
        const cBack = doc.createElement('div');
        const cFront = doc.createElement('div');
        const cCloser = doc.createElement('button');
        const cForm = doc.createElement('form');
        const cPlName = doc.createElement('h1');
        const cHeadline = doc.createElement('h2');
        const cText1 = doc.createElement('p');
        const cText2 = doc.createElement('span');
        const cInputParagraph = doc.createElement('input');
        const cButtonContainer = doc.createElement('div');
        const cSave = doc.createElement('button');

        cPopup.className = 'r2b2-popup';
        cFront.className = 'r2b2-popup-foreground';
        cBack.className = 'r2b2-popup-background';
        cBack.addEventListener('click', closePopup);

        cCloser.className = 'r2b2-popup-closer';
        cCloser.textContent = '⨯';
        cCloser.title = 'Close popup';
        cCloser.addEventListener('click', closePopup);
        cCloser.focus();

        cPlName.textContent = getAYMPlacementName(dgpm);
        cHeadline.textContent = 'Settings for banner placement in the articles';
        cText1.innerHTML = 'The banner will be displayed in the article after the selected paragraph.';
        cText2.textContent = 'Article paragraph: ';

        cInputParagraph.type = 'number';
        cInputParagraph.min = '1';
        cInputParagraph.max = '50';
        cInputParagraph.required = true;
        cInputParagraph.value = plData.paragraph_index;

        cButtonContainer.style.textAlign = 'right';

        cSave.type = "submit";
        cSave.className = 'button button__primary button--sm';
        cSave.innerHTML = '<span class="text-block text-block--bold text-block--md">Save</span>';

        cForm.addEventListener('submit', function (ev) {
            ev.preventDefault();

            updatePlacementData(dgpm, {paragraph_index: cInputParagraph.value});
            closePopup();
            if (callbackAfterSave && typeof callbackAfterSave === "function") {
                callbackAfterSave();
            }
            displayPlacementTable();
        })

        cFront.appendChild(cForm);
        cForm.appendChild(cCloser);
        cForm.appendChild(cPlName);
        cForm.appendChild(cHeadline);
        cForm.appendChild(cText1);
        cForm.appendChild(cText2);
        cForm.appendChild(cInputParagraph);
        cButtonContainer.appendChild(cSave);
        cForm.appendChild(cButtonContainer);
        cPopup.appendChild(cFront);
        cPopup.appendChild(cBack);
        cAdminPage.appendChild(cPopup);
        cInputParagraph.focus();
    }

    function closePopup() {
        if (typeof cPopup === "object" && typeof cPopup.remove === "function") {
            cPopup.remove();
            cPopup = null;
        }
        displayPlacementTable();
    }


    function createButton(text) {
        const button = doc.createElement('button');
        const content = doc.createElement('span');

        button.setAttribute('class', 'button button__primary button--sm');
        button.style.verticalAlign = 'middle';
        content.setAttribute('class', 'text-block text-block--bold text-block--md');
        content.textContent = text;

        button.appendChild(content);
        return button;
    }

    function createToggle(id, name, checked, eventListener) {
        const label = doc.createElement('label');
        const input = doc.createElement('input');
        const swField = doc.createElement('span');
        const swLabel = doc.createElement('span');

        label.className = 'switch';
        input.name = name;
        input.id = id;
        input.type = 'checkbox';
        input.checked = checked;
        input.addEventListener('change', eventListener);
        swField.className = 'switch__field';
        swLabel.className = 'switch__label';
        label.appendChild(input);
        label.appendChild(swField);
        label.appendChild(swLabel);
        return label;
    }

    function createCheckboxListenerDelivery(dgpm) {
        return function () {
            if (isPlacementWithContainer(dgpm)) {
                const pl = getPlacementDataSingle(dgpm);
                if (!pl.paragraph_index && this.checked) {
                    displayPopupEditPlacement(dgpm, function () {
                        updatePlacementData(dgpm, {delivery_enabled: true})
                    }.bind(this));
                    return;
                }
            }
            updatePlacementData(dgpm, {delivery_enabled: this.checked});
        }
    }

    function createCheckboxListenerDemo(dgpm) {
        return function () {
            updatePlacementData(dgpm, {demo: this.checked});
        }
    }

    /*  Processing  */

    function processPopupAddPlacements(newPlacements) {
        if (typeof newPlacements !== "string") throw new Error('Invalid data in new placements');
        const regexScript = /(src=["'`]([a-z0-9\.\-_/]+)["'`])/gim;
        const regexUrl = /\/\/(delivery.r2b2.io|delivery.r2b2.cz|trackad.cz|track.us.org|adtrack.docker)\/get\/([a-z0-9\._\-]+)\/([a-z0-9\._]+)\/([a-z0-9\._]+)\/?([a-z0-9\._]*)/i;
        for (const match of newPlacements.matchAll(regexScript)) {
            const srcUrl = match[2];
            const urlParts = srcUrl.match(regexUrl);
            const isMobile = !['desktop', 'classic', '0', ''].includes(urlParts[5]);
            const dgpm = {
                d: urlParts[2],
                g: urlParts[3],
                p: urlParts[4],
                m: isMobile,
            };
            if (!getPlacementDataSingle(dgpm)) {
                addPlacementData(createPlacementObj(dgpm, !isPlacementWithContainer(dgpm)));
            }
        }
        closePopup();
    }

    /**
     *
     * @returns {string[]|[]}
     */
    function getPlacementData() {
        if (!isElement(cInputListData)) throw new Error('List is not an Element');
        const value = cInputListData.value;
        let placementsData = [];
        if (value !== '') {
            const placementsDataRaw = value.split('\n');
            for (const placementData of placementsDataRaw) {
                if (placementData.trim() === '') continue;
                const data = JSON.parse(placementData);
                if (!data.dgpm || !data.dgpm.d || !data.dgpm.g || !data.dgpm.p) continue;
                placementsData.push(createPlacementObj(data.dgpm, data.delivery_enabled, data.demo, data.paragraph_index));
            }
        }
        return placementsData;
    }

    function getPlacementDataSingle(dgpm) {
        if (!isElement(cInputListData)) throw new Error('List is not an Element');
        const value = cInputListData.value;
        if (value !== '') {
            const placementsDataRaw = value.split('\n');
            for (const placementData of placementsDataRaw) {
                if (placementData.trim() === '') continue;
                const pl = JSON.parse(placementData);
                if (pl.dgpm.d === dgpm.d && pl.dgpm.g === dgpm.g && pl.dgpm.p === dgpm.p && pl.dgpm.m === dgpm.m) {
                    return createPlacementObj(pl.dgpm, pl.delivery_enabled, pl.demo, pl.paragraph_index);
                }
            }
        }
        return false;
    }

    function overwritePlacementData(data) {
        if (!isElement(cInputListData)) throw new Error('List is not an Element');
        let result = [];
        for (const placementData of data) {
            result.push(JSON.stringify(placementData));
        }
        cInputListData.value = result.join("\n");
        warnBeforeExit();
    }

    function addPlacementData(data) {
        if (!isElement(cInputListData)) throw new Error('List is not an Element');
        cInputListData.value += "\n" + JSON.stringify(data);
        warnBeforeExit();
    }

    function createPlacementObj(dgpm, delivery = true, demo = false, paragraphIndex = null) {
        return {
            'dgpm': {
                'd': dgpm.d,
                'g': dgpm.g,
                'p': dgpm.p,
                'm': dgpm.m,
            },
            'delivery_enabled': delivery,
            'paragraph_index': paragraphIndex,
            'demo': demo,
        };
    }

    function updatePlacementData(dgpm, newData) {
        if (!isElement(cInputListData)) throw new Error('List is not an Element');

        let data = getPlacementData();
        for (let i = 0; i < data.length; i++) {
            const pl = data[i];
            if (pl.dgpm.d === dgpm.d && pl.dgpm.g === dgpm.g && pl.dgpm.p === dgpm.p && pl.dgpm.m === dgpm.m) {
                for (const newDataKey in newData) {
                    data[i][newDataKey] = newData[newDataKey];
                }
            }
        }
        overwritePlacementData(data);
    }

    function isElement(element) {
        return element instanceof Element || element instanceof HTMLDocument;
    }

    function isPlacementWithContainer(dgpm) {
        return ['Interscroller', 'Outstream', 'Native', 'Banner'].includes(getMediaType(dgpm.p));
    }

    function getAYMPlacementName(dgpm) {
        const isMobile = dgpm.m === 'mobile' || dgpm.m === true;
        return `${dgpm.g} ${dgpm.p} ${isMobile ? 'mobile ' : ''}(${dgpm.d})`;
    }

    function getMediaType(position) {
        if (position.indexOf('sticky') !== -1 || position.indexOf('fixed') !== -1) {
            return 'Sticky';
        } else if (position.indexOf('vignette') !== -1) {
            return 'Vignette';
        } else if (position.indexOf('interscroll') !== -1) {
            return 'Interscroller';
        } else if (position.indexOf('inmedia') !== -1) {
            return 'In-Media';
        } else if (position.indexOf('outstream') !== -1) {
            return 'Outstream';
        } else if (position.indexOf('native') !== -1) {
            return 'Native';
        } else if (position.indexOf('branding') !== -1) {
            return 'Branding';
        } else {
            return 'Banner';
        }
    }

    function warnBeforeExit() {
        const listener = function (e) {
            e.preventDefault();
            e.returnValue = '';

            var confirmationMessage = 'You have unsaved changes. Are you sure you want to leave this page?';
            (e || window.event).returnValue = confirmationMessage;
            return confirmationMessage;
        }
        const submitBtn = window.document.querySelector('.r2b2-options input[type=submit]');
        if (submitBtn) {
            submitBtn.addEventListener('click', function () {
                window.removeEventListener('beforeunload', listener);
            })
        }
        window.addEventListener('beforeunload', listener);
    }

    function doError(message) {
        console.error('[R2B2]', message);
    }

})(window, window.document)
