(function () {
    "use strict";

    var _ = cockpit.gettext;

    var HELPER = "/usr/sbin/edubuntu-installer-helper";
    var QUERY  = "/usr/share/cockpit/edubuntu-installer/query.py";

    var state = null;
    var initialPkgs = [];       // initial installed package names
    var initialGlobalRadio = ""; // initial global default choice
    var initialUserRadios = {};  // username -> initial choice
    var checkboxMap = {};       // package name -> array of checkbox inputs

    function formatRelationText(relation, packageName) {
        return _("{relation} of {package}")
            .replace("{relation}", relation)
            .replace("{package}", packageName);
    }

    function registerCheckbox(packageName, cb) {
        if (!checkboxMap[packageName])
            checkboxMap[packageName] = [];
        checkboxMap[packageName].push(cb);
    }

    function syncCheckboxGroup(packageName, checked, source) {
        (checkboxMap[packageName] || []).forEach(function (cb) {
            if (cb !== source)
                cb.checked = checked;
        });
    }

    function allCheckedPackages() {
        var result = [];
        var seen = {};
        document.querySelectorAll("#pkg-list input[type=checkbox][data-pkg]").forEach(function (cb) {
            if (!cb.checked)
                return;
            if (seen[cb.dataset.pkg])
                return;
            seen[cb.dataset.pkg] = true;
            result.push(cb.dataset.pkg);
        });
        return result;
    }

    /* ── Tab switching ─────────────────────────────────────────── */

    var tabLinks = document.querySelectorAll(".nav-tabs a[data-toggle=tab]");
    tabLinks.forEach(function (a) {
        a.addEventListener("click", function (ev) {
            ev.preventDefault();
            tabLinks.forEach(function (l) {
                l.parentElement.classList.remove("active");
            });
            document.querySelectorAll(".tab-pane").forEach(function (p) {
                p.classList.remove("active");
            });
            a.parentElement.classList.add("active");
            var target = a.getAttribute("href").substring(1);
            document.getElementById(target).classList.add("active");
        });
    });

    /* ── Toggle log ────────────────────────────────────────────── */

    var toggleLink = document.getElementById("toggle-log");
    var outputLog  = document.getElementById("output-log");
    toggleLink.addEventListener("click", function (ev) {
        ev.preventDefault();
        if (outputLog.style.display === "none") {
            outputLog.style.display = "";
            toggleLink.textContent = _("Hide details ▴");
        } else {
            outputLog.style.display = "none";
            toggleLink.textContent = _("Show details ▾");
        }
    });

    /* ── Rendering ─────────────────────────────────────────────── */

    function renderPackages() {
        var container = document.getElementById("pkg-list");
        container.innerHTML = "";
        checkboxMap = {};
        state.packages.forEach(function (pkg) {
            var details = document.createElement("details");
            details.className = "pkg-entry";

            var summary = document.createElement("summary");
            summary.className = "pkg-summary";

            var cb  = document.createElement("input");
            cb.type = "checkbox";
            cb.dataset.pkg = pkg.name;
            cb.checked = pkg.installed;
            registerCheckbox(pkg.name, cb);

            var summaryText = document.createElement("span");
            summaryText.className = "pkg-summary-text";
            var text = " " + pkg.name;
            if (pkg.description)
                text += "  \u2014  " + pkg.description;
            summaryText.appendChild(document.createTextNode(text));

            summary.appendChild(cb);
            summary.appendChild(summaryText);
            details.appendChild(summary);

            var childBox = document.createElement("div");
            childBox.className = "pkg-children";
            var dependsChildren = [];

            (pkg.children || []).forEach(function (child) {
                var childLabel = document.createElement("label");
                childLabel.className = "pkg-child";

                var childCb = document.createElement("input");
                childCb.type = "checkbox";
                childCb.dataset.pkg = child.package;
                childCb.dataset.relation = child.relation;
                childCb.checked = child.installed;
                registerCheckbox(child.package, childCb);

                if (child.relation === "Depends")
                    dependsChildren.push(childCb);

                childCb.addEventListener("change", function () {
                    syncCheckboxGroup(child.package, childCb.checked, childCb);
                    if (child.relation === "Depends" && !childCb.checked)
                        cb.checked = false;
                    checkChanges();
                });

                childLabel.appendChild(childCb);
                childLabel.appendChild(document.createTextNode(
                    " " + formatRelationText(child.relation, child.package)
                ));
                childBox.appendChild(childLabel);
            });

            cb.addEventListener("change", function () {
                syncCheckboxGroup(pkg.name, cb.checked, cb);
                if (cb.checked) {
                    dependsChildren.forEach(function (depCb) {
                        depCb.checked = true;
                        syncCheckboxGroup(depCb.dataset.pkg, true, depCb);
                    });
                }
                checkChanges();
            });

            if (pkg.children && pkg.children.length)
                details.appendChild(childBox);

            container.appendChild(details);
        });
    }

    function renderRadioGroup(containerId, name, choices, selected) {
        var container = document.getElementById(containerId);
        container.innerHTML = "";
        container.classList.add("radio-group");
        choices.forEach(function (choice) {
            var lbl = document.createElement("label");
            var rb  = document.createElement("input");
            rb.type = "radio";
            rb.name = name;
            rb.value = choice;
            rb.checked = (choice === selected);
            rb.addEventListener("change", checkChanges);
            lbl.appendChild(rb);
            lbl.appendChild(document.createTextNode(" " + choice));
            container.appendChild(lbl);
        });
    }

    function renderGlobalSetup() {
        renderRadioGroup("global-radios", "global-default",
                         state.setup_choices, state.global_default);
    }

    function currentUserDefault() {
        var sel = document.getElementById("user-select");
        var uname = sel.value;
        if (!uname) return "";
        var u = state.users.find(function (u) { return u.username === uname; });
        return u ? u.age_group : state.setup_choices[state.setup_choices.length - 1];
    }

    function renderPerUserSetup() {
        var sel = document.getElementById("user-select");
        if (!sel.value) {
            document.getElementById("user-radios").innerHTML =
                "<p class='text-muted'>" + _("No non-administrator users found.") + "</p>";
            return;
        }
        renderRadioGroup("user-radios", "user-default",
                         state.setup_choices, currentUserDefault());
    }

    function populateUsers() {
        var sel = document.getElementById("user-select");
        sel.innerHTML = "";
        if (state.users.length === 0) {
            renderPerUserSetup();
            return;
        }
        state.users.forEach(function (u) {
            var opt = document.createElement("option");
            opt.value = u.username;
            opt.textContent = u.username;
            sel.appendChild(opt);
        });
        sel.addEventListener("change", function () {
            renderPerUserSetup();
            checkChanges();
        });
    }

    /* ── Data loading ──────────────────────────────────────────── */

    function loadState() {
        document.getElementById("loading").style.display = "";
        document.getElementById("content").style.display = "none";
        document.getElementById("error-bar").style.display = "none";
        document.getElementById("progress-panel").style.display = "none";

        cockpit.spawn(["python3", QUERY], { superuser: "try", err: "message" })
            .then(function (data) {
                state = JSON.parse(data);
                renderPackages();
                renderGlobalSetup();
                populateUsers();
                renderPerUserSetup();
                // Capture initial state
                initialPkgs = checkedPkgValues();
                initialGlobalRadio = state.global_default;
                state.users.forEach(function (u) {
                    initialUserRadios[u.username] = u.age_group;
                });
                document.getElementById("btn-apply").disabled = true;
                document.getElementById("loading").style.display = "none";
                document.getElementById("content").style.display = "";
            })
            .catch(function (err) {
                showError(_("Failed to load state: ") + err.message);
            });
    }

    /* ── Helpers ───────────────────────────────────────────────── */

    function selectedRadio(name) {
        var rb = document.querySelector("input[name='" + name + "']:checked");
        return rb ? rb.value : "";
    }

    function checkedPkgValues() {
        return allCheckedPackages();
    }

    function arraysEqual(a, b) {
        if (a.length !== b.length) return false;
        var sa = a.slice().sort();
        var sb = b.slice().sort();
        for (var i = 0; i < sa.length; i++) {
            if (sa[i] !== sb[i]) return false;
        }
        return true;
    }

    function checkChanges() {
        var btn = document.getElementById("btn-apply");
        // Check packages
        if (!arraysEqual(checkedPkgValues(), initialPkgs)) {
            btn.disabled = false;
            return;
        }
        // Check global radio
        if (selectedRadio("global-default") !== initialGlobalRadio) {
            btn.disabled = false;
            return;
        }
        // Check per-user radio
        var sel = document.getElementById("user-select");
        if (sel.value && initialUserRadios[sel.value] !== undefined) {
            if (selectedRadio("user-default") !== initialUserRadios[sel.value]) {
                btn.disabled = false;
                return;
            }
        }
        btn.disabled = true;
    }

    function showError(msg) {
        document.getElementById("loading").style.display = "none";
        document.getElementById("error-text").textContent = msg;
        document.getElementById("error-bar").style.display = "";
    }

    function setProgress(show) {
        document.getElementById("progress-panel").style.display =
            show ? "" : "none";
        if (show) {
            outputLog.textContent = "";
            outputLog.style.display = "none";
            toggleLink.textContent = _("Show details ▾");
        }
    }

    function appendLog(text) {
        outputLog.textContent += text;
        outputLog.scrollTop = outputLog.scrollHeight;
    }

    function runStream(cmd, label) {
        setProgress(true);
        return new Promise(function (resolve, reject) {
            var proc = cockpit.spawn(cmd, {
                superuser: "require",
                err: "message",
            });
            proc.stream(function (data) { appendLog(data); });
            proc.then(function () {
                resolve(true);
            }).catch(function (err) {
                appendLog("\nError: " + err.message + "\n");
                reject(err);
            });
        });
    }

    /* ── Apply ─────────────────────────────────────────────────── */

    function applyChanges() {
        var btn = document.getElementById("btn-apply");
        btn.disabled = true;
        document.getElementById("status-msg").textContent = "";

        var chain = Promise.resolve();

        // Determine package changes
        var toInstall = [];
        var toRemove  = [];
        var installed = {};
        state.packages.forEach(function (pkg) {
            if (pkg.installed)
                installed[pkg.name] = true;
            (pkg.children || []).forEach(function (child) {
                if (child.installed)
                    installed[child.package] = true;
            });
        });

        var selected = {};
        document.querySelectorAll("#pkg-list input[type=checkbox][data-pkg]").forEach(function (cb) {
            if (cb.checked)
                selected[cb.dataset.pkg] = true;
        });

        Object.keys(selected).forEach(function (name) {
            if (!installed[name])
                toInstall.push(name);
        });
        Object.keys(installed).forEach(function (name) {
            if (!selected[name])
                toRemove.push(name);
        });

        // apt-get update if package changes pending
        if (toInstall.length || toRemove.length) {
            chain = chain.then(function () {
                return runStream([HELPER, "update"], _("Updating package cache…"));
            });
        }

        // install
        if (toInstall.length) {
            chain = chain.then(function () {
                return runStream(
                    [HELPER, "install"].concat(toInstall),
                    _("Installing packages…")
                );
            });
        }

        // remove
        if (toRemove.length) {
            chain = chain.then(function () {
                return runStream(
                    [HELPER, "autoremove"].concat(toRemove),
                    _("Removing packages…")
                );
            });
        }

        // global default
        var newGlobal = selectedRadio("global-default");
        if (newGlobal && newGlobal !== state.global_default) {
            chain = chain.then(function () {
                if (newGlobal === state.setup_choices[state.setup_choices.length - 1]) {
                    return cockpit.spawn([HELPER, "tertdefault"],
                        { superuser: "require", err: "message" });
                }
                // Look up the gschema override content by querying the
                // helper inline — the helper accepts content as arg.
                // We replicate the mapping here for the Cockpit module.
                return cockpit.spawn(
                    ["python3", "/usr/share/cockpit/edubuntu-installer/apply-default.py",
                     newGlobal],
                    { superuser: "require", err: "message" }
                );
            });
        }

        // per-user default
        var sel = document.getElementById("user-select");
        var username = sel.value;
        if (username) {
            var newUser = selectedRadio("user-default");
            var curUser = currentUserDefault();
            if (newUser && newUser !== curUser) {
                chain = chain.then(function () {
                    if (newUser === state.setup_choices[state.setup_choices.length - 1]) {
                        return cockpit.spawn(
                            [HELPER, "usertertdefault", username],
                            { superuser: "require", err: "message" }
                        );
                    }
                    return cockpit.spawn(
                        ["python3",
                         "/usr/share/cockpit/edubuntu-installer/apply-default.py",
                         "--user", username, newUser],
                        { superuser: "require", err: "message" }
                    );
                });
            }
        }

        chain
            .then(function () {
                setProgress(false);
                document.getElementById("status-msg").textContent = _("Changes applied.");
                btn.disabled = false;
                loadState();
            })
            .catch(function (err) {
                showError(_("Apply failed: ") + err.message);
                btn.disabled = false;
            });
    }

    /* ── Wire buttons ──────────────────────────────────────────── */

    document.getElementById("btn-apply").addEventListener("click", applyChanges);
    document.getElementById("btn-reload").addEventListener("click", function () {
        document.getElementById("status-msg").textContent = "";
        loadState();
    });

    /* ── Bootstrap ─────────────────────────────────────────────── */

    loadState();
})();
