(() => {
    const menuController = window.WarpBoxUI?.bindMenuBar?.() || { close() {} };
    const rowsNode = document.getElementById("settings-rows");
    const searchInput = document.getElementById("settingsSearch");
    const categoryButtons = Array.from(document.querySelectorAll(".settings-category-button"));
    const groups = Array.from(document.querySelectorAll(".settings-group"));
    const saveButton = document.getElementById("saveButton");
    const exportButton = document.getElementById("exportButton");
    const importButton = document.getElementById("importButton");
    const resetButton = document.getElementById("resetButton");
    const importInput = document.getElementById("settingsImportInput");
    const dirtyChip = document.getElementById("dirtyChip");
    const actionSummary = document.getElementById("actionSummary");
    const visibleCount = document.getElementById("visibleCount");
    const editableCount = document.getElementById("editableCount");
    const unsavedCount = document.getElementById("unsavedCount");
    const lockedCount = document.getElementById("lockedCount");
    const statusLeft = document.getElementById("statusLeft");
    const statusMiddle = document.getElementById("statusMiddle");
    const statusRight = document.getElementById("statusRight");
    const popupClose = document.getElementById("doc-popup-close");
    const toastTarget = document.getElementById("toast");

    if (!rowsNode || !searchInput || !saveButton) return;

    const state = {
        currentCategory: "all",
        showChangedOnly: false,
        showLockedOnly: false
    };

    function parseRows() {
        try {
            return JSON.parse(rowsNode.textContent || "[]");
        } catch (_) {
            return [];
        }
    }

    const rowData = parseRows().reduce((map, row) => {
        map[row.key] = row;
        return map;
    }, {});

    const rows = Array.from(document.querySelectorAll(".setting-row")).map((row) => ({
        element: row,
        input: row.querySelector(".setting-input"),
        hint: row.querySelector('[data-role="hint"]'),
        badge: row.querySelector('[data-role="source-badge"]'),
        key: row.dataset.key,
        label: row.dataset.label,
        category: row.dataset.category,
        envName: row.dataset.envName,
        type: row.dataset.type,
        minimum: Number(row.dataset.minimum || 0),
        locked: row.classList.contains("is-locked")
    }));

    function showToast(message, type = "info", duration = 2400) {
        window.WarpBoxUI?.toast?.(message, type, { target: toastTarget, duration });
    }

    function escapeHtml(value) {
        return window.WarpBoxUI?.htmlEscape?.(value) || String(value ?? "");
    }

    function currentValue(row) {
        if (!row.input) return row.element.dataset.original || "";
        return String(row.input.value ?? "").trim();
    }

    function isDirty(row) {
        return !row.locked && currentValue(row) !== (row.element.dataset.original || "");
    }

    function validateRow(row) {
        if (row.locked || !row.input) {
            row.element.classList.remove("is-invalid");
            return true;
        }

        const value = currentValue(row);
        let valid = true;

        if (row.type === "size_gb") {
            if (!/^\d+(?:\.\d+)?$/.test(value)) valid = false;
            else if (Number(value) < row.minimum) valid = false;
        } else if (row.type === "int" || row.type === "int64") {
            if (!/^\d+$/.test(value)) valid = false;
            else if (Number(value) < row.minimum) valid = false;
        } else if (row.type === "bool") {
            valid = value === "true" || value === "false";
        }

        row.element.classList.toggle("is-invalid", !valid);
        return valid;
    }

    function rowMatchesSearch(row) {
        const query = searchInput.value.trim().toLowerCase();
        if (!query) return true;
        const data = [
            row.label,
            row.envName,
            row.element.dataset.description,
            row.key
        ].join(" ").toLowerCase();
        return data.includes(query);
    }

    function applyFilters() {
        let visible = 0;

        groups.forEach((group) => {
            let groupVisible = 0;
            group.querySelectorAll(".setting-row").forEach((node) => {
                const row = rows.find((item) => item.element === node);
                const categoryMatch = state.currentCategory === "all" || row.category === state.currentCategory;
                const searchMatch = rowMatchesSearch(row);
                const changedMatch = !state.showChangedOnly || isDirty(row);
                const lockedMatch = !state.showLockedOnly || row.locked;
                const show = categoryMatch && searchMatch && changedMatch && lockedMatch;
                node.classList.toggle("is-hidden", !show);
                if (show) {
                    visible += 1;
                    groupVisible += 1;
                }
            });
            group.hidden = groupVisible === 0;
        });

        visibleCount.textContent = String(visible);
        statusMiddle.textContent = `category: ${state.currentCategory}`;
    }

    function updateStats() {
        let dirty = 0;
        let editable = 0;
        let locked = 0;
        let invalid = 0;

        rows.forEach((row) => {
            if (row.locked) locked += 1;
            else editable += 1;
            if (isDirty(row)) dirty += 1;
            if (!validateRow(row)) invalid += 1;
        });

        editableCount.textContent = String(editable);
        lockedCount.textContent = String(locked);
        unsavedCount.textContent = String(dirty);
        dirtyChip.textContent = `${dirty} unsaved`;
        dirtyChip.classList.toggle("is-dirty", dirty > 0);
        saveButton.disabled = dirty === 0 || invalid > 0;

        if (invalid > 0) {
            actionSummary.textContent = `${invalid} invalid setting value(s) must be fixed before save.`;
            statusLeft.textContent = "Invalid values";
            statusRight.textContent = "fix before save";
        } else if (dirty > 0) {
            actionSummary.textContent = `${dirty} unsaved change(s) ready to save or export.`;
            statusLeft.textContent = "Unsaved changes";
            statusRight.textContent = "draft ready";
        } else {
            actionSummary.textContent = "No unsaved changes.";
            statusLeft.textContent = "No unsaved changes";
            statusRight.textContent = "admin only";
        }
    }

    function updateView() {
        updateStats();
        applyFilters();
    }

    function setCategory(category) {
        state.currentCategory = category;
        categoryButtons.forEach((button) => button.classList.toggle("is-active", button.dataset.category === category));
        applyFilters();
    }

    function draftValues() {
        const values = {};
        rows.forEach((row) => {
            if (!row.locked && isDirty(row)) values[row.key] = currentValue(row);
        });
        return values;
    }

    function updateRowFromPayload(payload) {
        const row = rows.find((item) => item.key === payload.key);
        if (!row) return;

        row.element.dataset.original = payload.value;
        row.element.dataset.default = payload.default_value || "";
        row.element.dataset.source = payload.source || "default";
        row.element.dataset.sourceBadge = payload.source_badge || payload.source || "default";
        row.element.dataset.description = payload.description || "";
        row.element.dataset.minimum = String(payload.minimum || 0);
        row.element.classList.toggle("is-locked", Boolean(payload.locked));
        row.locked = Boolean(payload.locked);
        row.minimum = Number(payload.minimum || 0);

        if (row.input) {
            row.input.value = payload.value ?? "";
            row.input.disabled = Boolean(payload.locked);
        }
        if (row.hint) {
            row.hint.textContent = payload.locked
                ? "Locked by environment or hard runtime implication."
                : payload.type === "size_gb"
                    ? "Use GB values. Decimals allowed, for example `0.5`."
                : (payload.default_value ? `Default: ${payload.default_value}` : "");
        }
        if (row.badge) {
            row.badge.textContent = payload.source_badge || payload.source || "default";
            row.badge.className = `settings-badge ${badgeClass(payload.source_badge || payload.source || "default")}`;
        }
        rowData[payload.key] = payload;
    }

    function badgeClass(source) {
        if (source === "default") return "badge-default";
        if (source === "environment") return "badge-env";
        if (source === "db override") return "badge-db";
        return "badge-hard";
    }

    function hydrateRows(payloadRows) {
        if (!Array.isArray(payloadRows)) return;
        payloadRows.forEach(updateRowFromPayload);
        updateView();
    }

    async function postJSON(url, body) {
        const response = await fetch(url, {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(body)
        });
        const payload = await response.json().catch(() => ({}));
        if (!response.ok) {
            throw new Error(payload.error || "Request failed");
        }
        return payload;
    }

    async function saveChanges() {
        const values = draftValues();
        if (Object.keys(values).length === 0) {
            showToast("No changed settings to save", "info");
            return;
        }
        try {
            const payload = await postJSON("/admin/settings/save", { values });
            hydrateRows(payload.rows);
            showToast(payload.message || "Settings saved", payload.warnings?.length ? "warning" : "success");
        } catch (error) {
            showToast(error.message, "error", 3200);
        }
    }

    async function resetDefaults() {
        if (!window.confirm("Reset all editable settings to built-in defaults?")) return;
        try {
            const payload = await postJSON("/admin/settings/reset", {});
            hydrateRows(payload.rows);
            showToast(payload.message || "Defaults restored", "success");
        } catch (error) {
            showToast(error.message, "error", 3200);
        }
    }

    async function resetSingleSetting(row) {
        if (row.locked || !row.input) return;

        if (isDirty(row)) {
            row.input.value = row.element.dataset.original || "";
            updateView();
            showToast(`${row.label} draft cleared`);
            return;
        }

        try {
            const payload = await postJSON("/admin/settings/reset", { keys: [row.key] });
            hydrateRows(payload.rows);
            showToast(`${row.label} reset`, "success");
        } catch (error) {
            showToast(error.message, "error", 3200);
        }
    }

    async function exportSettings() {
        try {
            const response = await fetch("/admin/settings/export");
            if (!response.ok) throw new Error("Could not export settings");
            const payload = await response.json();
            const blob = new Blob([JSON.stringify(payload, null, 2)], { type: "application/json;charset=utf-8" });
            const url = URL.createObjectURL(blob);
            const anchor = document.createElement("a");
            anchor.href = url;
            anchor.download = `warpbox-settings-${new Date().toISOString().replaceAll(":", "-")}.json`;
            anchor.click();
            URL.revokeObjectURL(url);
            showToast("Settings JSON exported");
        } catch (error) {
            showToast(error.message, "error", 3200);
        }
    }

    async function importSettingsFile(file) {
        if (!file) return;
        try {
            const text = await file.text();
            const payload = JSON.parse(text);
            const result = await postJSON("/admin/settings/import", payload);
            hydrateRows(result.rows);
            showToast(result.message || "Settings imported", result.warnings?.length ? "warning" : "success", 3200);
        } catch (error) {
            showToast(error.message || "Could not import settings JSON", "error", 3200);
        } finally {
            importInput.value = "";
        }
    }

    function discardUnsaved() {
        rows.forEach((row) => {
            if (!row.input) return;
            row.input.value = row.element.dataset.original || "";
        });
        updateView();
        showToast("Unsaved changes discarded");
    }

    function explainSources() {
        window.WarpBoxUI?.openPopup?.(
            "Setting Sources",
            `
                <ul>
                    <li><strong>default</strong>: built-in application value.</li>
                    <li><strong>environment</strong>: loaded from an environment variable.</li>
                    <li><strong>db override</strong>: saved from the admin settings page.</li>
                    <li><strong>hard env</strong>: visible here, but locked for safety.</li>
                </ul>
            `
        );
    }

    function explainReset() {
        window.WarpBoxUI?.openPopup?.(
            "Reset Behavior",
            `
                <p>Reset clears saved admin overrides.</p>
                <p>After reset, environment values win again. If no environment value exists, built-in defaults apply.</p>
            `
        );
    }

    function showRowInfo(row) {
        window.WarpBoxUI?.openPopup?.(
            row.label,
            `
                <p><strong>Environment variable:</strong> ${escapeHtml(row.envName || "n/a")}</p>
                <p><strong>Current source:</strong> ${escapeHtml(row.badge?.textContent || row.element.dataset.sourceBadge || "default")}</p>
                <p><strong>Description:</strong> ${escapeHtml(row.element.dataset.description || "No description available.")}</p>
                ${row.element.dataset.default ? `<p><strong>Default value:</strong> ${escapeHtml(row.element.dataset.default)}</p>` : ""}
            `
        );
    }

    async function runCommand(command) {
        switch (command) {
            case "save":
                await saveChanges();
                return;
            case "export":
                await exportSettings();
                return;
            case "import":
                importInput.click();
                return;
            case "discard":
                discardUnsaved();
                return;
            case "show-all":
                state.showChangedOnly = false;
                state.showLockedOnly = false;
                applyFilters();
                showToast("Showing all matching settings");
                return;
            case "show-changed":
                state.showChangedOnly = !state.showChangedOnly;
                if (state.showChangedOnly) state.showLockedOnly = false;
                applyFilters();
                showToast(state.showChangedOnly ? "Showing changed settings only" : "Showing all matching settings");
                return;
            case "show-locked":
                state.showLockedOnly = !state.showLockedOnly;
                if (state.showLockedOnly) state.showChangedOnly = false;
                applyFilters();
                showToast(state.showLockedOnly ? "Showing locked settings only" : "Showing all matching settings");
                return;
            case "reset-defaults":
                await resetDefaults();
                return;
            case "reload":
                window.location.reload();
                return;
            case "legend":
                explainSources();
                return;
            case "reset-help":
                explainReset();
                return;
            default:
                showToast(`Unknown command: ${command}`, "warning");
        }
    }

    rows.forEach((row) => {
        row.input?.addEventListener(row.input.tagName === "SELECT" ? "change" : "input", updateView);
        row.element.querySelector(".row-reset")?.addEventListener("click", () => resetSingleSetting(row));
        row.element.querySelector(".row-info")?.addEventListener("click", () => showRowInfo(row));
    });

    searchInput.addEventListener("input", applyFilters);
    categoryButtons.forEach((button) => button.addEventListener("click", () => setCategory(button.dataset.category)));
    saveButton.addEventListener("click", saveChanges);
    exportButton.addEventListener("click", exportSettings);
    importButton.addEventListener("click", () => importInput.click());
    resetButton.addEventListener("click", resetDefaults);
    importInput.addEventListener("change", (event) => importSettingsFile(event.target.files?.[0]));
    popupClose?.addEventListener("click", () => window.WarpBoxUI?.closePopup?.());
    document.getElementById("modal-backdrop")?.addEventListener("click", () => window.WarpBoxUI?.closePopup?.());

    document.querySelectorAll("[data-command]").forEach((button) => {
        button.addEventListener("click", async () => {
            menuController.close();
            await runCommand(button.dataset.command);
        });
    });

    document.addEventListener("keydown", async (event) => {
        if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "s") {
            event.preventDefault();
            await saveChanges();
        }
        if (event.key === "F5") {
            event.preventDefault();
            window.location.reload();
        }
        if (event.key === "Escape") {
            menuController.close();
            window.WarpBoxUI?.closePopup?.();
        }
    });

    updateView();
})();
