//injectConfig library by @theripper93
//License: MIT
//Documentation: https://github.com/theripper93/injectConfig

export var injectConfig = {
    inject: function injectConfig(app, html, data, object) {
        html = $(html);
        this._generateTabStruct(app, html, data, object);
        const tabSize = data.tab?.width ?? 100;
        object = object || app.document;
        const moduleId = data.moduleId;
        let injectPoint;
        if (typeof data.inject === "string") {
            injectPoint = html.find(data.inject).first().closest(".form-group");
        } else {
            injectPoint = data.inject;
        }
        injectPoint = injectPoint ? $(injectPoint) : data.tab ? html.find("form > .tab").last() : html.find(".form-group").last();
        let injectHtml = "";
        for (const [k, v] of Object.entries(data)) {
            if (k === "moduleId" || k === "inject" || k === "tab") continue;
            const elemData = data[k];
            const flag = "flags." + moduleId + "." + (k || "");
            const flagValue = object?.getFlag(moduleId, k) ?? elemData.default ?? getDefaultFlag(k);
            const notes = v.notes ? `<p class="notes">${v.notes}</p>` : "";
            v.label = v.units ? v.label + `<span class="units"> (${v.units})</span>` : v.label;
            switch (elemData.type) {
                case "text":
                    injectHtml += `<div class="form-group">
                        <label for="${k}">${v.label || ""}</label>
                            <input type="text" name="${flag}" ${elemData.dType ? `data-dtype="${elemData.dType}"` : ""} value="${flagValue}" placeholder="${v.placeholder || ""}">${notes}
                    </div>`;
                    break;
                case "number":
                    injectHtml += `<div class="form-group">
                        <label for="${k}">${v.label || ""}</label>
                            <input type="number" name="${flag}" min="${v.min}" max="${v.max}" step="${v.step ?? 1}" value="${flagValue}" placeholder="${v.placeholder || ""}">${notes}
                    </div>`;
                    break;
                case "checkbox":
                    injectHtml += `<div class="form-group">
                        <label for="${k}">${v.label || ""}</label>
                            <input type="checkbox" name="${flag}" ${flagValue ? "checked" : ""}>${notes}
                    </div>`;
                    break;
                case "select":
                    injectHtml += `<div class="form-group">
                        <label for="${k}">${v.label || ""}</label>
                            <select name="${flag}" ${elemData.dType ? `data-dtype="${elemData.dType}"` : ""}>`;
                    for (const [i, j] of Object.entries(v.options)) {
                        injectHtml += `<option value="${i}" ${flagValue == i ? "selected" : ""}>${j}</option>`;
                    }
                    injectHtml += `</select>${notes}
                    </div>`;
                    break;
                case "range":
                    injectHtml += `<div class="form-group">
                        <label for="${k}">${v.label || ""}</label>
                        <div class="form-fields">
                            <input type="range" name="${flag}" value="${flagValue}" min="${v.min}" max="${v.max}" step="${v.step ?? 1}">
                            <span class="range-value">${flagValue}</span>${notes}
                        </div>
                    </div>`;
                    break;
                case "color":
                    injectHtml += `<div class="form-group">
                        <label for="${k}">${v.label || ""}</label>
                        <div class="form-fields">
                            <input class="color" type="text" name="${flag}" value="${flagValue}">
                            <input type="color" data-edit="${flag}" value="${flagValue}">
                        </div>
                        ${notes}
                    </div>`;
                    break;
                case "custom":
                    injectHtml += v.html;
                    break;
            }
            if (elemData.type?.includes("filepicker")) {
                const fpType = elemData.type.split(".")[1] || "imagevideo";
                injectHtml += `<div class="form-group">
                <label for="${k}">${v.label || ""}</label>
                <div class="form-fields">     
                    <button type="button" class="file-picker" data-extras="${elemData.fpTypes ? elemData.fpTypes.join(",") : ""}" data-type="${fpType}" data-target="${flag}" title="Browse Files" tabindex="-1">
                        <i class="fas fa-file-import fa-fw"></i>
                    </button>
                    <input class="image" type="text" name="${flag}" placeholder="${v.placeholder || ""}" value="${flagValue}">
                </div>${notes}
            </div>`;
            }
        }
        injectHtml = $(injectHtml);
        injectHtml.on("click", ".file-picker", this.fpTypes, _bindFilePicker);
        injectHtml.on("change", `input[type="color"]`, _colorChange);
        if (data.tab) {
            const injectTab = createTab(data.tab.name, data.tab.label, data.tab.icon).append(injectHtml);
            injectPoint.after(injectTab);
            app?.setPosition({ height: "auto", width: data.tab ? app.options.width + tabSize : "auto" });
            return injectHtml;
        }
        injectPoint.after(injectHtml);
        if (app) {
            const pos = {height: "auto"};
            if(data.tab) pos.width = app.options.width + tabSize;
            app?.setPosition(pos);
        }
        return injectHtml;

        function createTab(name, label, icon) {
            /*let tabs = html.find(".sheet-tabs").last();
            if(!tabs.length) tabs = html.find(`nav[data-group="main"]`);*/
            const tabs = html.find(".sheet-tabs").first().find(".item").last();
            const tab = `<a class="item" data-tab="${name}"><i class="${icon}"></i> ${label}</a>`;
            tabs.after(tab);
            const tabContainer = `<div class="tab" data-tab="${name}"></div>`;
            return $(tabContainer);
        }

        function getDefaultFlag(inputType) {
            switch (inputType) {
                case "number":
                    return 0;
                case "checkbox":
                    return false;
            }
            return "";
        }

        function _colorChange(e) {
            const input = $(e.target);
            const edit = input.data("edit");
            const value = input.val();
            injectHtml.find(`input[name="${edit}"]`).val(value);
        }

        function _bindFilePicker(event) {
            event.preventDefault();
            const button = event.currentTarget;
            const input = $(button).closest(".form-fields").find("input") || null;
            const extraExt = button.dataset.extras ? button.dataset.extras.split(",") : [];
            const options = {
                field: input[0],
                type: button.dataset.type,
                current: input.val() || null,
                button: button,
            };
            const fp = new FilePicker(options);
            fp.extensions ? fp.extensions.push(...extraExt) : (fp.extensions = extraExt);
            return fp.browse();
        }
    },
    quickInject: function quickInject(injectData, data) {
        injectData = Array.isArray(injectData) ? injectData : [injectData];
        for (const doc of injectData) {
            let newData = data;
            if (doc.inject) {
                newData = JSON.parse(JSON.stringify(data));
                data.inject = doc.inject;
            }
            Hooks.on(`render${doc.documentName}Config`, (app, html) => {
                injectConfig.inject(app, html, newData);
            });
        }
    },
    _generateTabStruct: function _generateTabStruct(app, html, data, object) {
        const isTabs = html.find(".sheet-tabs").length;
        const useTabs = data.tab;
        if (isTabs || !useTabs) return;
        const tabSize = data.tab?.width || 100;
        const layer = app?.object?.layer?.options?.name;
        const icon = $(".main-controls").find(`li[data-canvas-layer="${layer}"]`).find("i").attr("class");

        const $tabs = $(`<nav class="sheet-tabs tabs">
        <a class="item active" data-tab="basic"><i class="${icon}"></i> ${game.i18n.localize("LIGHT.HeaderBasic")}</a>
        </nav>
        <div class="tab active" data-tab="basic"></div>`);
        //move all content of form into tab
        const form = html.find("form").first();
        form.children().each((i, e) => {
            $($tabs[2]).append(e);
        });

        form.append($tabs);
        const submitButton = html.find("button[type='submit']").first();
        form.append(submitButton);

        html.on("click", ".item", (e) => {
            html.find(".item").removeClass("active");
            $(e.currentTarget).addClass("active");
            html.find(".tab").removeClass("active");
            html.find(`[data-tab="${e.currentTarget.dataset.tab}"]`).addClass("active");
            app.setPosition({ height: "auto", width: data.tab ? app.options.width + tabSize : "auto" });
        });
    },
};
