// Status / players / whitelist sidebar panels. Polled (not streamed) because the
// data they show changes infrequently. Logs use SSE -- see console.js.
"use strict";

import { api, escapeHtml } from "./api.js";
import { state, rebuildKnownPlayers } from "./state.js";

export async function tickStatus() {
    const pill = document.getElementById("statusPill");
    const text = document.getElementById("statusText");
    const memEl = document.getElementById("memUsage");
    const memBar = document.getElementById("memBar");
    const cpuCur = document.getElementById("cpuCurrent");
    const cpuBar = document.getElementById("cpuBar");
    const cpuMax = document.getElementById("cpuMax");
    const cpuAvg = document.getElementById("cpuAvg");

    function renderResources(s) {
        if (s.memoryBytes != null) {
            const usedGB = s.memoryBytes / (1024 ** 3);
            const maxGB = s.memoryMaxMB ? s.memoryMaxMB / 1024 : null;
            memEl.textContent = maxGB
                ? `${usedGB.toFixed(2)} / ${maxGB.toFixed(1)} GB`
                : `${usedGB.toFixed(2)} GB`;
            memBar.style.width = maxGB ? `${Math.min(100, (usedGB / maxGB) * 100)}%` : "0%";
        } else {
            memEl.textContent = "--";
            memBar.style.width = "0%";
        }
        if (s.cpu) {
            cpuCur.textContent = `${s.cpu.current.toFixed(1)} %`;
            cpuBar.style.width = `${Math.min(100, s.cpu.current)}%`;
            cpuMax.textContent = `${s.cpu.max.toFixed(1)}%`;
            cpuAvg.textContent = `${s.cpu.avg.toFixed(1)}%`;
        } else {
            cpuCur.textContent = "--";
            cpuBar.style.width = "0%";
            cpuMax.textContent = "--";
            cpuAvg.textContent = "--";
        }
    }

    try {
        const s = await api("/api/status");
        if (s.running) {
            pill.className = "status-pill online";
            text.textContent = "Online";
            document.getElementById("pid").textContent = s.pid ?? "--";
            const secs = Math.floor(s.uptime ?? 0);
            const h = Math.floor(secs / 3600), m = Math.floor((secs % 3600) / 60);
            document.getElementById("uptime").textContent = `${h}h ${m}m`;
            renderResources(s);
        } else {
            pill.className = "status-pill offline";
            text.textContent = "Offline";
            document.getElementById("pid").textContent = "--";
            document.getElementById("uptime").textContent = "--";
            renderResources({ memoryBytes: null, cpu: null, memoryMaxMB: null });
        }
        const pv = s.packVersion;
        document.getElementById("packVersion").textContent = pv?.name ? `${pv.name} v${pv.version}` : "--";

        // World size -- even when server is offline we can still report disk usage.
        const worldEl = document.getElementById("worldSize");
        if (worldEl) {
            const b = s.worldSizeBytes;
            if (b == null || b === 0) worldEl.textContent = "--";
            else if (b < 1024 * 1024)              worldEl.textContent = `${(b / 1024).toFixed(0)} KB`;
            else if (b < 1024 * 1024 * 1024)       worldEl.textContent = `${(b / (1024 * 1024)).toFixed(1)} MB`;
            else                                    worldEl.textContent = `${(b / (1024 * 1024 * 1024)).toFixed(2)} GB`;
        }
    } catch {
        pill.className = "status-pill offline";
        text.textContent = "Disconnected";
    }
}

export async function tickPlayers() {
    try {
        const p = await api("/api/players");
        state.onlinePlayers = (p.players || []).slice();
        document.getElementById("playerCount").textContent = p.online >= 0 ? p.online : "?";
        const list = document.getElementById("players");
        if (state.onlinePlayers.length === 0) {
            list.innerHTML = '<li class="empty-state">No-one online</li>';
        } else {
            list.innerHTML = state.onlinePlayers.map(n => `<li>${escapeHtml(n)}<span></span></li>`).join("");
        }
    } catch {}
    rebuildKnownPlayers();
}

export async function tickWhitelist() {
    try {
        const w = await api("/api/whitelist");
        state.whitelistedPlayers = (w.players || []).slice();
        const list = document.getElementById("whitelist");
        if (state.whitelistedPlayers.length === 0) {
            list.innerHTML = '<li class="empty-state">No players whitelisted yet</li>';
        } else {
            list.innerHTML = state.whitelistedPlayers.map(n =>
                `<li>${escapeHtml(n)}<button data-name="${escapeHtml(n)}" class="wl-remove">Remove</button></li>`
            ).join("");
        }
    } catch {}
    rebuildKnownPlayers();
}

// MC takes ~1-2 s to look up a UUID via Mojang and write whitelist.json.
// Refresh shortly after a user-triggered add/remove instead of waiting for the
// 30-second polling tick.
let pendingRefresh;
export function refreshWhitelistSoon() {
    clearTimeout(pendingRefresh);
    pendingRefresh = setTimeout(tickWhitelist, 1500);
    setTimeout(tickWhitelist, 4000); // belt-and-braces if Mojang is slow
}
