import React, { useEffect, useMemo, useRef, useState } from "react";
import { Formik } from "formik";
import * as Yup from "yup";
import type { NinjaSageLoginUser, NinjaSageLoginUserListParams } from "../api";
import {
    createLoginUser,
    deleteLoginUser,
    fetchLoginUsersRev,
    fetchAmfUploads,
    importSampleLoginUser,
    importLoginUserFromAmfPair,
    uploadLoginUserAmf,
    storeSystemLoginSession,
    updateLoginUser,
    exportLoginUsers,
} from "../api";
import { useAppDispatch, useAppSelector } from "../hooks";
import { loadLoginUsers } from "../store";
import { Button, Modal, Pagination, Select, TextArea, TextInput, useNinjaSfx, useToast } from "../ui";

type FormValues = {
    username: string;
    password_hash: string;
    auth_token: string;
    auth_signature: string;
    auth_device_id: string;
    session_key: string;
    note: string;
    sort_order: string;
    is_active: boolean;
};

const schemaCreate = Yup.object({
    username: Yup.string().required("Username wajib diisi.").max(128),
    password_hash: Yup.string().required("Password hash wajib diisi.").max(2048),
    auth_token: Yup.string().max(64),
    auth_signature: Yup.string().max(512),
    auth_device_id: Yup.string().max(128),
    session_key: Yup.string().max(128),
    note: Yup.string().max(255),
    sort_order: Yup.number()
        .transform((v, o) => (o === "" || o === null ? undefined : v))
        .min(0)
        .max(100000)
        .nullable(),
    is_active: Yup.boolean(),
});

const schemaEdit = Yup.object({
    username: Yup.string().required("Username wajib diisi.").max(128),
    password_hash: Yup.string().max(2048),
    auth_token: Yup.string().max(64),
    auth_signature: Yup.string().max(512),
    auth_device_id: Yup.string().max(128),
    session_key: Yup.string().max(128),
    note: Yup.string().max(255),
    sort_order: Yup.number()
        .transform((v, o) => (o === "" || o === null ? undefined : v))
        .min(0)
        .max(100000)
        .nullable(),
    is_active: Yup.boolean(),
});

function toFormValues(item?: NinjaSageLoginUser | null): FormValues {
    return {
        username: item?.username ?? "",
        password_hash: "",
        auth_token: item?.auth_token ?? "",
        auth_signature: item?.auth_signature ?? "",
        auth_device_id: item?.auth_device_id ?? "",
        session_key: item?.session_key ?? "",
        note: item?.note ?? "",
        sort_order: item?.sort_order === null || item?.sort_order === undefined ? "" : String(item.sort_order),
        is_active: item?.is_active ?? true,
    };
}

function genPasswordB64(len = 32): string {
    const n = Math.max(8, Math.min(256, Math.floor(len)));
    const bytes = new Uint8Array(n);
    if (typeof window !== "undefined" && (window as any).crypto?.getRandomValues) {
        (window as any).crypto.getRandomValues(bytes);
    } else {
        for (let i = 0; i < n; i++) {
            bytes[i] = Math.floor(Math.random() * 256);
        }
    }
    let s = "";
    for (let i = 0; i < bytes.length; i++) {
        s += String.fromCharCode(bytes[i]);
    }
    return btoa(s);
}

function bytesToBase64(bytes: Uint8Array): string {
    let s = "";
    for (let i = 0; i < bytes.length; i++) {
        s += String.fromCharCode(bytes[i]);
    }
    return btoa(s);
}

async function sha256Bytes(text: string): Promise<Uint8Array> {
    const enc = new TextEncoder();
    const buf = await crypto.subtle.digest("SHA-256", enc.encode(text));
    return new Uint8Array(buf);
}

async function sha256Hex(text: string): Promise<string> {
    const bytes = await sha256Bytes(text);
    let out = "";
    for (let i = 0; i < bytes.length; i++) {
        out += bytes[i].toString(16).padStart(2, "0");
    }
    return out;
}

async function sha256Base64(text: string): Promise<string> {
    const bytes = await sha256Bytes(text);
    return bytesToBase64(bytes);
}

function textToBase64(text: string): string {
    const enc = new TextEncoder();
    return bytesToBase64(enc.encode(text));
}

