// ===== Teuanjai Radio — User / permission management (admin) =====
// เพิ่ม/แก้รหัส/ลบ บัญชีผู้ดูแล — เก็บใน D1 (admin_users), รหัสเป็น SHA-256 hash

function adminFetch(path, opts) {
  const o = opts || {};
  o.headers = Object.assign({ "x-admin-token": window.__adminToken || "" }, o.headers || {});
  o.cache = "no-store";
  return fetch(path, o);
}

// ===== นโยบายรหัสผ่าน =====
const PW_SPECIAL = /[!@#$%^&*()_+\-=\[\]{}|;':",.\/<>?]/;
function pwChecks(p) {
  return {
    len: p.length >= 8,
    upper: /[A-Z]/.test(p),
    lower: /[a-z]/.test(p),
    numSpec: /[0-9]/.test(p) || PW_SPECIAL.test(p),
  };
}
function pwValid(p) { const c = pwChecks(p); return c.len && c.upper && c.lower && c.numSpec; }
function pwStrength(p) {
  if (!p) return { pct: 0, label: "", color: "var(--ink-faint)" };
  const c = pwChecks(p);
  let s = (c.len ? 1 : 0) + (c.upper ? 1 : 0) + (c.lower ? 1 : 0) + (c.numSpec ? 1 : 0);
  if (p.length >= 12) s++;
  if (/[0-9]/.test(p) && PW_SPECIAL.test(p)) s++; // มีทั้งตัวเลข + อักขระพิเศษ
  const levels = [
    { pct: 22, label: "อ่อนมาก", color: "oklch(0.62 0.20 25)" },
    { pct: 44, label: "อ่อน", color: "oklch(0.70 0.17 55)" },
    { pct: 66, label: "ปานกลาง", color: "oklch(0.78 0.15 95)" },
    { pct: 84, label: "ดี", color: "oklch(0.70 0.15 150)" },
    { pct: 100, label: "ปลอดภัยสูง", color: "oklch(0.62 0.16 158)" },
  ];
  let idx = s <= 1 ? 0 : s === 2 ? 1 : s === 3 ? 2 : s === 4 ? 3 : 4;
  if (!pwValid(p) && idx > 2) idx = 2; // ยังไม่ผ่านเกณฑ์ครบ → ไม่เกิน "ปานกลาง"
  return levels[idx];
}

function PwReq({ ok, text }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 7, fontSize: 12, fontWeight: 500,
      color: ok ? "oklch(0.58 0.13 155)" : "var(--ink-faint)", transition: "color 0.2s" }}>
      <span style={{ width: 16, height: 16, borderRadius: "50%", flex: "0 0 auto", display: "grid", placeItems: "center", color: "#fff",
        background: ok ? "linear-gradient(140deg, oklch(0.72 0.14 158), oklch(0.70 0.13 168))" : "oklch(0.85 0.01 250)",
        transition: "background 0.2s" }}>
        <Icon name={ok ? "check" : "xmark"} size={10} stroke={3} />
      </span>
      {text}
    </div>
  );
}

