(() => {
    const menuController = window.WarpBoxUI?.bindMenuBar?.() || { close() {} };
    const eventsNode = document.getElementById("security-events-data");
    const alertsNode = document.getElementById("security-alerts-data");
    const bansNode = document.getElementById("security-bans-data");
    const ipInput = document.getElementById("security-ip-input");
    const banUntilInput = document.getElementById("security-ban-until");
    const alertList = document.getElementById("security-alert-list");
    const activityBody = document.getElementById("security-activity-body");
    const bansBody = document.getElementById("security-bans-body");
    const bansCount = document.getElementById("security-bans-count");
    const filterInput = document.getElementById("security-ban-filter");
    const sortSelect = document.getElementById("security-ban-sort");
    const selectAll = document.getElementById("security-select-all");
    const copyIPButton = document.getElementById("security-copy-ip");
    const openActivityButton = document.getElementById("security-open-activity");
    const openAlertsButton = document.getElementById("security-open-alerts");
    const toast = document.getElementById("toast");

    const detail = {
        ip: document.getElementById("security-detail-ip"),
        risk: document.getElementById("security-detail-risk"),
        threat: document.getElementById("security-detail-threat"),
        geo: document.getElementById("security-detail-geo"),
        asn: document.getElementById("security-detail-asn"),
        until: document.getElementById("security-detail-until"),
        why: document.getElementById("security-detail-why")
    };

    if (!eventsNode || !alertsNode || !bansNode) return;
    const state = {
        events: parse(eventsNode),
        alerts: parse(alertsNode),
        bans: parse(bansNode),
        selectedIP: "",
        selectedIPs: new Set()
    };

    setDefaultBanUntil();

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

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

    function createdLabel(value) {
        const parsed = new Date(value);
        if (Number.isNaN(parsed.getTime())) return "-";
        return parsed.toISOString().replace("T", " ").slice(0, 16) + " UTC";
    }

    function setDefaultBanUntil() {
        const base = new Date(Date.now() + 30 * 60 * 1000);
        const yyyy = String(base.getUTCFullYear());
        const mm = String(base.getUTCMonth() + 1).padStart(2, "0");
        const dd = String(base.getUTCDate()).padStart(2, "0");
        const hh = String(base.getUTCHours()).padStart(2, "0");
        const mi = String(base.getUTCMinutes()).padStart(2, "0");
        banUntilInput.value = `${yyyy}-${mm}-${dd}T${hh}:${mi}`;
    }

    function toRFC3339FromLocalUTC(datetimeLocalValue) {
        if (!datetimeLocalValue) return "";
        const date = new Date(datetimeLocalValue + ":00Z");
        if (Number.isNaN(date.getTime())) return "";
        return date.toISOString();
    }

    function setSelectedIP(ip) {
        state.selectedIP = ip || "";
        if (state.selectedIP) ipInput.value = state.selectedIP;
        renderBans();
        renderIPDetails();
    }

    function render() {
        renderAlerts();
        renderActivity();
        renderBans();
        renderIPDetails();
    }

    function renderAlerts() {
        alertList.innerHTML = "";
        state.alerts.slice(0, 12).forEach((alert) => {
            const entry = document.createElement("li");
            entry.textContent = `${createdLabel(alert.created_at)} | ${alert.severity || "low"} | ${alert.title || "-"}`;
            alertList.appendChild(entry);
        });
    }

    function renderActivity() {
        activityBody.innerHTML = "";
        state.events
            .filter((event) => String(event.kind || "").startsWith("security") || String(event.kind || "").startsWith("auth.admin"))
            .slice(0, 60)
            .forEach((event) => {
                const row = document.createElement("tr");
                row.innerHTML = `
                    <td>${createdLabel(event.created_at)}</td>
                    <td>${escapeHtml(event.kind || "-")}</td>
                    <td>${escapeHtml(event.severity || "-")}</td>
                    <td>${escapeHtml(event.ip || "-")}</td>
                    <td>${escapeHtml(event.path || "-")}</td>
                    <td title="${escapeHtml(event.message || "-")}">${escapeHtml(event.message || "-")}</td>
                `;
                activityBody.appendChild(row);
            });
    }

    function rowData() {
        const banMap = new Map(state.bans.map((entry) => [entry.ip, entry]));
        const filter = String(filterInput?.value || "").trim().toLowerCase();
        let rows = state.bans.map((entry) => ({ ip: entry.ip, status: "banned", until: entry.until, ban: entry }));
        if (filter) rows = rows.filter((row) => row.ip.toLowerCase().includes(filter));
        const sort = sortSelect?.value || "expiry_asc";
        rows.sort((a, b) => {
            if (sort === "ip_asc") return a.ip.localeCompare(b.ip);
            if (sort === "ip_desc") return b.ip.localeCompare(a.ip);
            const av = new Date(a.until).getTime();
            const bv = new Date(b.until).getTime();
            return sort === "expiry_desc" ? bv - av : av - bv;
        });
        return { rows, banMap };
    }

    function renderBans() {
        bansBody.innerHTML = "";
        const { rows } = rowData();
        rows.forEach((rowData) => {
            const row = document.createElement("tr");
            row.className = "security-bans-body-row";
            if (rowData.ip === state.selectedIP) row.classList.add("is-selected");
            row.innerHTML = `
                <td><input type="checkbox" class="security-row-select" data-ip="${escapeHtml(rowData.ip)}" ${state.selectedIPs.has(rowData.ip) ? "checked" : ""}></td>
                <td>${escapeHtml(rowData.ip || "-")}</td>
                <td>${rowData.status}</td>
                <td>${createdLabel(rowData.until)}</td>
            `;
            row.addEventListener("click", (event) => {
                if (event.target && event.target.classList.contains("security-row-select")) return;
                setSelectedIP(rowData.ip);
            });
            bansBody.appendChild(row);
        });
        bansBody.querySelectorAll(".security-row-select").forEach((checkbox) => {
            checkbox.addEventListener("change", () => {
                const ip = checkbox.getAttribute("data-ip");
                if (!ip) return;
                if (checkbox.checked) state.selectedIPs.add(ip); else state.selectedIPs.delete(ip);
            });
        });
        bansCount.textContent = `${state.bans.length} active bans`;
    }

    function renderIPDetails() {
        const ip = state.selectedIP || String(ipInput.value || "").trim();
        if (!ip) {
            detail.ip.textContent = "No IP selected";
            detail.risk.textContent = "-";
            detail.threat.textContent = "-";
            detail.geo.textContent = "GeoIP not enabled yet";
            detail.asn.textContent = "GeoIP not enabled yet";
            detail.until.textContent = "-";
            detail.why.textContent = "-";
            return;
        }
        const ban = state.bans.find((entry) => entry.ip === ip);
        const matchingEvents = state.events.filter((event) => String(event.ip || "") === ip);
        const matchingAlerts = state.alerts.filter((alert) => String(alert?.meta?.ip || "") === ip);
        const lastEvent = matchingEvents[0] || null;
        detail.ip.textContent = ip;
        detail.risk.textContent = ban ? "high" : "medium";
        detail.threat.textContent = ban ? "Temporary banned source" : "Observed source";
        detail.geo.textContent = "GeoIP not enabled yet";
        detail.asn.textContent = "GeoIP not enabled yet";
        detail.until.textContent = ban ? createdLabel(ban.until) : "Not banned";
        detail.why.textContent = `${matchingEvents.length} events, ${matchingAlerts.length} alerts${lastEvent ? `, latest=${lastEvent.kind}` : ""}`;
        if (ban && ban.until) {
            const parsed = new Date(ban.until);
            if (!Number.isNaN(parsed.getTime())) {
                const yyyy = String(parsed.getUTCFullYear());
                const mm = String(parsed.getUTCMonth() + 1).padStart(2, "0");
                const dd = String(parsed.getUTCDate()).padStart(2, "0");
                const hh = String(parsed.getUTCHours()).padStart(2, "0");
                const mi = String(parsed.getUTCMinutes()).padStart(2, "0");
                banUntilInput.value = `${yyyy}-${mm}-${dd}T${hh}:${mi}`;
            }
        }
    }

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

    async function postAction(action, payload = {}) {
        const response = await fetch("/admin/security/actions", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ action, ...payload })
        });
        const result = await response.json().catch(() => ({}));
        if (!response.ok) throw new Error(result.error || "Request failed");
        if (Array.isArray(result.bans)) state.bans = result.bans;
        return result;
    }

    async function banIP() {
        const ip = String(ipInput.value || "").trim();
        if (!ip) return showToast("Enter IP first", "warning");
        const payload = await postAction("ban", { ip });
        setSelectedIP(ip);
        showToast(payload.message || "IP banned", "success");
    }

    async function banUntil() {
        const ip = String(ipInput.value || "").trim();
        if (!ip) return showToast("Enter IP first", "warning");
        const banUntil = toRFC3339FromLocalUTC(banUntilInput.value);
        if (!banUntil) return showToast("Set valid expiration date", "warning");
        if (!window.confirm("Apply custom ban expiration?")) return;
        const payload = await postAction("ban_until", { ip, ban_until: banUntil });
        setSelectedIP(ip);
        showToast(payload.message || "IP ban expiration updated", "success");
    }

    async function unbanIP() {
        const ip = state.selectedIP || String(ipInput.value || "").trim();
        if (!ip) return showToast("Select or enter IP first", "warning");
        if (!window.confirm(`Unban ${ip}?`)) return;
        const payload = await postAction("unban", { ip });
        state.selectedIPs.delete(ip);
        setSelectedIP("");
        showToast(payload.message || "IP unbanned", "success");
    }

    async function bulkUnban() {
        const ips = Array.from(state.selectedIPs);
        if (ips.length === 0) return showToast("Select at least one banned IP", "warning");
        if (!window.confirm(`Unban ${ips.length} selected IPs?`)) return;
        const payload = await postAction("bulk_unban", { ips });
        state.selectedIPs.clear();
        setSelectedIP("");
        showToast(payload.message || "Bulk unban complete", "success");
    }

    async function unbanAll() {
        if (!window.confirm("Unban all active bans?")) return;
        const payload = await postAction("unban_all");
        state.selectedIPs.clear();
        setSelectedIP("");
        showToast(payload.message || "All bans cleared", "success");
    }

    document.querySelectorAll("[data-command]").forEach((button) => {
        button.addEventListener("click", async () => {
            menuController.close();
            try {
                const command = button.dataset.command;
                if (command === "refresh") return window.location.reload();
                if (command === "ban-ip") return await banIP();
                if (command === "ban-until") return await banUntil();
                if (command === "unban-ip") return await unbanIP();
                if (command === "bulk-unban") return await bulkUnban();
                if (command === "unban-all") return await unbanAll();
            } catch (error) {
                showToast(error.message, "error", 3200);
            } finally {
                renderBans();
                renderIPDetails();
            }
        });
    });

    ipInput.addEventListener("input", () => renderIPDetails());
    filterInput?.addEventListener("input", () => renderBans());
    sortSelect?.addEventListener("change", () => renderBans());
    selectAll?.addEventListener("change", () => {
        if (selectAll.checked) state.bans.forEach((ban) => state.selectedIPs.add(ban.ip));
        else state.selectedIPs.clear();
        renderBans();
    });

    copyIPButton?.addEventListener("click", async () => {
        const ip = state.selectedIP || String(ipInput.value || "").trim();
        if (!ip) return showToast("No IP selected", "warning");
        await navigator.clipboard.writeText(ip);
        showToast("IP copied", "success");
    });
    openActivityButton?.addEventListener("click", () => {
        const ip = state.selectedIP || String(ipInput.value || "").trim();
        if (!ip) return showToast("No IP selected", "warning");
        window.location.href = `/admin/activity?q=${encodeURIComponent(ip)}`;
    });
    openAlertsButton?.addEventListener("click", () => {
        const ip = state.selectedIP || String(ipInput.value || "").trim();
        if (!ip) return showToast("No IP selected", "warning");
        window.location.href = `/admin/alerts?q=${encodeURIComponent(ip)}`;
    });

    document.addEventListener("keydown", (event) => {
        if (event.key === "Escape") menuController.close();
        if (event.key === "F5") {
            event.preventDefault();
            window.location.reload();
        }
    });

    if (state.bans.length > 0) setSelectedIP(state.bans[0].ip);
    render();
})();
