"use strict";

const MAX_INPUT_SIZE = 1048576;

if ('serviceWorker' in navigator) {
    console.log("Registering service worker");
    navigator.serviceWorker.register('/sw.js');
}

class ConcPage {

    lang;
    tls;
    domWrapper;
    domUploaderWrapper;
    domResultsWrapper;
    domMainWrapper;

    constructor(lang, tls) {

        this.lang = lang;
        this.tls = Object.freeze(tls);

        let wrapper = document.createElement("div");
        wrapper.id = "contentWrapper";
        this.domWrapper = wrapper;

        let domUploaderWrapper = document.createElement("div");
        domUploaderWrapper.id = "uploader";
        domUploaderWrapper.classList.add("uploader");
        this.domUploaderWrapper = domUploaderWrapper;

        let domResultsWrapper = document.createElement("div");
        domResultsWrapper.id = "results";
        domResultsWrapper.classList.add("results");
        this.domResultsWrapper = domResultsWrapper;

        let domMainWrapper = document.createElement("main");
        this.domMainWrapper = domMainWrapper;
    }

    downloadFromString(filename, text) {

        const blob = new Blob([text], { type: "text/plain" });
        const link = document.createElement("a");

        link.download = filename;
        link.href = window.URL.createObjectURL(blob);
        link.dataset.downloadurl = ["text/plain", link.download, link.href].join(":");

        const evt = new MouseEvent("click", {
            view: window,
            bubbles: true,
            cancelable: true,
        });

        link.dispatchEvent(evt);
        link.remove()

    }

    renderGenHeader() {

        const header = document.createElement("header");
        header.id = "mainHeader";

        const logoArea = document.createElement("a");
        logoArea.id = "logoArea";
        logoArea.href = "https://www.museum-digital.org/";

        const logoImg = document.createElement("img");
        logoImg.src = "/static/img/mdlogo-code.svg";
        logoImg.alt = "Logo of museum-digital";
        logoArea.appendChild(logoImg);

        const h2 = document.createElement("h2");
        h2.textContent = "museum-digital";
        logoArea.appendChild(h2);

        header.appendChild(logoArea);

        // Right side of the header
        const nav = document.createElement("nav");

        const lAbout = document.createElement("a");
        lAbout.href = "https://en.about.museum-digital.org/about";
        lAbout.textContent = this.tls.about;
        nav.appendChild(lAbout);

        const lContactList = document.createElement("div");

        const lContact = document.createElement("a");
        lContact.textContent = this.tls.contact;
        lContact.href = "https://en.about.museum-digital.org/contact/";
        lContactList.appendChild(lContact);

        const lContactDiv = document.createElement("div");

        const lImprint = document.createElement("a");
        lImprint.textContent = this.tls.imprint;
        lImprint.href = "https://en.about.museum-digital.org/impressum";
        lContactDiv.appendChild(lImprint);

        const lPrivacy = document.createElement("a");
        lPrivacy.textContent = this.tls.privacy_policy;
        lPrivacy.href = "https://en.about.museum-digital.org/privacy/";
        lContactDiv.appendChild(lPrivacy);

        lContactList.appendChild(lContactDiv);
        nav.appendChild(lContactList);

        const lNews = document.createElement("a")
        lNews.textContent = this.tls.news;
        lNews.href = "https://blog.museum-digital.org/";
        nav.appendChild(lNews);

        header.appendChild(nav);
        document.body.appendChild(header);

    }

    renderHeader() {

        const appHeader = document.createElement("header");
        appHeader.id = "appHeader";

        const h1 = document.createElement("h1");

        const img = document.createElement("img");
        img.width = "70";
        img.height = "70";
        img.src = "/static/img/mdlogo-code.svg";
        img.alt = "";
        h1.appendChild(img);

        h1.appendChild(this.createPlainTextElem("span", "museum-digital:" + this.tls.concordance_checker));

        appHeader.appendChild(h1);

        document.body.appendChild(appHeader);

    }