function UserEditor({ initial, onSaved, onCancel }) {
  const isEdit = !!initial;
  const [username, setUsername] = useState(initial ? initial.username : "");
  const [password, setPassword] = useState("");
  const [show, setShow] = useState(false);
  const [err, setErr] = useState("");
  const [busy, setBusy] = useState(false);

  const checks = pwChecks(password);
  const strength = pwStrength(password);
  const valid = pwValid(password);
  const userOk = isEdit || /^[a-z0-9._-]{3,40}$/.test(username.trim().toLowerCase());

  const save = async () => {
    if (busy) return;
    const u = username.trim().toLowerCase();
    if (!isEdit && !/^[a-z0-9._-]{3,40}$/.test(u)) { setErr("ชื่อผู้ใช้ใช้ได้เฉพาะ a-z 0-9 . _ - (3-40 ตัว)"); return; }
    if (!pwValid(password)) { setErr("รหัสผ่านยังไม่ผ่านเกณฑ์ความปลอดภัย"); return; }
    setBusy(true);
    try {
      const r = await adminFetch("/api/admin/users", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ username: u, password }),
      });
      const data = await r.json().catch(() => ({}));
      if (!r.ok || !data.ok) { setErr(data.error || "บันทึกไม่สำเร็จ"); setBusy(false); return; }
      onSaved(u);
    } catch (e) { setErr("เชื่อมต่อเซิร์ฟเวอร์ไม่ได้"); setBusy(false); }
  };

  return (
    <div onClick={onCancel} style={{ position: "absolute", inset: 0, zIndex: 60, display: "flex", flexDirection: "column", justifyContent: "flex-end",
      background: "oklch(0.4 0.04 250 / 0.34)", backdropFilter: "blur(4px)", animation: "fadeIn 0.25s both" }}>
      <div onClick={(e) => e.stopPropagation()} className="glass" style={{ borderRadius: "26px 26px 0 0",
        padding: "10px 22px calc(22px + env(safe-area-inset-bottom))", background: "oklch(0.98 0.012 220 / 0.86)",
        animation: "slideUp 0.35s cubic-bezier(0.22,1,0.36,1)" }}>
        <div style={{ width: 44, height: 5, borderRadius: 5, background: "oklch(0.7 0.02 250 / 0.3)", margin: "4px auto 16px" }} />
        <div style={{ fontFamily: "var(--font-disp)", fontSize: 18, fontWeight: 700, color: "var(--ink)", marginBottom: 16 }}>
          {isEdit ? "เปลี่ยนรหัสผ่าน" : "เพิ่มผู้ดูแลใหม่"}
        </div>

        <label style={lblStyle}>ชื่อผู้ใช้</label>
        <input value={username} disabled={isEdit} autoCapitalize="none" autoCorrect="off" spellCheck={false}
          onChange={(e) => { setUsername(e.target.value.replace(/\s/g, "")); setErr(""); }}
          placeholder="เช่น thongchai.hoh"
          style={{ ...inpStyle, opacity: isEdit ? 0.6 : 1, cursor: isEdit ? "not-allowed" : "text" }} />

        <label style={{ ...lblStyle, marginTop: 12 }}>{isEdit ? "รหัสผ่านใหม่" : "รหัสผ่าน"}</label>
        <div style={{ position: "relative" }}>
          <input value={password} type={show ? "text" : "password"} autoCapitalize="none" autoCorrect="off" spellCheck={false}
            onChange={(e) => { setPassword(e.target.value); setErr(""); }}
            placeholder="ตั้งรหัสผ่านที่ปลอดภัย" style={{ ...inpStyle, paddingRight: 46 }} />
          <button type="button" onClick={() => setShow((s) => !s)} aria-label={show ? "ซ่อนรหัสผ่าน" : "แสดงรหัสผ่าน"}
            style={{ position: "absolute", right: 6, top: 0, height: 50, width: 40, display: "grid", placeItems: "center", color: "var(--ink-faint)" }}>
            <Icon name={show ? "eye-off" : "eye"} size={19} />
          </button>
        </div>

        {/* แถบความแข็งแกร่ง */}
        {password && (
          <div style={{ marginTop: 10 }}>
            <div style={{ height: 6, borderRadius: 5, background: "oklch(0.9 0.01 250)", overflow: "hidden" }}>
              <div style={{ height: "100%", width: strength.pct + "%", background: strength.color, borderRadius: 5,
                transition: "width 0.3s, background 0.3s" }} />
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", marginTop: 5 }}>
              <span style={{ fontSize: 11.5, color: "var(--ink-faint)" }}>ความแข็งแกร่งของรหัสผ่าน</span>
              <span style={{ fontSize: 11.5, fontWeight: 700, color: strength.color }}>{strength.label}</span>
            </div>
          </div>
        )}

        {/* checklist เกณฑ์รหัสผ่าน */}
        <div style={{ display: "flex", flexDirection: "column", gap: 6, marginTop: 12, padding: "12px 14px", borderRadius: 14,
          background: "oklch(0.97 0.012 230 / 0.6)", border: "1px solid var(--glass-line)" }}>
          <PwReq ok={checks.len} text="ยาวอย่างน้อย 8 ตัวอักษร" />
          <PwReq ok={checks.upper} text="มีตัวพิมพ์ใหญ่ (A–Z) อย่างน้อย 1 ตัว" />
          <PwReq ok={checks.lower} text="มีตัวพิมพ์เล็ก (a–z) อย่างน้อย 1 ตัว" />
          <PwReq ok={checks.numSpec} text="มีตัวเลข (0–9) หรืออักขระพิเศษ อย่างน้อย 1 ตัว" />
        </div>

        {err && (
          <div style={{ display: "flex", alignItems: "center", gap: 6, marginTop: 10, color: "oklch(0.55 0.18 25)", fontSize: 12.5, fontWeight: 600 }}>
            <Icon name="xmark" size={14} /> {err}
          </div>
        )}

        <button onClick={save} disabled={busy || !valid || !userOk}
          style={{ ...btnPrimary, marginTop: 18, opacity: (busy || !valid || !userOk) ? 0.5 : 1, cursor: (busy || !valid || !userOk) ? "not-allowed" : "pointer" }}>
          {busy ? "กำลังบันทึก…" : (isEdit ? "บันทึกรหัสใหม่" : "เพิ่มผู้ดูแล")}
        </button>
        <button onClick={onCancel} style={{ ...btnGhost, marginTop: 10 }}>ยกเลิก</button>
      </div>
    </div>
  );
}

