// Server settings: read/write a curated subset of server.properties.
// Changes require an MC restart -- Save writes only, Save & restart bounces MC.
"use strict";

import { api } from "./api.js";

const els = {};

// Map of input element ID -> server.properties key. Keeps the form ↔ file
// translation in one place; new fields can be added by adding a row here +
// matching elements in index.html.
const FIELDS = [
    { id: "ssfMotd",                 key: "motd",                  type: "string"  },
    { id: "ssfGamemode",             key: "gamemode",              type: "string"  },
    { id: "ssfDifficulty",           key: "difficulty",            type: "string"  },
    { id: "ssfViewDistance",         key: "view-distance",         type: "int"     },
    { id: "ssfSimulationDistance",   key: "simulation-distance",   type: "int"     },
    { id: "ssfMaxPlayers",           key: "max-players",           type: "int"     },
    { id: "ssfSpawnProtection",      key: "spawn-protection",      type: "int"     },
    { id: "ssfPvp",                  key: "pvp",                   type: "bool"    },
    { id: "ssfHardcore",             key: "hardcore",              type: "bool"    },
    { id: "ssfAllowFlight",          key: "allow-flight",          type: "bool"    },
    { id: "ssfWhiteList",            key: "white-list",            type: "bool"    },
    { id: "ssfEnforceWhitelist",     key: "enforce-whitelist",     type: "bool"    },
    { id: "ssfEnableCommandBlock",   key: "enable-command-block",  type: "bool"    },
];

// Fields that live in server-config.json (the daemon's own config), not
// server.properties. Endpoint is /api/daemon/config, payload is JSON-typed
// (not stringified like server.properties).
const DAEMON_FIELDS = [
    { id: "ssfMemoryMB",             key: "memoryMB",              type: "int"     },
];

function readForm() {
    const out = {};
    for (const f of FIELDS) {
        const el = document.getElementById(f.id);
        if (!el) continue;
        if (f.type === "bool") out[f.key] = el.checked ? "true" : "false";
        else if (f.type === "int") {
            const v = parseInt(el.value, 10);
            if (Number.isFinite(v)) out[f.key] = String(v);
        } else {
            out[f.key] = el.value;
        }
    }
    return out;
}

function writeForm(values) {
    for (const f of FIELDS) {
        const el = document.getElementById(f.id);
        if (!el) continue;
        const v = values[f.key];
        if (v === undefined) continue;
        if (f.type === "bool") el.checked = (v === "true");
        else el.value = v;
    }
}

function renderSummary(values) {
    document.getElementById("ssMotd").textContent       = values["motd"]       ?? "--";
    document.getElementById("ssDifficulty").textContent = values["difficulty"] ?? "--";
    document.getElementById("ssDistances").textContent  =
        `${values["view-distance"] ?? "--"} / ${values["simulation-distance"] ?? "--"}`;
    document.getElementById("ssMaxPlayers").textContent = values["max-players"] ?? "--";
    const wl = values["white-list"] === "true";
    const enf = values["enforce-whitelist"] === "true";
    document.getElementById("ssWhitelist").textContent =
        wl ? (enf ? "enforced" : "enabled") : "off";
}

function readDaemonForm() {
    const out = {};
    for (const f of DAEMON_FIELDS) {
        const el = document.getElementById(f.id);
        if (!el) continue;
        if (f.type === "int") {
            const v = parseInt(el.value, 10);
            if (Number.isFinite(v)) out[f.key] = v;
        } else {
            out[f.key] = el.value;
        }
    }
    return out;
}

function writeDaemonForm(values) {
    for (const f of DAEMON_FIELDS) {
        const el = document.getElementById(f.id);
        if (!el) continue;
        const v = values[f.key];
        if (v === undefined) continue;
        el.value = String(v);
    }
}

async function refresh() {
    try {
        const data = await api("/api/server/settings");
        renderSummary(data.values || {});
        writeForm(data.values || {});
    } catch { /* ignore -- panel just shows last-known */ }
    try {
        const daemon = await api("/api/daemon/config");
        writeDaemonForm(daemon || {});
    } catch { /* ignore */ }
}

async function postSettings() {
    // Two endpoints, two payloads. We always POST both -- backend short-circuits
    // when nothing changed, and combining them in one round-trip would mean
    // either endpoint failing leaves the other in an inconsistent state.
    const propsPayload  = readForm();
    const daemonPayload = readDaemonForm();

    const propsRes = await fetch("/api/server/settings", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(propsPayload),
    });
    const propsBody = await propsRes.json().catch(() => ({}));

    const daemonRes = await fetch("/api/daemon/config", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(daemonPayload),
    });
    const daemonBody = await daemonRes.json().catch(() => ({}));

    const ok = propsRes.ok && daemonRes.ok && propsBody.ok !== false && daemonBody.ok !== false;
    const error = propsBody.error || daemonBody.error || null;
    const restartRequired = (propsBody.restartRequired || daemonBody.restartRequired) ?? false;
    return { ok, body: { ok, error, restartRequired } };
}

function showMsg(text, ok = false) {
    els.msg.className = ok ? "acct-msg ok" : "acct-msg";
    els.msg.textContent = text;
}

export function setupSettings() {
    els.msg     = document.getElementById("ssMsg");
    els.save    = document.getElementById("ssSave");
    els.restart = document.getElementById("ssRestart");
    if (!els.save) return;

    els.save.addEventListener("click", async () => {
        showMsg("Saving...");
        els.save.disabled = true;
        try {
            const r = await postSettings();
            if (!r.ok || r.body.ok === false) {
                showMsg(r.body.error || `Error ${r.body.status ?? ""}`);
                return;
            }
            showMsg(r.body.restartRequired
                ? "Saved. Restart for changes to take effect."
                : "Saved.", true);
            refresh();
        } catch (e) { showMsg(e.message); }
        finally { els.save.disabled = false; }
    });

    els.restart.addEventListener("click", async () => {
        if (!confirm("Save changes and restart the server now? Players will be disconnected briefly.")) return;
        showMsg("Saving + restarting...");
        els.save.disabled = true; els.restart.disabled = true;
        try {
            const r = await postSettings();
            if (!r.ok || r.body.ok === false) {
                showMsg(r.body.error || `Save failed: ${r.body.status ?? ""}`);
                return;
            }
            const rr = await fetch("/api/server/restart", { method: "POST" });
            const rb = await rr.json().catch(() => ({}));
            if (!rr.ok || rb.ok === false) showMsg("Saved, but restart failed: " + (rb.error || rr.status));
            else showMsg("Saved + restarting. New settings live in ~30s.", true);
            refresh();
        } catch (e) { showMsg(e.message); }
        finally { els.save.disabled = false; els.restart.disabled = false; }
    });

    refresh();
    // Light poll: pick up out-of-band edits to server.properties.
    setInterval(refresh, 30000);
}