function SystemLoginLogModal({
    open,
    user,
    manualCfg,
    onClose,
    onDone,
    onError,
}: {
    open: boolean;
    user: NinjaSageLoginUser | null;
    manualCfg?: {
        username: string;
        password_b64: string;
        s1: string;
        s2: string;
        s3: string;
        upstream_url?: string | null;
    };
    onClose: () => void;
    onDone?: (info: { session_key: string; user_id?: string | null; char_id?: number | null }) => void;
    onError?: (error: string) => void;
}) {
    const [logs, setLogs] = useState<string[]>([]);
    const [status, setStatus] = useState<"idle" | "connecting" | "done" | "error">("idle");
    const [extracted, setExtracted] = useState<{
        upstream_url?: string | null;
        session_key?: string | null;
        user_id?: string | null;
        char_id?: number | null;
    } | null>(null);
    const [savingSession, setSavingSession] = useState(false);
    const esRef = useRef<EventSource | null>(null);
    const bottomRef = useRef<HTMLDivElement>(null);
    const { toast } = useToast();
    const sfx = useNinjaSfx();

    useEffect(() => {
        if (!open || (!user && !manualCfg)) {
            if (esRef.current) {
                esRef.current.close();
                esRef.current = null;
            }
            setLogs([]);
            setStatus("idle");
            setExtracted(null);
            setSavingSession(false);
            return;
        }

        setStatus("connecting");
        setLogs((p) => [
            ...p,
            `Connecting to SystemLogin stream for ${user ? user.username : manualCfg?.username || ""}...`,
        ]);
        setExtracted(null);

        let url = `/admin/api/systemlogin/stream`;
        if (manualCfg) {
            try {
                const cfg = {
                    username: manualCfg.username,
                    password_b64: manualCfg.password_b64,
                    s1: manualCfg.s1,
                    s2: manualCfg.s2,
                    s3: manualCfg.s3,
                };
                const cfgB64 = btoa(JSON.stringify(cfg));
                const qs = new URLSearchParams();
                qs.set("cfg_b64", cfgB64);
                if (manualCfg.upstream_url) {
                    qs.set("url", manualCfg.upstream_url);
                }
                url = `/admin/api/systemlogin/stream?${qs.toString()}`;
            } catch {
                url = `/admin/api/systemlogin/stream`;
            }
        } else if (user) {
            url = `/admin/api/systemlogin/stream?login_user_id=${user.id}`;
        }
        const es = new EventSource(url);
        esRef.current = es;

        const log = (msg: string) => setLogs((p) => [...p, msg]);

        es.onopen = () => log("Connection opened.");

        es.addEventListener("meta", (e: any) => {
            log(`[META] ${e.data}`);
            try {
                const d = JSON.parse(e.data);
                if (typeof d?.upstream === "string" && d.upstream.trim()) {
                    setExtracted((prev) => ({ ...(prev || {}), upstream_url: d.upstream }));
                }
            } catch {}
        });

        es.addEventListener("request", (e: any) => {
            try {
                const d = JSON.parse(e.data);
                log(`[REQ] ${d.step} -> ${d.target}`);
            } catch {
                log(`[REQ] ${e.data}`);
            }
        });

        es.addEventListener("response", (e: any) => {
            try {
                const d = JSON.parse(e.data);
                log(`[RES] ${d.step} status=${d.http_status}`);
                if (d.extracted?.session_key) {
                    log(`*** SESSION KEY: ${d.extracted.session_key} ***`);
                    setExtracted((prev) => ({
                        ...(prev || {}),
                        session_key: String(d.extracted.session_key || "").trim() || null,
                    }));
                }
            } catch {
                log(`[RES] ${e.data}`);
            }
        });

        es.addEventListener("done", (e: any) => {
            log(`[DONE] ${e.data}`);
            try {
                const d = JSON.parse(e.data);
                const sessionKey = String(d?.session_key || "").trim() || null;
                const userId = d?.user_id !== undefined && d?.user_id !== null ? String(d.user_id).trim() : null;
                const charIdNum = Number(d?.char_id);
                const charId = Number.isFinite(charIdNum) && charIdNum > 0 ? charIdNum : null;
                setExtracted((prev) => ({
                    ...(prev || {}),
                    session_key: sessionKey,
                    user_id: userId,
                    char_id: charId,
                }));
                if (sessionKey) {
                    onDone?.({ session_key: sessionKey, user_id: userId || null, char_id: charId || null });
                }
            } catch {}
            setStatus("done");
            es.close();
        });

        es.onerror = () => {
            log("[ERROR] Koneksi stream gagal atau ditutup.");
            onError?.("error");
            setStatus("error");
            try {
                es.close();
            } catch {}
        };

        es.addEventListener("error", (e: any) => {
            try {
                const d = JSON.parse(e.data);
                const detail =
                    d?.message || d?.reason ? `${d.message || ""}${d.message && d.reason ? " - " : ""}${d.reason || ""}` : "";
                log(`[ERROR] ${d.error} - ${detail}`.trim());
                if (d?.error === "cfg_missing" && Array.isArray(d?.missing)) {
                    log(`[HINT] Lengkapi field: ${d.missing.join(", ")}`);
                }
                onError?.(String(d?.error || "error"));
            } catch {
                // log(`[ERROR] Stream ended or connection failed.`);
                onError?.("error");
            }
            setStatus("error");
            es.close();
        });

        return () => {
            es.close();
        };
    }, [open, user]);

    useEffect(() => {
        bottomRef.current?.scrollIntoView({ behavior: "smooth" });
    }, [logs]);

    return (
        <Modal
            open={open}
            onClose={onClose}
            title={`Auto Login: ${user?.username || manualCfg?.username || ""}`}
            widthClassName="max-w-3xl"
        >
            <div className="h-96 overflow-y-auto rounded bg-black/50 p-4 font-mono text-xs whitespace-pre-wrap text-green-400">
                {logs.join("\n")}
                <div ref={bottomRef} />
            </div>
            <div className="mt-2 text-right text-xs font-semibold text-gray-400">
                Status: {status}
            </div>
            {!!extracted?.session_key && (
                <div className="mt-4 grid gap-3 rounded-lg border border-white/10 bg-white/[0.02] p-4">
                    <div className="grid grid-cols-1 gap-3 md:grid-cols-2">
                        <TextInput
                            label="Session Key"
                            value={extracted.session_key || ""}
                            onChange={() => {}}
                            readOnly
                        />
                        <TextInput
                            label="User ID"
                            value={extracted.user_id || ""}
                            onChange={() => {}}
                            readOnly
                        />
                        <TextInput
                            label="Char ID"
                            value={extracted.char_id ? String(extracted.char_id) : ""}
                            onChange={() => {}}
                            readOnly
                        />
                        <TextInput
                            label="Upstream URL"
                            value={extracted.upstream_url || ""}
                            onChange={() => {}}
                            readOnly
                        />
                    </div>
                    <div className="flex flex-wrap justify-end gap-2">
                        <Button
                            type="button"
                            variant="secondary"
                            onClick={async () => {
                                const v = String(extracted.session_key || "").trim();
                                if (!v) return;
                                try {
                                    await navigator.clipboard.writeText(v);
                                    toast("success", "Session key tersalin.");
                                } catch {
                                    toast("error", "Gagal menyalin session key.");
                                }
                            }}
                        >
                            Copy Session Key
                        </Button>
                        {/* Session otomatis disimpan saat DONE; tombol tetap disediakan untuk manual */}
                        <Button type="button" disabled>
                            Simpan Session (otomatis)
                        </Button>
                    </div>
                </div>
            )}
            <div className="mt-4 flex justify-end">
                <Button onClick={onClose} variant="secondary">
                    Close
                </Button>
            </div>
        </Modal>
    );
}