function ConfirmDeleteUser({ username, onConfirm, onCancel, busy, err }) {
  return (
    <div onClick={onCancel} style={{ position: "absolute", inset: 0, zIndex: 70, display: "grid", placeItems: "center", padding: 28,
      background: "oklch(0.4 0.04 250 / 0.4)", backdropFilter: "blur(5px)", animation: "fadeIn 0.2s both" }}>
      <div onClick={(e) => e.stopPropagation()} className="glass" style={{ borderRadius: 22, padding: "22px 20px 16px", width: "100%", maxWidth: 320, textAlign: "center",
        background: "oklch(0.98 0.012 220 / 0.92)", animation: "pop 0.32s both" }}>
        <div style={{ width: 46, height: 46, borderRadius: 14, margin: "0 auto 12px", display: "grid", placeItems: "center", color: "#fff",
          background: "linear-gradient(140deg, oklch(0.66 0.18 25), oklch(0.62 0.18 15))",
          boxShadow: "0 8px 18px oklch(0.62 0.18 20 / 0.32)" }}><Icon name="trash" size={22} /></div>
        <div style={{ fontFamily: "var(--font-disp)", fontSize: 17, fontWeight: 700, color: "var(--ink)", marginBottom: 4 }}>ลบผู้ดูแลนี้?</div>
        <div style={{ fontSize: 13, color: "var(--ink-soft)", lineHeight: 1.45, marginBottom: 16 }}>
          <b style={{ color: "var(--ink)" }}>{username}</b> จะเข้าระบบผู้ดูแลไม่ได้อีก
        </div>
        {err && <div style={{ color: "oklch(0.55 0.18 25)", fontSize: 12.5, fontWeight: 600, marginBottom: 12 }}>{err}</div>}
        <div style={{ display: "flex", gap: 10 }}>
          <button onClick={onCancel} style={{ ...btnGhost, height: 48, flex: 1 }}>ยกเลิก</button>
          <button onClick={() => onConfirm(username)} disabled={busy} style={{ ...btnPrimary, height: 48, flex: 1, opacity: busy ? 0.55 : 1,
            background: "linear-gradient(120deg, oklch(0.62 0.18 22), oklch(0.6 0.17 10))",
            boxShadow: "0 10px 22px oklch(0.62 0.18 20 / 0.36)" }}>{busy ? "กำลังลบ…" : "ยืนยันลบ"}</button>
        </div>
      </div>
    </div>
  );
}