    createP(text) {
        const output = document.createElement("p");
        output.textContent = text;
        return output;
    }

    createPlainTextElem(type, text) {
        const output = document.createElement(type);
        output.textContent = text;
        return output;
    }

    renderText() {

        const domH2 = document.createElement("h2");
        domH2.textContent = this.tls.quality_assessment_tools;
        this.domMainWrapper.appendChild(domH2);

        this.domMainWrapper.appendChild(this.createP(this.tls.intro));

        this.domWrapper.appendChild(this.domMainWrapper);

    }

    generateBoilerplateForTableSection(hl) {

        const passedSec = document.createElement("div");

        const passedHl = document.createElement("h3");
        passedHl.textContent = hl;
        passedSec.appendChild(passedHl);

        const passedTable = document.createElement("table");

        const passedThead = document.createElement("thead");
        passedTable.appendChild(passedThead);

        const passedTBody = document.createElement("tbody");
        passedTable.appendChild(passedTBody);

        passedSec.appendChild(passedTable);

        return {
            section: passedSec,
            thead: passedThead,
            tbody: passedTBody,
        };

    }

    generateListResponse(context, listOptionsEn, listOptions, elements) {

        // Empty
        while (this.domResultsWrapper.firstChild) {
            this.domResultsWrapper.removeChild(this.domResultsWrapper.firstChild);
        }

        // Fill passed entries

        if (elements.passed.length === undefined) {

            const passedSec = this.generateBoilerplateForTableSection(this.tls.passed);

            // TL TODO
            const theadTr = document.createElement("tr");
            for (const theadname of ['Input', 'Match']) {
                const theadTd = document.createElement("th");
                theadTd.textContent = theadname;
                theadTr.appendChild(theadTd);
            }
            passedSec.thead.appendChild(theadTr);

            for (const passedKey in elements.passed) {
                const passedValue = elements.passed[passedKey];
                const tr = document.createElement("tr");

                tr.appendChild(this.createPlainTextElem("td", passedKey));

                if (listOptions[passedValue]) {
                    tr.appendChild(this.createPlainTextElem("td", listOptions[passedValue]));
                }
                else {
                    valueTd.textContent = passedValue;
                    tr.appendChild(this.createPlainTextElem("td", passedValue));
                }

                passedSec.tbody.appendChild(tr);
            }

            this.domResultsWrapper.appendChild(passedSec.section);

        }

        // Fill unpassed entries
        const app = this;

        if (elements.not_passed.length !== 0) {

            const nonpassedSec = this.generateBoilerplateForTableSection(this.tls.not_yet_matched);

            const ntheadTr = document.createElement("tr");
            for (const theadname of ['Input', 'Select Your Match']) {
                const theadTd = document.createElement("th");
                theadTd.textContent = theadname;
                ntheadTr.appendChild(theadTd);
            }
            nonpassedSec.thead.appendChild(ntheadTr);

            let matchSelects = [];
            for (let nonpassedName of elements.not_passed) {
                const tr = document.createElement("tr");

                tr.appendChild(this.createPlainTextElem("td", nonpassedName));

                const valueTd = document.createElement("td");

                const valueSelect = document.createElement("select");
                valueSelect.setAttribute('data-input', nonpassedName);

                for (const key in listOptions) {
                    const opt = document.createElement("option");
                    opt.value = key;
                    opt.textContent = listOptions[key];
                    valueSelect.appendChild(opt);
                }

                matchSelects.push(valueSelect);
                valueTd.appendChild(valueSelect);

                tr.appendChild(valueTd);

                nonpassedSec.tbody.appendChild(tr);
            }

            this.domResultsWrapper.appendChild(nonpassedSec.section);

            const convertB = document.createElement("button");
            convertB.textContent = this.tls.generate_code_snippet;
            nonpassedSec.section.appendChild(convertB);

            const resultsWrap = document.createElement("div");
            convertB.addEventListener('click', function() {

                let keysAreNumeric = false;
                if (listOptions[1] !== undefined && listOptions[1] !== null) {
                    keysAreNumeric = true;
                }

                // First gather lines by target type for rough sorting
                let linesByType = {};
                for (let m of matchSelects) {

                    let line = ("'" + m.getAttribute("data-input") + "'").padEnd(40, " ") + " => ";
                    if (keysAreNumeric === true) {
                        line += m.value + ",";
                    }
                    else {
                        line += "'" + m.value + "',";
                    }
                    line += ' // ' + listOptionsEn[m.value];

                    // A
                    if (linesByType[m.value] === undefined) {
                        linesByType[m.value] = [];
                    }
                    linesByType[m.value].push(line);

                    m.setAttribute("readonly", "readonly");
                }

                // Then put the lines together so they can be joined
                let lines = [];
                for (let key in linesByType) {
                    for (let l of linesByType[key]) {
                        lines.push(l);
                    }
                }

                const output = " ".repeat(8) + lines.join("\n" + " ".repeat(8));
                console.log(output);

                // Present output online

                const resultsP = app.createP(output);
                resultsP.id = "resultsP";
                resultsP.style.fontFamily = "Monospace, Courier";
                resultsP.style.whiteSpace = "pre-wrap";

                resultsWrap.appendChild(resultsP);
                resultsP.scrollIntoView({block: "start", behavior: "smooth"});

                // Download
                app.downloadFromString("new-concordance-" + context + '.htm', output);

            });

            this.domResultsWrapper.appendChild(resultsWrap);

        }

        this.domResultsWrapper.scrollIntoView({block: "start", behavior: "smooth"});

        //

    }