export function AdminNinjaSageLoginPage() {
    const dispatch = useAppDispatch();
    const { toast } = useToast();
    const sfx = useNinjaSfx();
    const state = useAppSelector((s) => s.loginUsers);
    const [encryptUpload, setEncryptUpload] = useState(false);
    const [plainPassword, setPlainPassword] = useState("");
    const [converterText, setConverterText] = useState("");
    const [converterB64, setConverterB64] = useState<string>("");
    const [converterShaHex, setConverterShaHex] = useState<string>("");
    const [converterShaB64, setConverterShaB64] = useState<string>("");
    const [converterBusy, setConverterBusy] = useState(false);
    const [amfUploads, setAmfUploads] = useState<
        Array<{
            id: number;
            original_name?: string | null;
            size: number;
            mime_type?: string | null;
            sha256?: string | null;
            encrypted: boolean;
            parsed_preview?: { username?: string | null } | null;
            created_at?: string | null;
        }>
    >([]);
    const [amfLimit, setAmfLimit] = useState(10);
    const [amfLoading, setAmfLoading] = useState(false);

    const listParamsRef = useRef<NinjaSageLoginUserListParams>({
        per_page: 25,
        page: 1,
    });

    const [q, setQ] = useState("");
    const [active, setActive] = useState<"" | "1" | "0">("");
    const [perPage, setPerPage] = useState(25);
    const [page, setPage] = useState(1);
    const [sort, setSort] = useState<string>("");

    const [editing, setEditing] = useState<NinjaSageLoginUser | null>(null);
    const [editorSeed, setEditorSeed] = useState<Partial<FormValues> | null>(null);
    const [openEditor, setOpenEditor] = useState(false);
    const [confirmDelete, setConfirmDelete] = useState<NinjaSageLoginUser | null>(null);
    const [loginTarget, setLoginTarget] = useState<NinjaSageLoginUser | null>(null);
    const autoStartedRef = useRef(false);
    const autoQueueRef = useRef<number[]>([]);
    const [autoInfo, setAutoInfo] = useState<{ session_key: string; user_id?: string | null; char_id?: number | null } | null>(null);
    const [manualCfg, setManualCfg] = useState<{
        username: string;
        password_b64: string;
        s1: string;
        s2: string;
        s3: string;
        upstream_url?: string | null;
    } | null>(null);

    const loadAmfHistory = async (limit?: number) => {
        setAmfLoading(true);
        try {
            const data = await fetchAmfUploads({ limit: limit ?? amfLimit });
            setAmfUploads(Array.isArray(data) ? data : []);
        } catch {}
        setAmfLoading(false);
    };
    useEffect(() => {
        void loadAmfHistory();
    }, []);

    useEffect(() => {
        const v = converterText || "";
        setConverterB64(v ? textToBase64(v) : "");
        setConverterShaHex("");
        setConverterShaB64("");
        if (!v) return;
        let cancelled = false;
        setConverterBusy(true);
        const t = window.setTimeout(() => {
            Promise.all([sha256Hex(v), sha256Base64(v)])
                .then(([hex, b64]) => {
                    if (cancelled) return;
                    setConverterShaHex(hex);
                    setConverterShaB64(b64);
                })
                .finally(() => {
                    if (cancelled) return;
                    setConverterBusy(false);
                });
        }, 250);
        return () => {
            cancelled = true;
            window.clearTimeout(t);
        };
    }, [converterText]);

    useEffect(() => {
        const scrollToConverter = () => {
            if (typeof window === "undefined") return;
            if (window.location.hash !== "#konversi-password") return;
            const el = document.getElementById("konversi-password");
            if (!el) return;
            el.scrollIntoView({ behavior: "smooth", block: "start" });
        };

        scrollToConverter();
        const t = window.setTimeout(scrollToConverter, 50);
        window.addEventListener("hashchange", scrollToConverter);
        return () => {
            window.clearTimeout(t);
            window.removeEventListener("hashchange", scrollToConverter);
        };
    }, []);

    const openAddWithPassword = (passwordHash: string) => {
        setEditing(null);
        setEditorSeed({ password_hash: passwordHash, is_active: true });
        setOpenEditor(true);
    };

    const listParams: NinjaSageLoginUserListParams = useMemo(
        () => ({
            q: q.trim() || undefined,
            active: active || undefined,
            per_page: perPage,
            page,
            sort: sort || undefined,
        }),
        [q, active, perPage, page, sort],
    );

    useEffect(() => {
        listParamsRef.current = listParams;
    }, [listParams]);

    useEffect(() => {
        const t = window.setTimeout(() => {
            dispatch(loadLoginUsers(listParams));
        }, 300);
        return () => window.clearTimeout(t);
    }, [dispatch, listParams]);

    const revRef = useRef<number>(0);

    useEffect(() => {
        if (typeof state.rev === "number") {
            revRef.current = state.rev;
        }
    }, [state.rev]);

    useEffect(() => {
        if (typeof state.rev !== "number") return;

        let stopped = false;
        const tick = async () => {
            try {
                const res = await fetchLoginUsersRev();
                const rev = Number(res?.rev);
                if (!Number.isFinite(rev) || rev <= revRef.current) return;
                revRef.current = rev;
                dispatch(loadLoginUsers(listParamsRef.current));
            } catch {}
        };

        void tick();
        const timer = window.setInterval(() => {
            if (stopped) return;
            void tick();
        }, 3000);

        return () => {
            stopped = true;
            window.clearInterval(timer);
        };
    }, [dispatch, state.rev]);

    const meta = state.meta || { page: 1, per_page: perPage, total: 0, last_page: 1 };

    const initialEditorValues: FormValues = useMemo(() => {
        const base = toFormValues(editing);
        return { ...base, ...(editorSeed || {}) };
    }, [editing, editorSeed]);

    const editorTitle = editing ? `Edit Login User #${editing.id}` : "Tambah Login User";

    useEffect(() => {
        if (autoStartedRef.current) return;
        if (state.loading) return;
        const candidates = state.items.filter((it) => it.is_active && it.has_password_hash).map((it) => it.id);
        if (candidates.length === 0) return;
        autoQueueRef.current = candidates.slice(1);
        const firstId = candidates[0];
        const first = state.items.find((it) => it.id === firstId) || null;
        if (first) {
            autoStartedRef.current = true;
            setLoginTarget(first);
            if (window.location.protocol !== "https:") {
                toast("info", "Disarankan akses melalui HTTPS untuk keamanan cookie.");
            }
        }
    }, [state.loading, state.items]);

    const handleAutoDone = async (info: { session_key: string; user_id?: string | null; char_id?: number | null }) => {
        setAutoInfo(info);
        const target = loginTarget;
        const manual = manualCfg;
        if (!target && !manual) return;
        try {
            sfx.play("save");
            setLoginTarget(null);
            setManualCfg(null);
            await storeSystemLoginSession({
                session_key: info.session_key,
                username: (target ? target.username : manual?.username) ?? null,
                user_id: info.user_id ?? null,
                char_id: info.char_id ?? null,
                upstream_url: undefined,
                source: "admin_auto_login",
                meta: { via: "admin_auto_login" },
            });
            toast("success", "Auto-login berhasil. Session tersimpan (HttpOnly cookie).");
        } catch (e: any) {
            toast("error", e?.response?.data?.message || "Gagal menyimpan session.");
        }
    };

    const handleAutoError = (error: string) => {
        if (manualCfg) {
            toast("error", "Auto-login manual gagal.");
            setManualCfg(null);
            return;
        }
        const queue = autoQueueRef.current;
        const nextId = queue.shift();
        const next = state.items.find((it) => it.id === nextId) || null;
        if (next) {
            setLoginTarget(next);
            return;
        }
        toast("error", "Auto-login gagal untuk semua kandidat. Silakan pilih manual.");
        setLoginTarget(null);
    };

    return (
        <div className="space-y-6">
            <div className="flex items-center gap-2 text-xs font-medium text-gray-400">
                <a href="/admin" className="hover:text-white transition">Dashboard</a>
                <span>/</span>
                <span className="text-gray-200">Backend Settings</span>
                <span>/</span>
                <span className="text-[#FFD700]">Login Users</span>
            </div>

            {state.error && (
                <div className="rounded-lg border border-red-500/20 bg-red-500/10 p-4 text-sm text-red-200">
                    <span className="font-bold">Error:</span> {state.error}
                </div>
            )}

            <div className="ninja-card rounded-2xl border border-white/10 bg-white/[0.03] p-6 shadow-[0_20px_80px_-40px_rgba(0,0,0,0.9)] backdrop-blur">
                <div className="grid gap-4 md:grid-cols-2">
                    <div className="rounded-xl border border-white/10 bg-white/[0.02] p-4">
                        <div className="mb-2 text-sm font-semibold text-white">Upload AMF</div>
                        <div className="text-xs text-gray-300 mb-3">Unggah file AMF untuk diekstrak dan disimpan. Maks 5MB, tipe application/octet-stream.</div>
                        <input
                            type="file"
                            accept="*/*"
                            onChange={async (e) => {
                                const target = e.currentTarget;
                                const file = target.files?.[0];
                                if (!file) return;
                                try {
                                    const res = await uploadLoginUserAmf(file, encryptUpload);
                                    if (res?.data) {
                                        toast("success", "Upload berhasil. Data siap diedit.");
                                        setEditing(null);
                                        setEditorSeed({
                                            username: res.data.username || "",
                                            password_hash: "",
                                            auth_token: res.data.auth_token || "",
                                            auth_signature: res.data.auth_signature || "",
                                            auth_device_id: res.data.auth_device_id || "",
                                            note: "",
                                            sort_order: "",
                                            is_active: true,
                                        });
                                        setOpenEditor(true);
                                        dispatch(loadLoginUsers(listParamsRef.current));
                                        void loadAmfHistory();
                                    } else {
                                        toast("info", "Upload tersimpan. Tidak ditemukan data login.");
                                    }
                                } catch (err: any) {
                                    toast("error", err?.response?.data?.message || "Upload gagal.");
                                } finally {
                                    target.value = "";
                                }
                            }}
                            className="block w-full rounded-xl border border-white/10 bg-white/[0.03] px-3 py-2 text-sm font-semibold text-gray-100 shadow-sm outline-none transition duration-300 focus:border-fuchsia-500 focus:ring-2 focus:ring-fuchsia-500/40"
                        />
                        <label className="mt-3 flex items-center gap-2 text-xs font-semibold text-gray-300">
                            <input
                                type="checkbox"
                                checked={encryptUpload}
                                onChange={(e) => setEncryptUpload(e.currentTarget.checked)}
                                className="h-4 w-4 rounded border border-white/20 bg-white/10 text-fuchsia-500 focus:ring-fuchsia-500/40"
                            />
                            Enkripsi konten AMF (disimpan terenkripsi di database)
                        </label>
                    </div>
                    <div className="rounded-xl border border-white/10 bg-white/[0.02] p-4">
                        <div className="mb-2 flex items-center justify-between">
                            <div className="text-sm font-semibold text-white">Riwayat Upload AMF</div>
                            <div className="flex items-end gap-2">
                                <Select
                                    label="Jumlah"
                                    value={String(amfLimit)}
                                    onChange={(e) => {
                                        const v = Number(e.target.value);
                                        setAmfLimit(v);
                                        void loadAmfHistory(v);
                                    }}
                                >
                                    <option value="10">10</option>
                                    <option value="20">20</option>
                                    <option value="50">50</option>
                                </Select>
                                <Button type="button" variant="secondary" onClick={() => loadAmfHistory()}>
                                    Refresh
                                </Button>
                            </div>
                        </div>
                        <div className="rounded-xl border border-white/10 bg-white/[0.015]">
                            {amfLoading ? (
                                <div className="px-4 py-6 text-xs text-gray-300">Memuat...</div>
                            ) : amfUploads.length === 0 ? (
                                <div className="px-4 py-6 text-xs text-gray-300">Tidak ada riwayat.</div>
                            ) : (
                                <table className="min-w-full divide-y divide-white/10 text-xs">
                                    <thead>
                                        <tr className="bg-white/[0.02] text-left font-semibold uppercase tracking-[0.18em] text-gray-300">
                                            <th className="py-2 pl-4 pr-4">File</th>
                                            <th className="py-2 pr-4">Preview</th>
                                            <th className="py-2 pr-4">Size</th>
                                            <th className="py-2 pr-4">Encrypted</th>
                                            <th className="py-2 pr-4">Uploaded</th>
                                        </tr>
                                    </thead>
                                    <tbody className="divide-y divide-white/10">
                                        {amfUploads.map((u) => (
                                            <tr key={u.id} className="text-gray-200">
                                                <td className="py-2 pl-4 pr-4">
                                                    <div className="font-semibold text-white">{u.original_name || "—"}</div>
                                                    <div className="mt-0.5 text-[11px] text-gray-300/70">#{u.id} · {u.sha256?.slice(0, 10) || "—"}</div>
                                                </td>
                                                <td className="py-2 pr-4">
                                                    {u.parsed_preview?.username || "—"}
                                                </td>
                                                <td className="py-2 pr-4">
                                                    {(() => {
                                                        const s = Number(u.size || 0);
                                                        if (!Number.isFinite(s)) return "—";
                                                        if (s >= 1024 * 1024) return `${(s / (1024 * 1024)).toFixed(2)} MB`;
                                                        if (s >= 1024) return `${(s / 1024).toFixed(2)} KB`;
                                                        return `${s} B`;
                                                    })()}
                                                </td>
                                                <td className="py-2 pr-4">
                                                    <span
                                                        className={
                                                            "inline-flex items-center rounded-full px-2.5 py-1 text-[11px] font-semibold ring-1 " +
                                                            (u.encrypted
                                                                ? "bg-fuchsia-500/15 text-fuchsia-200 ring-fuchsia-500/30"
                                                                : "bg-white/5 text-gray-200 ring-white/10")
                                                        }
                                                    >
                                                        {u.encrypted ? "Ya" : "Tidak"}
                                                    </span>
                                                </td>
                                                <td className="py-2 pr-4">
                                                    {u.created_at || "—"}
                                                </td>
                                            </tr>
                                        ))}
                                    </tbody>
                                </table>
                            )}
                        </div>
                    </div>
                    <div
                        id="konversi-password"
                        className="md:col-span-2 rounded-xl border border-white/10 bg-white/[0.02] p-4"
                    >
                        <div className="mb-2 flex items-center justify-between">
                            <div className="text-sm font-semibold text-white">Konversi Password</div>
                            <div className="text-xs text-gray-300/80">
                                {converterBusy ? "Menghitung SHA-256..." : "Siap"}
                            </div>
                        </div>
                        <div className="grid grid-cols-1 gap-3 lg:grid-cols-12">
                            <TextInput
                                className="lg:col-span-12"
                                label="Teks Password"
                                value={converterText}
                                onChange={(e) => setConverterText(e.target.value)}
                                placeholder="Masukkan teks biasa"
                            />
                            <TextInput
                                className="lg:col-span-12"
                                label="Base64 (teks → base64)"
                                value={converterB64 || ""}
                                onChange={() => {}}
                                readOnly
                            />
                            <div className="lg:col-span-12 flex flex-wrap justify-end gap-2">
                                <Button
                                    type="button"
                                    variant="secondary"
                                    disabled={!converterB64}
                                    onClick={async () => {
                                        try {
                                            await navigator.clipboard.writeText(converterB64);
                                            toast("success", "Base64 tersalin.");
                                        } catch {
                                            toast("error", "Gagal menyalin.");
                                        }
                                    }}
                                >
                                    Copy Base64
                                </Button>
                                <Button
                                    type="button"
                                    variant="secondary"
                                    disabled={!converterB64}
                                    onClick={() => openAddWithPassword(converterB64)}
                                >
                                    Pakai ke Tambah
                                </Button>
                            </div>
                            <TextInput
                                className="lg:col-span-12"
                                label="SHA-256 Hex (teks → sha256 → hex)"
                                value={converterShaHex || ""}
                                onChange={() => {}}
                                readOnly
                            />
                            <div className="lg:col-span-12 flex flex-wrap justify-end gap-2">
                                <Button
                                    type="button"
                                    variant="secondary"
                                    disabled={!converterShaHex}
                                    onClick={async () => {
                                        try {
                                            await navigator.clipboard.writeText(converterShaHex);
                                            toast("success", "SHA-256 Hex tersalin.");
                                        } catch {
                                            toast("error", "Gagal menyalin.");
                                        }
                                    }}
                                >
                                    Copy Hex
                                </Button>
                                <Button
                                    type="button"
                                    variant="secondary"
                                    disabled={!converterShaHex}
                                    onClick={() => openAddWithPassword(converterShaHex)}
                                >
                                    Pakai ke Tambah
                                </Button>
                            </div>
                            <TextInput
                                className="lg:col-span-12"
                                label="SHA-256 Base64 (teks → sha256 → base64)"
                                value={converterShaB64 || ""}
                                onChange={() => {}}
                                readOnly
                            />
                            <div className="lg:col-span-12 flex flex-wrap justify-end gap-2">
                                <Button
                                    type="button"
                                    variant="secondary"
                                    disabled={!converterShaB64}
                                    onClick={async () => {
                                        try {
                                            await navigator.clipboard.writeText(converterShaB64);
                                            toast("success", "SHA-256 Base64 tersalin.");
                                        } catch {
                                            toast("error", "Gagal menyalin.");
                                        }
                                    }}
                                >
                                    Copy SHA Base64
                                </Button>
                                <Button
                                    type="button"
                                    variant="secondary"
                                    disabled={!converterShaB64}
                                    onClick={() => openAddWithPassword(converterShaB64)}
                                >
                                    Pakai ke Tambah
                                </Button>
                            </div>
                        </div>
                    </div>
                </div>
                <div className="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
                    <div>
                        <div className="text-xs font-semibold uppercase tracking-[0.18em] text-gray-300">
                            Pengaturan Backend Ninja Sage
                        </div>
                        <div className="mt-1 text-2xl font-semibold tracking-tight text-white font-ninja">
                            <span className="text-[#FFD700]">Login User</span> Manager
                        </div>
                        <div className="mt-1 text-sm text-gray-300/80">
                            CRUD + filter/sort/pagination + realtime
                        </div>
                    </div>
                    <div className="flex flex-wrap items-center gap-2">
                        <Button
                            type="button"
                            tip="Ambil contoh dari file LoginUser"
                            variant="secondary"
                            onClick={async () => {
                                try {
                                    sfx.play("upload");
                                    const res = await importSampleLoginUser();
                                    if (!res.username || !res.password_hash) {
                                        toast("error", "Data sample tidak ditemukan di file.");
                                        return;
                                    }
                                    setEditing(null);
                                    setEditorSeed({
                                        username: res.username,
                                        password_hash: res.password_hash,
                                        auth_token: res.auth_token ?? "",
                                        auth_signature: res.auth_signature ?? "",
                                        auth_device_id: res.auth_device_id ?? "",
                                    });
                                    setOpenEditor(true);
                                } catch (e: any) {
                                    toast("error", e?.response?.data?.message || "Gagal mengambil sample.");
                                }
                            }}
                        >
                            Import Sample
                        </Button>
                        <Button
                            type="button"
                            tip="Tambah data"
                            onClick={() => {
                                setEditing(null);
                                setEditorSeed(null);
                                setOpenEditor(true);
                            }}
                        >
                            Tambah
                        </Button>
                        <Button
                            type="button"
                            variant="secondary"
                            onClick={() => exportLoginUsers("json", listParamsRef.current)}
                        >
                            Export JSON
                        </Button>
                        <Button
                            type="button"
                            variant="secondary"
                            onClick={() => exportLoginUsers("csv", listParamsRef.current)}
                        >
                            Export CSV
                        </Button>
                    </div>
                </div>

                <div className="mt-6 grid grid-cols-1 gap-3 lg:grid-cols-12">
                <TextInput
                    className="lg:col-span-6"
                    label="Cari"
                    value={q}
                    onChange={(e) => {
                        setPage(1);
                        setQ(e.target.value);
                    }}
                    placeholder="Username..."
                />
                <Select
                    className="lg:col-span-3"
                    label="Status"
                    value={active}
                    onChange={(e) => {
                        setPage(1);
                        setActive(e.target.value as any);
                    }}
                >
                    <option value="">Semua</option>
                    <option value="1">Aktif</option>
                    <option value="0">Nonaktif</option>
                </Select>
                <Select
                    className="lg:col-span-3"
                    label="Per Halaman"
                    value={String(perPage)}
                    onChange={(e) => {
                        setPage(1);
                        setPerPage(Number(e.target.value));
                    }}
                >
                    <option value="10">10</option>
                    <option value="25">25</option>
                    <option value="50">50</option>
                    <option value="100">100</option>
                </Select>
                <Select
                    className="lg:col-span-12"
                    label="Sorting"
                    value={sort}
                    onChange={(e) => {
                        setPage(1);
                        setSort(e.target.value);
                    }}
                >
                    <option value="">Default (sort_order asc, id desc)</option>
                    <option value="username:asc">Username ↑</option>
                    <option value="username:desc">Username ↓</option>
                    <option value="created_at:desc">Created ↓</option>
                    <option value="created_at:asc">Created ↑</option>
                    <option value="updated_at:desc">Updated ↓</option>
                    <option value="updated_at:asc">Updated ↑</option>
                    <option value="is_active:desc">Aktif dulu</option>
                    <option value="is_active:asc">Nonaktif dulu</option>
                </Select>
            </div>

            <div className="mt-6 grid grid-cols-1 gap-3 lg:grid-cols-12">
                <TextInput
                    className="lg:col-span-2"
                    label="Manual Username"
                    value={manualCfg?.username || ""}
                    onChange={(e) =>
                        setManualCfg((p) => ({ ...(p || { username: "", password_b64: "", s1: "", s2: "", s3: "" }), username: e.target.value }))
                    }
                    placeholder="Contoh: n031"
                />
                <TextInput
                    className="lg:col-span-3"
                    label="Password (Base64)"
                    value={manualCfg?.password_b64 || ""}
                    onChange={(e) =>
                        setManualCfg((p) => ({ ...(p || { username: "", password_b64: "", s1: "", s2: "", s3: "" }), password_b64: e.target.value }))
                    }
                    placeholder="Base64"
                />
                <div className="lg:col-span-3 flex justify-end">
                    <Button
                        type="button"
                        variant="secondary"
                        onClick={() =>
                            setManualCfg((p) => ({
                                ...(p || { username: "", password_b64: "", s1: "", s2: "", s3: "" }),
                                password_b64: genPasswordB64(32),
                            }))
                        }
                    >
                        Generate Password
                    </Button>
                </div>
                <TextInput
                    className="lg:col-span-2"
                    label="s1 Token"
                    value={manualCfg?.s1 || ""}
                    onChange={(e) =>
                        setManualCfg((p) => ({ ...(p || { username: "", password_b64: "", s1: "", s2: "", s3: "" }), s1: e.target.value }))
                    }
                    placeholder="Token"
                />
                <TextArea
                    className="lg:col-span-3"
                    label="s2 Signature (Hex)"
                    value={manualCfg?.s2 || ""}
                    onChange={(e) =>
                        setManualCfg((p) => ({ ...(p || { username: "", password_b64: "", s1: "", s2: "", s3: "" }), s2: e.target.value }))
                    }
                    rows={2}
                    placeholder="Hex panjang"
                />
                <TextInput
                    className="lg:col-span-2"
                    label="s3 Device ID"
                    value={manualCfg?.s3 || ""}
                    onChange={(e) =>
                        setManualCfg((p) => ({ ...(p || { username: "", password_b64: "", s1: "", s2: "", s3: "" }), s3: e.target.value }))
                    }
                    placeholder="Numeric besar"
                />
                <div className="lg:col-span-12 flex justify-end">
                    <Button
                        type="button"
                        onClick={() => {
                            const cfg = manualCfg;
                            const u = cfg?.username?.trim() || "";
                            const p = cfg?.password_b64?.trim() || "";
                            const s1 = cfg?.s1?.trim() || "";
                            const s2 = cfg?.s2?.trim() || "";
                            const s3 = cfg?.s3?.trim() || "";
                            if (!u || !p || !s1 || !s2 || !s3) {
                                toast("error", "Lengkapi username, password_b64, s1, s2, s3.");
                                return;
                            }
                            sfx.play("upload");
                            setLoginTarget(null);
                            setAutoInfo(null);
                            autoStartedRef.current = true;
                            setManualCfg({ username: u, password_b64: p, s1, s2, s3 });
                            if (window.location.protocol !== "https:") {
                                toast("info", "Disarankan akses melalui HTTPS untuk keamanan cookie.");
                            }
                        }}
                    >
                        Auto Login Manual (SSE)
                    </Button>
                    <Button
                        type="button"
                        variant="secondary"
                        className="ml-2"
                        onClick={async () => {
                            try {
                                sfx.play("upload");
                                const data = await importLoginUserFromAmfPair();
                                const username = data.username || "";
                                const password_b64 = data.password_hash || "";
                                const s1 = data.auth_token || "";
                                const s2 = data.auth_signature || "";
                                const s3 = data.auth_device_id || "";
                                setManualCfg({ username, password_b64, s1, s2, s3 });
                                toast("success", "Berhasil mengisi dari file AMF.");
                            } catch (e: any) {
                                toast("error", e?.response?.data?.message || "Gagal membaca file AMF.");
                            }
                        }}
                    >
                        Isi dari File AMF
                    </Button>
                </div>
            </div>

            <div className="mt-6 overflow-x-auto rounded-2xl border border-white/10">
                <table className="min-w-full divide-y divide-white/10">
                    <thead>
                        <tr className="bg-white/[0.02] text-left text-xs font-semibold uppercase tracking-[0.18em] text-gray-300">
                            <th className="py-3.5 pl-4 pr-4">Username</th>
                            <th className="py-3.5 pr-4">Note</th>
                            <th className="py-3.5 pr-4">Sort</th>
                            <th className="py-3.5 pr-4">Status</th>
                            <th className="py-3.5 pr-4">Hash</th>
                            <th className="py-3.5 pr-4">Session Key</th>
                            <th className="py-3.5 pr-4 text-right">Action</th>
                        </tr>
                    </thead>
                    <tbody className="divide-y divide-white/10">
                        {state.loading ? (
                            <tr>
                                <td colSpan={7} className="px-4 py-8 text-sm text-gray-300/80">
                                    Memuat...
                                </td>
                            </tr>
                        ) : state.items.length === 0 ? (
                            <tr>
                                <td colSpan={7} className="px-4 py-8 text-sm text-gray-300/80">
                                    Tidak ada data.
                                </td>
                            </tr>
                        ) : (
                            state.items.map((item) => (
                                <tr
                                    key={item.id}
                                    className="text-sm text-gray-200 transition duration-300 hover:bg-white/[0.02]"
                                >
                                    <td className="py-3.5 pl-4 pr-4">
                                        <div className="font-semibold text-white">{item.username}</div>
                                        <div className="mt-0.5 text-xs text-gray-300/70">
                                            #{item.id} · {item.updated_at || item.created_at || "—"}
                                        </div>
                                    </td>
                                    <td className="py-3.5 pr-4 text-xs text-gray-300/80">
                                        {item.note || "—"}
                                    </td>
                                    <td className="py-3.5 pr-4 text-xs text-gray-300/80">
                                        {item.sort_order ?? "—"}
                                    </td>
                                    <td className="py-3.5 pr-4">
                                        <span
                                            className={
                                                "inline-flex items-center rounded-full px-2.5 py-1 text-xs font-semibold ring-1 " +
                                                (item.is_active
                                                    ? "bg-emerald-500/15 text-emerald-200 ring-emerald-500/30"
                                                    : "bg-white/5 text-gray-200 ring-white/10")
                                            }
                                        >
                                            {item.is_active ? "Aktif" : "Nonaktif"}
                                        </span>
                                    </td>
                                    <td className="py-3.5 pr-4">
                                        <span
                                            className={
                                                "inline-flex items-center rounded-full px-2.5 py-1 text-xs font-semibold ring-1 " +
                                                (item.has_password_hash
                                                    ? "bg-sky-500/15 text-sky-200 ring-sky-500/30"
                                                    : "bg-white/5 text-gray-200 ring-white/10")
                                            }
                                        >
                                            {item.has_password_hash ? "Ada" : "Kosong"}
                                        </span>
                                    </td>
                                    <td className="py-3.5 pr-4 text-xs font-mono text-gray-300/80">
                                        {item.session_key ? (
                                            <span title={item.session_key}>
                                                {item.session_key.length > 8
                                                    ? item.session_key.slice(0, 8) + "..."
                                                    : item.session_key}
                                            </span>
                                        ) : (
                                            "—"
                                        )}
                                    </td>
                                    <td className="py-3.5 pr-4 text-right">
                                        <div className="inline-flex items-center gap-2">
                                            <Button
                                                type="button"
                                                variant="secondary"
                                                className="!bg-emerald-500/20 !text-emerald-300 hover:!bg-emerald-500/30 ring-1 ring-emerald-500/40"
                                                onClick={() => setLoginTarget(item)}
                                            >
                                                Auto Login
                                            </Button>
                                            <Button
                                                type="button"
                                                variant="secondary"
                                                onClick={async () => {
                                                    try {
                                                        sfx.play("upload");
                                                        const res = await importSampleLoginUser();
                                                        if (!res.username || !res.password_hash) {
                                                            toast("error", "Data sample tidak ditemukan di file.");
                                                            return;
                                                        }
                                                        if (res.username !== item.username) {
                                                            toast(
                                                                "error",
                                                                `Username sample (${res.username}) tidak sama dengan baris ini (${item.username}).`,
                                                            );
                                                            return;
                                                        }
                                                        setEditing(item);
                                                        setEditorSeed({
                                                            username: res.username,
                                                            password_hash: res.password_hash,
                                                            auth_token: res.auth_token ?? "",
                                                            auth_signature: res.auth_signature ?? "",
                                                            auth_device_id: res.auth_device_id ?? "",
                                                        });
                                                        setOpenEditor(true);
                                                    } catch (e: any) {
                                                        toast(
                                                            "error",
                                                            e?.response?.data?.message || "Gagal mengambil sample.",
                                                        );
                                                    }
                                                }}
                                            >
                                                Import Sample
                                            </Button>
                                            <Button
                                                type="button"
                                                variant="secondary"
                                                onClick={() => {
                                                    setEditing(item);
                                                    setEditorSeed(null);
                                                    setOpenEditor(true);
                                                }}
                                            >
                                                Edit
                                            </Button>
                                            <Button
                                                type="button"
                                                variant="danger"
                                                onClick={() => setConfirmDelete(item)}
                                            >
                                                Hapus
                                            </Button>
                                        </div>
                                    </td>
                                </tr>
                            ))
                        )}
                    </tbody>
                </table>
            </div>

            <div className="mt-5 flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
                <div className="text-sm text-gray-300/80">
                    Total: <span className="font-semibold text-gray-100">{meta.total}</span>
                    {typeof state.rev === "number" ? (
                        <>
                            {" "}
                            · Realtime Rev: <span className="font-semibold text-gray-100">{state.rev}</span>
                        </>
                    ) : null}
                </div>
                <Pagination page={meta.page} lastPage={meta.last_page} onPage={setPage} />
            </div>

            <SystemLoginLogModal
                open={!!loginTarget || !!manualCfg}
                user={loginTarget}
                manualCfg={manualCfg || undefined}
                onClose={() => {
                    setLoginTarget(null);
                    setManualCfg(null);
                }}
                onDone={handleAutoDone}
                onError={handleAutoError}
            />

            <Modal
                open={openEditor}
                title={editorTitle}
                onClose={() => setOpenEditor(false)}
                widthClassName="max-w-2xl"
            >
                <Formik<FormValues>
                    initialValues={initialEditorValues}
                    enableReinitialize
                    validationSchema={editing ? schemaEdit : schemaCreate}
                    onSubmit={async (values, helpers) => {
                        helpers.setSubmitting(true);
                        try {
                            const payload = {
                                username: values.username.trim(),
                                password_hash: values.password_hash.trim(),
                                auth_token: values.auth_token.trim() || null,
                                auth_signature: values.auth_signature.trim() || null,
                                auth_device_id: values.auth_device_id.trim() || null,
                                session_key: values.session_key.trim() || null,
                                note: values.note.trim() === "" ? null : values.note.trim(),
                                sort_order: values.sort_order.trim() === "" ? null : Number(values.sort_order),
                                is_active: values.is_active,
                            };

                            if (editing) {
                                sfx.play("save");
                                await updateLoginUser(editing.id, {
                                    username: payload.username,
                                    password_hash: payload.password_hash === "" ? undefined : payload.password_hash,
                                    auth_token: payload.auth_token,
                                    auth_signature: payload.auth_signature,
                                    auth_device_id: payload.auth_device_id,
                                    session_key: payload.session_key,
                                    note: payload.note,
                                    sort_order: payload.sort_order,
                                    is_active: payload.is_active,
                                });
                                toast("success", "Login User diperbarui.");
                            } else {
                                sfx.play("save");
                                await createLoginUser({
                                    username: payload.username,
                                    password_hash: payload.password_hash,
                                    auth_token: payload.auth_token,
                                    auth_signature: payload.auth_signature,
                                    auth_device_id: payload.auth_device_id,
                                    session_key: payload.session_key,
                                    note: payload.note,
                                    sort_order: payload.sort_order,
                                    is_active: payload.is_active,
                                });
                                toast("success", "Login User ditambahkan.");
                            }

                            setOpenEditor(false);
                            setEditing(null);
                            setEditorSeed(null);
                            await dispatch(loadLoginUsers(listParamsRef.current));
                        } catch (e: any) {
                            const msg =
                                e?.response?.status === 422 ? "Validasi gagal." : "Gagal menyimpan.";
                            toast("error", e?.response?.data?.message || msg);
                        } finally {
                            helpers.setSubmitting(false);
                        }
                    }}
                >
                    {({ handleSubmit, values, errors, touched, isSubmitting, setFieldValue }) => (
                        <form onSubmit={handleSubmit} className="grid grid-cols-1 gap-4 lg:grid-cols-2">
                            <TextInput
                                label="Username"
                                value={values.username}
                                onChange={(e) => setFieldValue("username", e.target.value)}
                                error={touched.username ? (errors.username as any) : null}
                                placeholder="Contoh: kingjoki"
                                className="lg:col-span-2"
                            />
                            <TextArea
                                label={editing ? "Password Hash (opsional)" : "Password Hash"}
                                value={values.password_hash}
                                onChange={(e) => setFieldValue("password_hash", e.target.value)}
                                error={touched.password_hash ? (errors.password_hash as any) : null}
                                rows={3}
                                placeholder={editing ? "Kosongkan jika tidak ingin mengubah." : "Masukkan password hash."}
                                className="lg:col-span-2"
                            />
                            <div className="lg:col-span-2 grid grid-cols-1 gap-2 md:grid-cols-2">
                                <TextInput
                                    label="Teks Password"
                                    value={plainPassword}
                                    onChange={(e) => setPlainPassword(e.target.value)}
                                    placeholder="Masukkan teks biasa"
                                />
                                <div className="flex items-end justify-end gap-2">
                                    <Button
                                        type="button"
                                        variant="secondary"
                                        onClick={() => setFieldValue("password_hash", textToBase64(plainPassword))}
                                    >
                                        Teks → Base64
                                    </Button>
                                    <Button
                                        type="button"
                                        variant="secondary"
                                        onClick={async () => setFieldValue("password_hash", await sha256Hex(plainPassword))}
                                    >
                                        Teks → SHA-256 Hex
                                    </Button>
                                    <Button
                                        type="button"
                                        variant="secondary"
                                        onClick={async () => setFieldValue("password_hash", await sha256Base64(plainPassword))}
                                    >
                                        Teks → SHA-256 Base64
                                    </Button>
                                </div>
                            </div>
                            <div className="lg:col-span-2 flex justify-end gap-2">
                                <Button
                                    type="button"
                                    variant="secondary"
                                    onClick={() => setFieldValue("password_hash", genPasswordB64(32))}
                                >
                                    Generate Password
                                </Button>
                                <Button
                                    type="button"
                                    variant="secondary"
                                    onClick={() => setFieldValue("password_hash", "")}
                                >
                                    Kosongkan
                                </Button>
                            </div>
                            <TextInput
                                label="Auth Token"
                                value={values.auth_token}
                                onChange={(e) => setFieldValue("auth_token", e.target.value)}
                                error={touched.auth_token ? (errors.auth_token as any) : null}
                                placeholder="Token (16 chars)"
                                className="lg:col-span-2"
                            />
                            <TextArea
                                label="Auth Signature"
                                value={values.auth_signature}
                                onChange={(e) => setFieldValue("auth_signature", e.target.value)}
                                error={touched.auth_signature ? (errors.auth_signature as any) : null}
                                rows={2}
                                placeholder="Signature (Long Hex)"
                                className="lg:col-span-2"
                            />
                            <TextInput
                                label="Auth Device ID"
                                value={values.auth_device_id}
                                onChange={(e) => setFieldValue("auth_device_id", e.target.value)}
                                error={touched.auth_device_id ? (errors.auth_device_id as any) : null}
                                placeholder="Device ID (Numeric)"
                                className="lg:col-span-2"
                            />
                            <TextInput
                                label="Session Key"
                                value={values.session_key}
                                onChange={(e) => setFieldValue("session_key", e.target.value)}
                                error={touched.session_key ? (errors.session_key as any) : null}
                                placeholder="Session Key (Optional)"
                                className="lg:col-span-2"
                            />
                            <TextInput
                                label="Sort Order"
                                value={values.sort_order}
                                onChange={(e) => setFieldValue("sort_order", e.target.value)}
                                error={touched.sort_order ? (errors.sort_order as any) : null}
                                placeholder="0..100000"
                            />
                            <Select
                                label="Aktif"
                                value={values.is_active ? "1" : "0"}
                                onChange={(e) => setFieldValue("is_active", e.target.value === "1")}
                            >
                                <option value="1">Aktif</option>
                                <option value="0">Nonaktif</option>
                            </Select>
                            <TextArea
                                label="Note"
                                value={values.note}
                                onChange={(e) => setFieldValue("note", e.target.value)}
                                error={touched.note ? (errors.note as any) : null}
                                rows={3}
                                className="lg:col-span-2"
                            />
                            <div className="lg:col-span-2 flex justify-end gap-2">
                                <Button
                                    type="button"
                                    variant="secondary"
                                    onClick={() => setOpenEditor(false)}
                                >
                                    Batal
                                </Button>
                                <Button type="submit" disabled={isSubmitting}>
                                    Simpan
                                </Button>
                            </div>
                        </form>
                    )}
                </Formik>
            </Modal>

            <Modal
                open={!!confirmDelete}
                title={confirmDelete ? `Hapus Login User #${confirmDelete.id}?` : "Hapus"}
                onClose={() => setConfirmDelete(null)}
                widthClassName="max-w-xl"
                footer={
                    <>
                        <Button type="button" variant="secondary" onClick={() => setConfirmDelete(null)}>
                            Batal
                        </Button>
                        <Button
                            type="button"
                            variant="danger"
                            onClick={async () => {
                                if (!confirmDelete) return;
                                try {
                                    sfx.play("delete");
                                    await deleteLoginUser(confirmDelete.id);
                                    toast("success", "Login User dihapus.");
                                    setConfirmDelete(null);
                                    await dispatch(loadLoginUsers(listParamsRef.current));
                                } catch (e: any) {
                                    toast("error", e?.response?.data?.message || "Gagal menghapus.");
                                }
                            }}
                        >
                            Hapus
                        </Button>
                    </>
                }
            >
                <div className="text-sm text-gray-200">
                    Data akan dihapus permanen. Lanjutkan?
                </div>
            </Modal>
        </div>
    </div>
    );
}