function UsersView() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [editing, setEditing] = useState(null);   // {username} | "new" | null
  const [confirm, setConfirm] = useState(null);    // {username} | null
  const [delBusy, setDelBusy] = useState(false);
  const [delErr, setDelErr] = useState("");

  const load = async () => {
    setLoading(true);
    try {
      const r = await adminFetch("/api/admin/users");
      const data = await r.json().catch(() => ({}));
      if (r.ok && data.ok) setUsers(data.users || []);
    } catch (e) {}
    setLoading(false);
  };
  useEffect(() => { load(); }, []);

  const doDelete = async (username) => {
    setDelBusy(true); setDelErr("");
    try {
      const r = await adminFetch("/api/admin/users/" + encodeURIComponent(username), { method: "DELETE" });
      const data = await r.json().catch(() => ({}));
      if (!r.ok || !data.ok) { setDelErr(data.error || "ลบไม่สำเร็จ"); setDelBusy(false); return; }
      setConfirm(null); setDelBusy(false); load();
    } catch (e) { setDelErr("เชื่อมต่อเซิร์ฟเวอร์ไม่ได้"); setDelBusy(false); }
  };

  return (
    <div className="scroll" style={{ flex: 1, padding: "4px 16px 160px" }}>
      {/* summary + add */}
      <div className="glass" style={{ borderRadius: 22, padding: "16px 18px", marginBottom: 14,
        background: "linear-gradient(135deg, oklch(0.96 0.03 220 / 0.7), oklch(0.96 0.03 175 / 0.6))" }}>
        <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 12 }}>
          <div>
            <div style={{ fontSize: 12.5, color: "var(--ink-soft)", fontWeight: 600, marginBottom: 4 }}>บัญชีผู้ดูแลระบบ</div>
            <div style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
              <span style={{ fontFamily: "var(--font-disp)", fontSize: 32, fontWeight: 700, lineHeight: 1, color: "var(--ink)", fontVariantNumeric: "tabular-nums" }}>{users.length}</span>
              <span style={{ fontSize: 12, color: "var(--ink-faint)" }}>บัญชี</span>
            </div>
          </div>
          <button onClick={() => setEditing("new")} style={{ display: "flex", alignItems: "center", gap: 7, height: 44, padding: "0 16px", borderRadius: 14,
            color: "#fff", fontSize: 14, fontWeight: 700, flex: "0 0 auto",
            background: "linear-gradient(120deg, var(--accent), var(--accent-2))", boxShadow: "0 10px 22px oklch(0.6 0.12 215 / 0.34)" }}>
            <Icon name="plus" size={18} /> เพิ่มผู้ใช้
          </button>
        </div>
      </div>

      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 4px 10px" }}>
        <div style={{ fontSize: 15, fontWeight: 700, color: "var(--ink)" }}>รายชื่อผู้ดูแล</div>
        <Chip>{users.length} บัญชี</Chip>
      </div>

      {loading ? (
        <div className="glass" style={{ borderRadius: 18, padding: "26px 16px", textAlign: "center", color: "var(--ink-faint)", fontSize: 13.5 }}>
          กำลังโหลด…
        </div>
      ) : users.length === 0 ? (
        <div className="glass" style={{ borderRadius: 18, padding: "26px 16px", textAlign: "center", color: "var(--ink-faint)", fontSize: 13.5 }}>
          ยังไม่มีบัญชีผู้ดูแล
        </div>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
          {users.map((u) => (
            <div key={u.username} className="glass" style={{ borderRadius: 16, padding: "10px 12px", display: "flex", alignItems: "center", gap: 12 }}>
              <div style={{ width: 46, height: 46, borderRadius: 13, flex: "0 0 auto", display: "grid", placeItems: "center",
                color: "var(--accent-deep)", background: "oklch(0.93 0.04 215 / 0.7)" }}><Icon name="user" size={20} /></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 14.5, fontWeight: 600, color: "var(--ink)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{u.username}</div>
                <div style={{ fontSize: 11.5, color: "var(--ink-faint)", marginTop: 1 }}>สร้างเมื่อ {u.created_at ? fmtThaiDate(u.created_at) : "—"}</div>
              </div>
              <button onClick={() => setEditing({ username: u.username })} aria-label="เปลี่ยนรหัส"
                style={{ width: 38, height: 38, borderRadius: 11, flex: "0 0 auto", display: "grid", placeItems: "center",
                  color: "var(--accent-deep)", background: "oklch(1 0 0 / 0.6)", border: "1px solid var(--glass-line)" }}>
                <Icon name="edit" size={18} />
              </button>
              <button onClick={() => { setDelErr(""); setConfirm({ username: u.username }); }} aria-label="ลบ"
                style={{ width: 38, height: 38, borderRadius: 11, flex: "0 0 auto", display: "grid", placeItems: "center",
                  color: "oklch(0.55 0.16 25)", background: "oklch(1 0 0 / 0.6)", border: "1px solid var(--glass-line)" }}>
                <Icon name="trash" size={17} />
              </button>
            </div>
          ))}
        </div>
      )}

      <div style={{ display: "flex", alignItems: "flex-start", gap: 7, marginTop: 14, padding: "0 4px", fontSize: 11.5, color: "var(--ink-faint)", lineHeight: 1.5 }}>
        <Icon name="lock" size={13} /> รหัสผ่านถูกเก็บแบบเข้ารหัส (SHA-256) — ดูรหัสเดิมไม่ได้ หากลืมให้ตั้งรหัสใหม่
      </div>

      {editing && (
        <UserEditor initial={editing === "new" ? null : editing}
          onSaved={() => { setEditing(null); load(); }}
          onCancel={() => setEditing(null)} />
      )}
      {confirm && (
        <ConfirmDeleteUser username={confirm.username} busy={delBusy} err={delErr}
          onConfirm={doDelete} onCancel={() => setConfirm(null)} />
      )}
    </div>
  );
}

Object.assign(window, { UsersView });