    // Setup
    renderUploader() {

        const listSelect = document.createElement("select");

        const listOptions = document.documentElement.getAttribute("data-lists").split(',');

        for (const lOpt of listOptions) {
            const opt = document.createElement("option");
            opt.textContent = this.tls[lOpt];
            opt.value = lOpt;
            listSelect.appendChild(opt);
        }
        this.domUploaderWrapper.appendChild(listSelect);

        const textarea = document.createElement("textarea");
        textarea.placeholder = this.tls.one_line_per_entry;
        this.domUploaderWrapper.appendChild(textarea);

        const submitB = document.createElement("button");
        submitB.textContent = this.tls.submit;
        this.domUploaderWrapper.appendChild(submitB);

        const app = this;

        submitB.addEventListener('click', async function(e) {
            e.stopPropagation();
            e.preventDefault();

            // Load translations in English
            const listResponseEn = await window.fetch('/static/json/tls.' + listSelect.value + '.en.json', {
                method: 'GET', cache: 'no-cache',
            });

            if (listResponseEn.status !== 200) {
                const text = await response.text();
                window.alert(text);
            }
            const tListOptionsEn = await listResponseEn.json();

            // Load translations
            const listResponse = await window.fetch('/static/json/tls.' + listSelect.value + '.' + app.lang + '.json', {
                method: 'GET', cache: 'no-cache',
            });

            if (listResponse.status !== 200) {
                const text = await response.text();
                window.alert(text);
            }
            const tListOptions = await listResponse.json();

            // Get API output

            let requestBody = [];
            requestBody.push('terms=' + encodeURIComponent(textarea.value));
            const response = await window.fetch('/api/evaluate/' + listSelect.value, {
                method: 'POST', cache: 'no-cache',
                headers: {'Content-Type': 'application/x-www-form-urlencoded'},
                body: requestBody.join("&"),
            });

            if (response.status !== 200) {
                const text = await response.text();
                window.alert(text);
            }
            const elements = await response.json();

            app.generateListResponse(listSelect.value, tListOptionsEn, tListOptions, elements);

        });

        this.domWrapper.appendChild(this.domUploaderWrapper);
        this.domWrapper.appendChild(this.domResultsWrapper);

    }

    renderFooter() {

        const footer = document.createElement("footer");

        /*

        const licenseStatement = document.createElement("p");
        licenseStatement.textContent = "This work is licensed under the GNU Affero Public License Version 3.";
        footer.appendChild(licenseStatement);

        */

        const footerOptions = document.createElement("div");

        /*
        const codeLink = document.createElement("a");
        codeLink.textContent = "Source code";
        codeLink.href = "https://gitea.armuli.eu/museum-digital/csvxml";
        footerOptions.appendChild(codeLink);
        */

        /*
        const codeLink = document.createElement("a");
        codeLink.textContent = "API"; // TODO
        codeLink.href = "/swagger";
        footerOptions.appendChild(codeLink);
        */

        if ('serviceWorker' in navigator) {
            const refreshB = document.createElement("span");
            refreshB.textContent = this.tls.reload_application;
            refreshB.setAttribute("tabindex", 1);
            refreshB.addEventListener('click', function(e) {

                Promise.all(['conc-cache-v1'].map(function(cache) {
                    caches.has(cache).then(function(hasCache) {
                        if (hasCache === true) {
                            caches.delete(cache).then(function(deletionStatus) {});
                        }
                    })
                }))
                location.reload()

            }, {passive: true, once: true});
            footerOptions.appendChild(refreshB);
        }

        const allowedLangs = document.documentElement.getAttribute("data-allowed-langs").split(',');
        const langSel = document.createElement("div");
        for (let lang of allowedLangs) {
            const l = document.createElement("a");
            l.href = "#" + lang;
            l.textContent = lang;
            l.style.textTranform = "uppercase";
            l.addEventListener('click', function(e) {
                e.preventDefault();
                sessionStorage.setItem("lang", lang);
                location.reload();
            });
            langSel.appendChild(l);
        }
        footerOptions.appendChild(langSel);

        footer.appendChild(footerOptions);

        const licenseLine = document.createElement("p");

        const license = document.createElement("a");
        license.textContent = "MIT-Licensed";
        license.href = "https://opensource.org/license/mit";
        licenseLine.appendChild(license);

        licenseLine.appendChild(this.createPlainTextElem("span", " @ "));

        const author = document.createElement("a");
        author.textContent = "Joshua Ramon Enslin";
        author.href = "https://www.jrenslin.de";
        author.setAttribute("rel", "author");
        licenseLine.appendChild(author);

        licenseLine.appendChild(this.createPlainTextElem("span", ", "));

        const attributionYear = document.createElement("span");
        attributionYear.textContent = "2025";
        licenseLine.appendChild(attributionYear);

        footer.appendChild(licenseLine);

        document.body.appendChild(footer);

    }

}

(async function() {

    function getLang() {

        const allowedLangs = document.documentElement.getAttribute("data-allowed-langs").split(',');

        const langFromSession = sessionStorage.getItem("lang");
        if (langFromSession !== undefined && allowedLangs.includes(langFromSession)) {
            return langFromSession;
        }

        if (navigator.language === undefined) return 'en';

        const browserLang = navigator.language.toLowerCase().substr(0, 2);
        console.log(browserLang);

        if (allowedLangs.includes(browserLang)) return browserLang;
        else return 'en';

    }

    const lang = getLang();
    document.documentElement.setAttribute("lang", lang);

    document.body.classList.add("loading");

    let loaded = 0;

    let tls;

    function loadPage() {

        document.body.classList.remove("loading");

        const page = new ConcPage(lang, tls);
        page.renderGenHeader();
        page.renderHeader();
        page.renderText();
        page.renderUploader();
        document.body.appendChild(page.domWrapper);
        page.renderFooter();

    }

    window.fetch('/static/json/tls.' + lang + '.json', {
        method: 'GET', cache: 'no-cache', credentials: 'same-origin',
    }).then(function(response) {
        return response.json();
    }).then(function(elements) {
        tls = elements;
        loadPage();
    });

})();
