import { useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import {
  Shield, Users, Image as ImageIcon, Key, Trash2, Crown, CrownIcon,
  Settings, RefreshCw, Eye, EyeOff, ChevronDown, ChevronUp, AlertCircle,
  CheckCircle, Lock, Zap, Bookmark, Clock, Terminal, Copy, Check,
  Database, Plus, Pencil, X, ToggleLeft, ToggleRight, UserPlus, Activity,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { useToast } from "@/hooks/use-toast";
import { useLang } from "@/contexts/LanguageContext";
import { useAuth } from "@/contexts/AuthContext";
import { useLocation } from "wouter";

const BASE = import.meta.env.BASE_URL.replace(/\/$/, "");
const API_BASE = `${BASE}/api/admin`;

interface Stats { users: number; images: number; apiKeys: number }
interface AdminUser {
  id: number; email: string; displayName: string | null;
  isAdmin: boolean; createdAt: string;
}
interface ConfigRow { id: number; key: string; value: string; updatedAt: string }

async function fetchStats(): Promise<Stats> {
  const r = await fetch(`${API_BASE}/stats`, { credentials: "include" });
  if (!r.ok) throw new Error("Forbidden");
  return r.json();
}
async function fetchUsers(): Promise<AdminUser[]> {
  const r = await fetch(`${API_BASE}/users`, { credentials: "include" });
  if (!r.ok) throw new Error("Forbidden");
  return (await r.json()).users;
}
async function fetchConfig(): Promise<ConfigRow[]> {
  const r = await fetch(`${API_BASE}/config`, { credentials: "include" });
  if (!r.ok) throw new Error("Forbidden");
  return (await r.json()).config;
}

function StatCard({ icon: Icon, label, value, color }: { icon: any; label: string; value: number; color: string }) {
  return (
    <div className="flex items-center gap-4 p-5 rounded-xl border border-border/60 bg-card/50">
      <div className={`w-12 h-12 rounded-xl flex items-center justify-center ${color}`}>
        <Icon className="w-6 h-6" />
      </div>
      <div>
        <div className="text-2xl font-bold text-foreground">{value.toLocaleString()}</div>
        <div className="text-sm text-muted-foreground">{label}</div>
      </div>
    </div>
  );
}

function UserRow({ user, currentUserId, onUpdate, onDelete }: {
  user: AdminUser;
  currentUserId: number;
  onUpdate: (id: number, data: Record<string, unknown>) => Promise<void>;
  onDelete: (id: number) => Promise<void>;
}) {
  const { toast } = useToast();
  const { t } = useLang();
  const [expanded, setExpanded] = useState(false);
  const [newPass, setNewPass] = useState("");
  const [showPass, setShowPass] = useState(false);
  const [busy, setBusy] = useState(false);
  const isSelf = user.id === currentUserId;

  const handleToggleAdmin = async () => {
    if (isSelf) return;
    setBusy(true);
    try {
      await onUpdate(user.id, { isAdmin: !user.isAdmin });
      toast({ description: t.adminUserUpdated });
    } catch { toast({ variant: "destructive", description: t.adminError }); }
    setBusy(false);
  };

  const handleResetPass = async () => {
    if (!newPass || newPass.length < 6) {
      toast({ variant: "destructive", description: t.adminPassTooShort });
      return;
    }
    setBusy(true);
    try {
      await onUpdate(user.id, { password: newPass });
      setNewPass("");
      toast({ description: t.adminPassReset });
    } catch { toast({ variant: "destructive", description: t.adminError }); }
    setBusy(false);
  };

  const handleDelete = async () => {
    if (!confirm(t.adminDeleteConfirm)) return;
    setBusy(true);
    try {
      await onDelete(user.id);
      toast({ description: t.adminUserDeleted });
    } catch { toast({ variant: "destructive", description: t.adminError }); }
    setBusy(false);
  };

  return (
    <div className="border border-border/50 rounded-xl overflow-hidden">
      <div className="flex items-center gap-3 p-3 hover:bg-card/60 transition-colors">
        <div className="w-8 h-8 rounded-full bg-primary/15 border border-primary/20 flex items-center justify-center flex-shrink-0 text-xs font-bold text-primary">
          {(user.displayName || user.email)[0].toUpperCase()}
        </div>
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2">
            <span className="text-sm font-medium text-foreground truncate">{user.displayName || user.email.split("@")[0]}</span>
            {user.isAdmin && <Crown className="w-3.5 h-3.5 text-yellow-400 flex-shrink-0" />}
            {isSelf && <Badge variant="outline" className="text-[10px] px-1 py-0">{t.adminYou}</Badge>}
          </div>
          <div className="text-xs text-muted-foreground truncate">{user.email}</div>
        </div>
        <div className="text-xs text-muted-foreground hidden sm:block">
          {new Date(user.createdAt).toLocaleDateString()}
        </div>
        <button
          onClick={() => setExpanded(!expanded)}
          className="p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-secondary transition-colors"
        >
          {expanded ? <ChevronUp className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
        </button>
      </div>
      {expanded && (
        <div className="border-t border-border/40 p-4 bg-black/10 space-y-3">
          <div className="flex flex-wrap gap-2">
            {!isSelf && (
              <Button
                size="sm"
                variant="outline"
                disabled={busy}
                onClick={handleToggleAdmin}
                className={user.isAdmin ? "border-yellow-500/40 text-yellow-400 hover:bg-yellow-500/10" : ""}
              >
                <CrownIcon className="w-3.5 h-3.5 mr-1.5" />
                {user.isAdmin ? t.adminRevokeAdmin : t.adminGrantAdmin}
              </Button>
            )}
            {!isSelf && (
              <Button
                size="sm"
                variant="outline"
                disabled={busy}
                onClick={handleDelete}
                className="border-destructive/30 text-destructive hover:bg-destructive/10"
              >
                <Trash2 className="w-3.5 h-3.5 mr-1.5" />
                {t.adminDeleteUser}
              </Button>
            )}
          </div>
          <div className="flex gap-2 items-end">
            <div className="flex-1 space-y-1">
              <label className="text-xs text-muted-foreground">{t.adminResetPass}</label>
              <div className="relative">
                <Input
                  type={showPass ? "text" : "password"}
                  value={newPass}
                  onChange={(e) => setNewPass(e.target.value)}
                  placeholder={t.adminNewPassPlaceholder}
                  className="bg-background/50 border-border/60 pr-9 text-sm"
                />
                <button
                  type="button"
                  onClick={() => setShowPass(!showPass)}
                  className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
                >
                  {showPass ? <EyeOff className="w-3.5 h-3.5" /> : <Eye className="w-3.5 h-3.5" />}
                </button>
              </div>
            </div>
            <Button size="sm" disabled={busy || !newPass} onClick={handleResetPass}>
              {t.adminResetPassBtn}
            </Button>
          </div>
        </div>
      )}
    </div>
  );
}

const BASE_URL = import.meta.env.BASE_URL.replace(/\/$/, "");

function TokenGuide() {
  const { t } = useLang();
  const [open, setOpen] = useState(false);

  return (
    <div className="rounded-xl border border-blue-500/30 bg-blue-500/5 p-4 space-y-3">
      <div className="flex items-start justify-between gap-3">
        <div>
          <h3 className="text-sm font-semibold text-blue-300 flex items-center gap-2">
            <span>📖</span> {t.adminGuideTitle}
          </h3>
          <p className="text-xs text-muted-foreground mt-0.5">{t.adminGuideSubtitle}</p>
        </div>
        <button
          onClick={() => setOpen(!open)}
          className="text-xs px-3 py-1.5 rounded-lg border border-blue-500/40 text-blue-400 hover:bg-blue-500/10 transition-colors flex-shrink-0"
        >
          {open ? t.adminGuideHide : t.adminGuideShow}
        </button>
      </div>

      {open && (
        <div className="space-y-4">
          <ol className="space-y-2 text-sm text-muted-foreground">
            {(t.adminGuideSteps as string[]).map((step, i) => (
              <li key={i} className="flex gap-3">
                <span className="flex-shrink-0 w-5 h-5 rounded-full bg-blue-500/20 border border-blue-500/40 text-blue-300 text-xs flex items-center justify-center font-bold">
                  {i + 1}
                </span>
                <span dangerouslySetInnerHTML={{ __html: step }} />
              </li>
            ))}
          </ol>
          <div className="rounded-lg overflow-hidden border border-border/40">
            <img
              src={`${BASE_URL}/token-guide.png`}
              alt="Token guide screenshot"
              className="w-full h-auto"
            />
          </div>
          <p className="text-xs text-muted-foreground/70 italic">{t.adminGuideNote}</p>
        </div>
      )}
    </div>
  );
}


type AccountRow = {
  id: number;
  label: string;
  tokenPreview: string | null;
  hasRefreshToken: boolean;
  isActive: boolean;
  lastUsedAt: string | null;
  createdAt: string;
};

type AddMode = "console" | "bookmark" | "manual";

function AccountPoolCard() {
  const { toast } = useToast();
  const { t } = useLang();
  const BASE_URL = import.meta.env.BASE_URL.replace(/\/$/, "");

  // Account list state
  const [editingId, setEditingId] = useState<number | null>(null);
  const [editLabel, setEditLabel] = useState("");

  // "Add account" panel state
  const [addMode, setAddMode] = useState<AddMode | null>(null);

  // Manual add state
  const [newLabel, setNewLabel] = useState("");
  const [newBearer, setNewBearer] = useState("");
  const [newRefresh, setNewRefresh] = useState("");
  const [adding, setAdding] = useState(false);

  // Console / bookmarklet sync state
  const [syncLabel, setSyncLabel] = useState("");
  const [otp, setOtp] = useState<string | null>(null);
  const [expiresAt, setExpiresAt] = useState<number | null>(null);
  const [generating, setGenerating] = useState(false);
  const [copied, setCopied] = useState(false);
  const [bookmarkMode, setBookmarkMode] = useState<"console" | "bookmark">("console");

  const receiveUrl = `${window.location.origin}${BASE_URL}/api/public/receive-tokens`;

  const { data: accounts = [], refetch } = useQuery<AccountRow[]>({
    queryKey: ["gemini-accounts"],
    queryFn: async () => {
      const r = await fetch(`${BASE_URL}/api/admin/accounts`, { credentials: "include" });
      if (!r.ok) return [];
      return r.json();
    },
  });

  // ── Console / bookmarklet helpers ──────────────────────────────
  const buildCode = (otpVal: string, label: string) => {
    const safeLabel = (label || t.poolUnnamed).replace(/'/g, "\\'");
    return `(function(){var t=null;for(var k in localStorage){try{var v=JSON.parse(localStorage.getItem(k)||'');if(v&&v.access_token&&v.refresh_token){t=v;break;}}catch(e){}}if(!t){var at=localStorage.getItem('access_token'),rt=localStorage.getItem('refresh_token');if(at&&rt)t={access_token:at,refresh_token:rt};}if(!t){alert('找不到 Token，請先登入 geminigen.ai');return;}fetch('${receiveUrl}',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({otp:'${otpVal}',access_token:t.access_token,refresh_token:t.refresh_token,label:'${safeLabel}'})}).then(function(r){return r.json()}).then(function(d){if(d.success)alert('✅ Token 已成功同步到星光工坊！');else alert('❌ 同步失敗：'+(d.error||'未知錯誤'));}).catch(function(){alert('❌ 無法連接星光工坊');});})();`;
  };
  const buildBookmarklet = (otpVal: string, label: string) =>
    `javascript:${encodeURIComponent(buildCode(otpVal, label))}`;

  const handleGenerateOtp = async () => {
    setGenerating(true);
    setCopied(false);
    try {
      const r = await fetch(`${BASE_URL}/api/admin/bookmarklet-otp`, { method: "POST", credentials: "include" });
      const data = await r.json();
      if (!r.ok) throw new Error(data.error || "Failed");
      setOtp(data.otp);
      setExpiresAt(Date.now() + data.expiresInSeconds * 1000);
    } catch (e: any) {
      toast({ variant: "destructive", description: e.message || t.poolGenFailed });
    }
    setGenerating(false);
  };

  const handleCopyCode = async () => {
    if (!otp) return;
    try {
      await navigator.clipboard.writeText(buildCode(otp, syncLabel));
      setCopied(true);
      toast({ description: t.poolCopySuccess });
      setTimeout(() => setCopied(false), 3000);
    } catch {
      toast({ variant: "destructive", description: t.poolCopyFailed });
    }
  };

  // ── Account CRUD ───────────────────────────────────────────────
  const handleAdd = async () => {
    if (!newBearer.trim()) return;
    setAdding(true);
    try {
      const r = await fetch(`${BASE_URL}/api/admin/accounts`, {
        method: "POST", credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ label: newLabel || t.poolUnnamed, bearerToken: newBearer.trim(), refreshToken: newRefresh.trim() || undefined }),
      });
      if (!r.ok) throw new Error((await r.json()).error || "Failed");
      toast({ description: t.poolAddSuccess });
      setNewLabel(""); setNewBearer(""); setNewRefresh("");
      setAddMode(null);
      refetch();
    } catch (e: any) {
      toast({ variant: "destructive", description: e.message });
    }
    setAdding(false);
  };

  const handleToggle = async (id: number) => {
    await fetch(`${BASE_URL}/api/admin/accounts/${id}/toggle`, { method: "PATCH", credentials: "include" });
    refetch();
  };

  const handleDelete = async (id: number) => {
    await fetch(`${BASE_URL}/api/admin/accounts/${id}`, { method: "DELETE", credentials: "include" });
    toast({ description: t.poolDeleteSuccess });
    refetch();
  };

  const handleRename = async (id: number) => {
    if (!editLabel.trim()) return;
    await fetch(`${BASE_URL}/api/admin/accounts/${id}/label`, {
      method: "PATCH", credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ label: editLabel }),
    });
    setEditingId(null);
    refetch();
  };

  const activeCount = accounts.filter((a) => a.isActive).length;
  const isExpired = expiresAt !== null && Date.now() > expiresAt;
  const minutesLeft = expiresAt ? Math.max(0, Math.floor((expiresAt - Date.now()) / 60000)) : 0;

  return (
    <div className="rounded-xl border border-blue-500/30 bg-blue-500/5 p-4 space-y-4">
      {/* ── Header ── */}
      <div className="flex items-start justify-between gap-3">
        <div className="flex items-start gap-3">
          <div className="w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0 bg-blue-500/20 border border-blue-500/30">
            <Database className="w-4 h-4 text-blue-400" />
          </div>
          <div>
            <h3 className="text-sm font-semibold text-blue-300 flex items-center gap-2">
              {t.poolTitle}
              <span className="text-[10px] font-normal px-1.5 py-0.5 rounded bg-blue-500/20 text-blue-400 border border-blue-500/30">
                {activeCount}/{accounts.length}
              </span>
            </h3>
            <p className="text-xs text-muted-foreground mt-0.5">
              {t.poolDesc}
            </p>
          </div>
        </div>
        <Button size="sm" variant="ghost" className="h-7 px-2 text-xs" onClick={() => refetch()}>
          <RefreshCw className="w-3 h-3" />
        </Button>
      </div>

      {/* ── Account list ── */}
      {accounts.length === 0 ? (
        <div className="py-4 flex flex-col items-center gap-1.5 text-muted-foreground">
          <UserPlus className="w-7 h-7 opacity-30" />
          <p className="text-sm">{t.poolEmpty}</p>
          <p className="text-xs opacity-50">{t.poolEmptyDesc}</p>
        </div>
      ) : (
        <div className="space-y-2">
          {accounts.map((acc) => (
            <div key={acc.id} className={`rounded-lg border p-3 transition-colors ${acc.isActive ? "border-blue-500/30 bg-blue-500/5" : "border-border/30 bg-black/10 opacity-60"}`}>
              <div className="flex items-center gap-3">
                <div className={`w-2 h-2 rounded-full flex-shrink-0 ${acc.isActive ? "bg-green-400 shadow-[0_0_6px_rgb(74,222,128)]" : "bg-muted-foreground/30"}`} />
                <div className="flex-1 min-w-0">
                  {editingId === acc.id ? (
                    <div className="flex gap-1.5">
                      <input value={editLabel} onChange={(e) => setEditLabel(e.target.value)}
                        onKeyDown={(e) => { if (e.key === "Enter") handleRename(acc.id); if (e.key === "Escape") setEditingId(null); }}
                        className="flex-1 px-2 py-0.5 rounded border border-blue-500/40 bg-black/30 text-sm text-foreground focus:outline-none" autoFocus />
                      <button onClick={() => handleRename(acc.id)} className="text-green-400 hover:text-green-300"><Check className="w-3.5 h-3.5" /></button>
                      <button onClick={() => setEditingId(null)} className="text-muted-foreground hover:text-foreground"><X className="w-3.5 h-3.5" /></button>
                    </div>
                  ) : (
                    <div className="flex items-center gap-1.5">
                      <span className="text-sm font-medium truncate">{acc.label || t.poolUnnamed}</span>
                      <button onClick={() => { setEditingId(acc.id); setEditLabel(acc.label); }} className="text-muted-foreground/40 hover:text-blue-400 transition-colors">
                        <Pencil className="w-3 h-3" />
                      </button>
                    </div>
                  )}
                  <div className="flex items-center gap-2 mt-0.5">
                    <span className="text-[10px] font-mono text-muted-foreground/60">{acc.tokenPreview || "—"}</span>
                    {acc.hasRefreshToken && <span className="text-[9px] px-1 rounded bg-green-500/15 text-green-400 border border-green-500/20">{t.poolHasRefresh}</span>}
                  </div>
                </div>
                <div className="text-right hidden sm:block">
                  {acc.lastUsedAt ? (
                    <div className="flex items-center gap-1 text-[10px] text-muted-foreground">
                      <Activity className="w-2.5 h-2.5" />
                      {new Date(acc.lastUsedAt).toLocaleString("zh-TW", { month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" })}
                    </div>
                  ) : <span className="text-[10px] text-muted-foreground/40">{t.poolNeverUsed}</span>}
                </div>
                <div className="flex items-center gap-1">
                  <button onClick={() => handleToggle(acc.id)} title={acc.isActive ? t.poolDisable : t.poolEnable} className="p-1 rounded hover:bg-white/10 transition-colors">
                    {acc.isActive ? <ToggleRight className="w-5 h-5 text-green-400" /> : <ToggleLeft className="w-5 h-5 text-muted-foreground" />}
                  </button>
                  <button onClick={() => handleDelete(acc.id)} title={t.poolDelete} className="p-1 rounded text-muted-foreground/50 hover:text-red-400 transition-colors">
                    <Trash2 className="w-3.5 h-3.5" />
                  </button>
                </div>
              </div>
            </div>
          ))}
          <p className="text-[10px] text-muted-foreground/40 text-center pt-1">
            {t.poolLRUNote}
          </p>
        </div>
      )}

      {/* ── Add account section ── */}
      <div className="border-t border-blue-500/20 pt-3 space-y-3">
        {/* Mode picker */}
        <p className="text-[11px] font-semibold text-blue-300/70 uppercase tracking-wide">{t.poolAddTitle}</p>
        <div className="grid grid-cols-3 gap-2">
          {/* Console sync */}
          <button
            onClick={() => { if (addMode === "console") { setAddMode(null); } else { setAddMode("console"); setBookmarkMode("console"); } }}
            className={`flex flex-col items-center gap-1.5 rounded-lg border p-2.5 text-xs transition-colors ${addMode === "console" ? "border-amber-500/50 bg-amber-500/15 text-amber-300" : "border-border/40 bg-black/20 text-muted-foreground hover:border-amber-500/30 hover:text-amber-400"}`}
          >
            <Terminal className="w-4 h-4" />
            <span>{t.poolBtnConsole}</span>
            <span className="text-[9px] opacity-60">{t.poolBtnConsoleDesc}</span>
          </button>
          {/* Bookmarklet */}
          <button
            onClick={() => { if (addMode === "bookmark") { setAddMode(null); } else { setAddMode("bookmark"); setBookmarkMode("bookmark"); } }}
            className={`flex flex-col items-center gap-1.5 rounded-lg border p-2.5 text-xs transition-colors ${addMode === "bookmark" ? "border-amber-500/50 bg-amber-500/15 text-amber-300" : "border-border/40 bg-black/20 text-muted-foreground hover:border-amber-500/30 hover:text-amber-400"}`}
          >
            <Bookmark className="w-4 h-4" />
            <span>{t.poolBtnBookmark}</span>
            <span className="text-[9px] opacity-60">{t.poolBtnBookmarkDesc}</span>
          </button>
          {/* Manual */}
          <button
            onClick={() => setAddMode(addMode === "manual" ? null : "manual")}
            className={`flex flex-col items-center gap-1.5 rounded-lg border p-2.5 text-xs transition-colors ${addMode === "manual" ? "border-blue-500/50 bg-blue-500/15 text-blue-300" : "border-border/40 bg-black/20 text-muted-foreground hover:border-blue-500/30 hover:text-blue-400"}`}
          >
            <Plus className="w-4 h-4" />
            <span>{t.poolBtnManual}</span>
            <span className="text-[9px] opacity-60">{t.poolBtnManualDesc}</span>
          </button>
        </div>

        {/* ── Console sync panel ── */}
        {(addMode === "console" || addMode === "bookmark") && (
          <div className="rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 space-y-3">
            {/* Sub-mode toggle (console vs bookmark) */}
            <div className="flex rounded-lg overflow-hidden border border-amber-500/30 text-[11px]">
              <button
                onClick={() => setBookmarkMode("console")}
                className={`flex-1 flex items-center justify-center gap-1.5 py-1.5 transition-colors ${bookmarkMode === "console" ? "bg-amber-500/20 text-amber-300 font-medium" : "text-muted-foreground hover:text-foreground"}`}
              >
                <Terminal className="w-3 h-3" /> {t.poolModeConsole}
              </button>
              <button
                onClick={() => setBookmarkMode("bookmark")}
                className={`flex-1 flex items-center justify-center gap-1.5 py-1.5 transition-colors ${bookmarkMode === "bookmark" ? "bg-amber-500/20 text-amber-300 font-medium" : "text-muted-foreground hover:text-foreground"}`}
              >
                <Bookmark className="w-3 h-3" /> {t.poolModeBookmark}
              </button>
            </div>

            {/* Account label */}
            <div className="space-y-1">
              <label className="text-[11px] text-amber-300/80 font-medium">{t.poolAccountLabel}</label>
              <input
                value={syncLabel}
                onChange={(e) => setSyncLabel(e.target.value)}
                placeholder={t.poolAccountPlaceholder}
                className="w-full px-3 py-1.5 rounded-lg border border-amber-500/30 bg-black/20 text-sm text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:border-amber-500/60"
              />
            </div>

            {/* Generate OTP / show code */}
            {(!otp || isExpired) ? (
              <Button size="sm" className="w-full bg-amber-600 hover:bg-amber-500 text-white" disabled={generating} onClick={handleGenerateOtp}>
                {generating
                  ? <><RefreshCw className="w-3.5 h-3.5 animate-spin mr-2" />{t.poolGenerating}</>
                  : <><Terminal className="w-3.5 h-3.5 mr-2" />{t.poolGenerate}</>}
              </Button>
            ) : (
              <div className="space-y-3">
                {/* Expiry */}
                <div className="flex items-center justify-between">
                  <div className="flex items-center gap-1.5 text-[11px] text-amber-400/80">
                    <Clock className="w-3 h-3" />
                    {t.poolExpiryPrefix} {minutesLeft} {t.poolExpirySuffix}
                  </div>
                  <button onClick={handleGenerateOtp} className="text-[11px] text-muted-foreground hover:text-amber-400 flex items-center gap-1 transition-colors">
                    <RefreshCw className="w-3 h-3" />{t.poolRegenerate}
                  </button>
                </div>

                {bookmarkMode === "console" ? (
                  <>
                    {/* Steps */}
                    <ol className="text-[11px] text-muted-foreground space-y-1.5">
                      <li className="flex gap-2"><span className="w-4 h-4 rounded-full bg-amber-500/20 text-amber-300 text-[9px] flex items-center justify-center font-bold flex-shrink-0">1</span>{t.poolConsoleStep1.replace("geminigen.ai", "")}<a href="https://geminigen.ai" target="_blank" rel="noreferrer" className="text-amber-400 underline mx-1">geminigen.ai</a></li>
                      <li className="flex gap-2"><span className="w-4 h-4 rounded-full bg-amber-500/20 text-amber-300 text-[9px] flex items-center justify-center font-bold flex-shrink-0">2</span>{t.poolConsoleStep2}</li>
                      <li className="flex gap-2"><span className="w-4 h-4 rounded-full bg-amber-500/20 text-amber-300 text-[9px] flex items-center justify-center font-bold flex-shrink-0">3</span>{t.poolConsoleStep3}</li>
                      <li className="flex gap-2"><span className="w-4 h-4 rounded-full bg-amber-500/20 text-amber-300 text-[9px] flex items-center justify-center font-bold flex-shrink-0">4</span>{t.poolConsoleStep4}</li>
                    </ol>
                    {/* Code block */}
                    <div className="rounded-lg border border-border/40 bg-black/50 overflow-hidden">
                      <div className="flex items-center justify-between px-3 py-1.5 border-b border-border/30 bg-black/30">
                        <span className="text-[10px] text-muted-foreground font-mono">JavaScript Console</span>
                        <button
                          onClick={handleCopyCode}
                          className={`flex items-center gap-1.5 text-[10px] px-2 py-1 rounded transition-all ${copied ? "text-green-400 bg-green-500/10" : "text-amber-400 hover:bg-amber-500/10"}`}
                        >
                          {copied ? <><Check className="w-3 h-3" />{t.poolCopied}</> : <><Copy className="w-3 h-3" />{t.poolCopyCode}</>}
                        </button>
                      </div>
                      <pre className="p-3 text-[10px] font-mono text-emerald-300/80 whitespace-pre-wrap break-all leading-relaxed max-h-24 overflow-y-auto">
                        {buildCode(otp!, syncLabel)}
                      </pre>
                    </div>
                    <Button size="sm" className="w-full bg-amber-600 hover:bg-amber-500 text-white" onClick={handleCopyCode}>
                      {copied ? <><Check className="w-3.5 h-3.5 mr-2" />{t.poolCopiedBtn}</> : <><Copy className="w-3.5 h-3.5 mr-2" />{t.poolCopyBtn}</>}
                    </Button>
                  </>
                ) : (
                  <>
                    <ol className="text-[11px] text-muted-foreground space-y-1.5">
                      <li className="flex gap-2"><span className="w-4 h-4 rounded-full bg-amber-500/20 text-amber-300 text-[9px] flex items-center justify-center font-bold flex-shrink-0">1</span>{t.poolBookmarkStep1}</li>
                      <li className="flex gap-2"><span className="w-4 h-4 rounded-full bg-amber-500/20 text-amber-300 text-[9px] flex items-center justify-center font-bold flex-shrink-0">2</span>{t.poolBookmarkStep2.replace("geminigen.ai", "")}<a href="https://geminigen.ai" target="_blank" rel="noreferrer" className="text-amber-400 underline mx-1">geminigen.ai</a></li>
                      <li className="flex gap-2"><span className="w-4 h-4 rounded-full bg-amber-500/20 text-amber-300 text-[9px] flex items-center justify-center font-bold flex-shrink-0">3</span>{t.poolBookmarkStep3}</li>
                    </ol>
                    <a
                      href={buildBookmarklet(otp!, syncLabel)}
                      draggable
                      onClick={(e) => { e.preventDefault(); toast({ description: t.poolDragToast }); }}
                      className="flex items-center justify-center gap-2 w-full px-4 py-2.5 rounded-lg border-2 border-dashed border-amber-500/50 bg-amber-500/10 text-amber-300 text-sm font-medium hover:bg-amber-500/20 transition-colors cursor-grab active:cursor-grabbing select-none"
                    >
                      <Bookmark className="w-4 h-4" />
                      {t.poolBookmarkBtnText}
                    </a>
                    <p className="text-[10px] text-muted-foreground/50 text-center">{t.poolBookmarkDragHint}</p>
                  </>
                )}
              </div>
            )}
          </div>
        )}

        {/* ── Manual add panel ── */}
        {addMode === "manual" && (
          <div className="rounded-lg border border-blue-500/30 bg-black/20 p-3 space-y-2">
            <p className="text-[11px] font-medium text-blue-300/80">{t.poolManualTitle}</p>
            <input
              value={newLabel} onChange={(e) => setNewLabel(e.target.value)}
              placeholder={t.poolManualNamePlaceholder}
              className="w-full px-3 py-1.5 rounded border border-border/40 bg-black/30 text-sm text-foreground placeholder:text-muted-foreground/50 focus:outline-none"
            />
            <input
              value={newBearer} onChange={(e) => setNewBearer(e.target.value)}
              placeholder={t.poolManualBearerPlaceholder}
              className="w-full px-3 py-1.5 rounded border border-border/40 bg-black/30 text-sm font-mono text-foreground placeholder:text-muted-foreground/50 focus:outline-none"
            />
            <input
              value={newRefresh} onChange={(e) => setNewRefresh(e.target.value)}
              placeholder={t.poolManualRefreshPlaceholder}
              className="w-full px-3 py-1.5 rounded border border-border/40 bg-black/30 text-sm font-mono text-foreground placeholder:text-muted-foreground/50 focus:outline-none"
            />
            <div className="flex gap-2">
              <Button size="sm" className="flex-1 bg-blue-600 hover:bg-blue-500 text-white" disabled={adding || !newBearer.trim()} onClick={handleAdd}>
                {adding ? <RefreshCw className="w-3 h-3 animate-spin mr-1" /> : <Plus className="w-3 h-3 mr-1" />}{t.poolManualAddBtn}
              </Button>
              <Button size="sm" variant="ghost" onClick={() => setAddMode(null)}>{t.poolCancel}</Button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function AutoRenewalCard() {
  const { toast } = useToast();
  const { t } = useLang();
  const qc = useQueryClient();
  const BASE_URL = import.meta.env.BASE_URL.replace(/\/$/, "");

  // Credential setup state
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [showPass, setShowPass] = useState(false);
  const [savingCreds, setSavingCreds] = useState(false);

  // Fetch credential status
  const { data: credStatus, refetch: refetchCreds } = useQuery({
    queryKey: ["credentialStatus"],
    queryFn: async () => {
      const r = await fetch(`${BASE_URL}/api/admin/credentials`, { credentials: "include" });
      if (!r.ok) return { configured: false, username: null };
      return r.json() as Promise<{ configured: boolean; username: string | null }>;
    },
  });

  const handleSaveCreds = async () => {
    if (!username.trim() || !password.trim()) {
      toast({ variant: "destructive", description: t.renewalRequireFields });
      return;
    }
    setSavingCreds(true);
    try {
      const r = await fetch(`${BASE_URL}/api/admin/credentials`, {
        method: "POST",
        credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ username: username.trim(), password: password.trim() }),
      });
      const data = await r.json();
      if (!r.ok) throw new Error(data.error || "Failed");
      setUsername(""); setPassword("");
      await refetchCreds();
      qc.invalidateQueries({ queryKey: ["adminConfig"] });
      qc.invalidateQueries({ queryKey: ["setupStatus"] });
      toast({ description: t.renewalSuccess });
    } catch (e: any) {
      toast({ variant: "destructive", description: e.message || t.renewalFailed });
    }
    setSavingCreds(false);
  };

  const handleDeleteCreds = async () => {
    await fetch(`${BASE_URL}/api/admin/credentials`, { method: "DELETE", credentials: "include" });
    await refetchCreds();
    toast({ description: t.renewalClearedCreds });
  };

  return (
    <div className="space-y-3">
      {/* Auto-renewal via credentials (recommended) */}
      <div className={`rounded-xl border p-4 space-y-3 ${credStatus?.configured ? "border-green-500/40 bg-green-500/5" : "border-primary/40 bg-primary/5"}`}>
        <div className="flex items-start gap-3">
          <div className={`w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0 ${credStatus?.configured ? "bg-green-500/20 border border-green-500/30" : "bg-primary/20 border border-primary/30"}`}>
            {credStatus?.configured ? <CheckCircle className="w-4 h-4 text-green-400" /> : <Zap className="w-4 h-4 text-primary" />}
          </div>
          <div className="flex-1">
            <h3 className={`text-sm font-semibold ${credStatus?.configured ? "text-green-300" : "text-primary"}`}>
              {credStatus?.configured ? t.renewalTitle : t.renewalSetupTitle}
            </h3>
            <p className="text-xs text-muted-foreground mt-0.5">
              {credStatus?.configured
                ? <>{credStatus.username && <span className="text-green-300/70 font-mono">{credStatus.username}</span>} — {t.renewalActiveDesc}</>
                : t.renewalInactiveDesc}
            </p>
          </div>
          {credStatus?.configured && (
            <Button size="sm" variant="ghost" className="text-xs text-muted-foreground h-7" onClick={handleDeleteCreds}>
              {t.renewalRemove}
            </Button>
          )}
        </div>

        {!credStatus?.configured && (
          <div className="space-y-2">
            <Input
              className="text-sm bg-background/50"
              placeholder={t.renewalEmailPlaceholder}
              value={username}
              onChange={(e) => setUsername(e.target.value)}
              autoComplete="off"
            />
            <div className="relative">
              <Input
                className="text-sm bg-background/50 pr-10"
                type={showPass ? "text" : "password"}
                placeholder={t.renewalPassPlaceholder}
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                autoComplete="new-password"
              />
              <button
                type="button"
                className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
                onClick={() => setShowPass(!showPass)}
              >
                {showPass ? <EyeOff className="w-3.5 h-3.5" /> : <Eye className="w-3.5 h-3.5" />}
              </button>
            </div>
            <p className="text-xs text-muted-foreground/70 flex items-center gap-1.5">
              <Lock className="w-3 h-3" />
              {t.renewalSecureNote}
            </p>
            <Button
              size="sm"
              className="w-full"
              disabled={!username.trim() || !password.trim() || savingCreds}
              onClick={handleSaveCreds}
            >
              {savingCreds ? <><RefreshCw className="w-3.5 h-3.5 animate-spin mr-2" />{t.renewalSaving}</> : t.renewalSaveBtn}
            </Button>
          </div>
        )}
      </div>

      {/* Manual refresh token fallback */}
      <details className="rounded-xl border border-border/40 overflow-hidden">
        <summary className="px-4 py-3 text-xs font-medium text-muted-foreground cursor-pointer hover:text-foreground hover:bg-secondary/30 transition-colors select-none">
          {t.renewalManualTitle}
        </summary>
        <div className="px-4 pb-4 pt-2 space-y-2 border-t border-border/40 bg-black/10">
          <p className="text-xs text-muted-foreground">{t.renewalManualDesc}</p>
          <ManualTokenInput qc={qc} baseUrl={BASE_URL} />
        </div>
      </details>
    </div>
  );
}

function ManualTokenInput({ qc, baseUrl }: { qc: any; baseUrl: string }) {
  const { toast } = useToast();
  const { t } = useLang();
  const [newToken, setNewToken] = useState("");
  const [saving, setSaving] = useState(false);

  const handleRenew = async () => {
    if (!newToken.trim() || newToken.trim().length < 20) {
      toast({ variant: "destructive", description: t.renewalManualInvalid });
      return;
    }
    setSaving(true);
    try {
      const r = await fetch(`${baseUrl}/api/admin/setup`, {
        method: "POST", credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ refreshToken: newToken.trim() }),
      });
      const data = await r.json();
      if (!r.ok) throw new Error(data.error || "Failed");
      qc.invalidateQueries({ queryKey: ["adminConfig"] });
      qc.invalidateQueries({ queryKey: ["setupStatus"] });
      setNewToken("");
      toast({ description: t.renewalManualSuccess });
    } catch (e: any) {
      toast({ variant: "destructive", description: e.message || t.renewalManualFailed });
    }
    setSaving(false);
  };

  return (
    <div className="flex gap-2">
      <Input
        className="flex-1 text-xs font-mono bg-background/50"
        placeholder={t.renewalManualPlaceholder}
        value={newToken}
        onChange={(e) => setNewToken(e.target.value)}
        spellCheck={false}
      />
      <Button size="sm" disabled={!newToken.trim() || saving} onClick={handleRenew} className="flex-shrink-0">
        {saving ? <RefreshCw className="w-3.5 h-3.5 animate-spin" /> : t.renewalManualBtn}
      </Button>
    </div>
  );
}

function QuickTokenUpdate() {
  const { toast } = useToast();
  const { t } = useLang();
  const qc = useQueryClient();
  const BASE_URL = import.meta.env.BASE_URL.replace(/\/$/, "");
  const [accessToken, setAccessToken] = useState("");
  const [capsolverKey, setCapsolverKey] = useState("");
  const [yescaptchaKey, setYescaptchaKey] = useState("");
  const [playwrightUrl, setPlaywrightUrl] = useState("");
  const [playwrightSecret, setPlaywrightSecret] = useState("");
  const [savingToken, setSavingToken] = useState(false);
  const [savingCapsolver, setSavingCapsolver] = useState(false);
  const [savingYescaptcha, setSavingYescaptcha] = useState(false);
  const [savingPlaywright, setSavingPlaywright] = useState(false);
  const [testingPlaywright, setTestingPlaywright] = useState(false);

  const saveConfig = async (key: string, value: string): Promise<boolean> => {
    const r = await fetch(`${BASE_URL}/api/admin/config`, {
      method: "PUT",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ key, value }),
    });
    const data = await r.json();
    if (!r.ok) throw new Error(data.error || "Failed");
    return true;
  };

  const handleSaveToken = async () => {
    const tok = accessToken.trim();
    if (tok.length < 20) return;
    setSavingToken(true);
    try {
      await saveConfig("access_token", tok);
      setAccessToken("");
      qc.invalidateQueries({ queryKey: ["adminConfig"] });
      toast({ description: t.adminTokenSuccess });
    } catch (e: any) {
      toast({ variant: "destructive", description: e.message || t.adminSaveFailed });
    }
    setSavingToken(false);
  };

  const handleSaveCapsolver = async () => {
    const key = capsolverKey.trim();
    if (!key) return;
    setSavingCapsolver(true);
    try {
      await saveConfig("capsolver_api_key", key);
      setCapsolverKey("");
      qc.invalidateQueries({ queryKey: ["adminConfig"] });
      toast({ description: t.adminCapSolverSuccess });
    } catch (e: any) {
      toast({ variant: "destructive", description: e.message || t.adminSaveFailed });
    }
    setSavingCapsolver(false);
  };

  const handleSaveYescaptcha = async () => {
    const key = yescaptchaKey.trim();
    if (!key) return;
    setSavingYescaptcha(true);
    try {
      await saveConfig("yescaptcha_api_key", key);
      setYescaptchaKey("");
      qc.invalidateQueries({ queryKey: ["adminConfig"] });
      toast({ description: t.adminYesCaptchaSuccess });
    } catch (e: any) {
      toast({ variant: "destructive", description: e.message || t.adminSaveFailed });
    }
    setSavingYescaptcha(false);
  };

  const handleSavePlaywright = async () => {
    const url = playwrightUrl.trim();
    if (!url) return;
    setSavingPlaywright(true);
    try {
      await saveConfig("playwright_solver_url", url);
      if (playwrightSecret.trim()) {
        await saveConfig("playwright_solver_secret", playwrightSecret.trim());
      }
      setPlaywrightUrl("");
      setPlaywrightSecret("");
      qc.invalidateQueries({ queryKey: ["adminConfig"] });
      toast({ description: t.adminPlaywrightSuccess });
    } catch (e: any) {
      toast({ variant: "destructive", description: e.message || t.adminSaveFailed });
    }
    setSavingPlaywright(false);
  };

  const handleTestPlaywright = async () => {
    const urlToTest = playwrightUrl.trim();
    if (!urlToTest) return;
    setTestingPlaywright(true);
    try {
      const headers: Record<string, string> = { "Content-Type": "application/json" };
      if (playwrightSecret.trim()) headers["X-Solver-Secret"] = playwrightSecret.trim();
      const r = await fetch(urlToTest, { method: "POST", headers, body: "{}", signal: AbortSignal.timeout(60000) });
      const data = await r.json();
      if (r.ok && data.token) {
        toast({ description: `✅ ${t.adminTestSuccess}：${data.token.substring(0, 20)}... (cached=${data.cached})` });
      } else {
        toast({ variant: "destructive", description: `${t.adminTestFailed}：${data.error || r.status}` });
      }
    } catch (e: any) {
      toast({ variant: "destructive", description: `${t.videoConnectionFailed}：${e.message}` });
    }
    setTestingPlaywright(false);
  };

  return (
    <div className="space-y-3">
      {/* Access Token */}
      <div className="rounded-xl border border-orange-500/40 bg-orange-500/5 p-4 space-y-3">
        <div className="flex items-start gap-3">
          <div className="w-8 h-8 rounded-lg bg-orange-500/20 border border-orange-500/30 flex items-center justify-center flex-shrink-0">
            <Key className="w-4 h-4 text-orange-400" />
          </div>
          <div>
            <h3 className="text-sm font-semibold text-orange-300">{t.adminTokenTitle}</h3>
            <p className="text-xs text-muted-foreground mt-0.5">
              {t.adminTokenDesc}
            </p>
          </div>
        </div>
        <div className="rounded-lg border border-border/40 bg-black/20 p-3 text-xs text-muted-foreground space-y-1">
          <p className="font-medium text-foreground/80">{t.adminTokenHowTo} <code className="bg-black/30 px-1 rounded">Authorization: Bearer eyJ...</code></p>
        </div>
        <div className="flex gap-2">
          <Input
            className="flex-1 text-xs font-mono bg-background/50"
            placeholder="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
            value={accessToken}
            onChange={(e) => setAccessToken(e.target.value)}
            spellCheck={false}
          />
          <Button
            size="sm"
            disabled={accessToken.trim().length < 20 || savingToken}
            onClick={handleSaveToken}
            className="bg-orange-500 hover:bg-orange-600 text-white shrink-0"
          >
            {savingToken ? <RefreshCw className="w-3.5 h-3.5 animate-spin" /> : t.adminTokenUpdate}
          </Button>
        </div>
      </div>

      {/* Playwright Solver */}
      <div className="rounded-xl border border-green-500/40 bg-green-500/5 p-4 space-y-3">
        <div className="flex items-start gap-3">
          <div className="w-8 h-8 rounded-lg bg-green-500/20 border border-green-500/30 flex items-center justify-center flex-shrink-0">
            <Zap className="w-4 h-4 text-green-400" />
          </div>
          <div>
            <h3 className="text-sm font-semibold text-green-300">{t.adminPlaywrightTitle}</h3>
            <p className="text-xs text-muted-foreground mt-0.5">
              {t.adminPlaywrightDesc}
            </p>
          </div>
        </div>
        <div className="rounded-lg border border-border/40 bg-black/20 p-3 text-xs text-muted-foreground space-y-1">
          <p className="font-medium text-foreground/80 mb-1">{t.adminPlaywrightStepsLabel}</p>
          <ol className="list-decimal list-inside space-y-0.5 pl-1">
            <li>{t.adminPlaywrightStep1}</li>
            <li><a href="https://vercel.com" target="_blank" rel="noopener noreferrer" className="text-green-400 underline">Vercel</a> — {t.adminPlaywrightStep2}</li>
            <li>{t.adminPlaywrightStep3}</li>
            <li>{t.adminPlaywrightStep4}</li>
          </ol>
        </div>
        <div className="space-y-2">
          <div className="flex gap-2">
            <Input
              className="flex-1 text-xs font-mono bg-background/50"
              placeholder="https://your-solver.vercel.app/api/solve"
              value={playwrightUrl}
              onChange={(e) => setPlaywrightUrl(e.target.value)}
              spellCheck={false}
            />
          </div>
          <div className="flex gap-2">
            <Input
              className="flex-1 text-xs font-mono bg-background/50"
              placeholder={t.adminPlaywrightSecretPlaceholder}
              value={playwrightSecret}
              onChange={(e) => setPlaywrightSecret(e.target.value)}
              spellCheck={false}
              type="password"
            />
          </div>
          <div className="flex gap-2">
            <Button
              size="sm"
              variant="outline"
              disabled={playwrightUrl.trim().length < 10 || testingPlaywright}
              onClick={handleTestPlaywright}
              className="border-green-500/40 text-green-300 hover:bg-green-500/10 shrink-0"
            >
              {testingPlaywright ? <RefreshCw className="w-3.5 h-3.5 animate-spin mr-1" /> : null}
              {t.adminTestConn}
            </Button>
            <Button
              size="sm"
              disabled={playwrightUrl.trim().length < 10 || savingPlaywright}
              onClick={handleSavePlaywright}
              className="bg-green-600 hover:bg-green-700 text-white shrink-0"
            >
              {savingPlaywright ? <RefreshCw className="w-3.5 h-3.5 animate-spin" /> : t.adminSave}
            </Button>
          </div>
        </div>
      </div>

      {/* YesCaptcha API Key */}
      <div className="rounded-xl border border-purple-500/40 bg-purple-500/5 p-4 space-y-3">
        <div className="flex items-start gap-3">
          <div className="w-8 h-8 rounded-lg bg-purple-500/20 border border-purple-500/30 flex items-center justify-center flex-shrink-0">
            <CheckCircle className="w-4 h-4 text-purple-400" />
          </div>
          <div>
            <h3 className="text-sm font-semibold text-purple-300">{t.adminYesCaptchaTitle}</h3>
            <p className="text-xs text-muted-foreground mt-0.5">
              {t.adminYesCaptchaDesc}
            </p>
          </div>
        </div>
        <div className="rounded-lg border border-border/40 bg-black/20 p-3 text-xs text-muted-foreground">
          <p>{t.adminYesCaptchaHowTo}</p>
        </div>
        <div className="flex gap-2">
          <Input
            className="flex-1 text-xs font-mono bg-background/50"
            placeholder="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
            value={yescaptchaKey}
            onChange={(e) => setYescaptchaKey(e.target.value)}
            spellCheck={false}
          />
          <Button
            size="sm"
            disabled={yescaptchaKey.trim().length < 10 || savingYescaptcha}
            onClick={handleSaveYescaptcha}
            className="bg-purple-600 hover:bg-purple-700 text-white shrink-0"
          >
            {savingYescaptcha ? <RefreshCw className="w-3.5 h-3.5 animate-spin" /> : t.adminYesCaptchaSet}
          </Button>
        </div>
      </div>

      {/* CapSolver API Key */}
      <div className="rounded-xl border border-blue-500/40 bg-blue-500/5 p-4 space-y-3">
        <div className="flex items-start gap-3">
          <div className="w-8 h-8 rounded-lg bg-blue-500/20 border border-blue-500/30 flex items-center justify-center flex-shrink-0">
            <Shield className="w-4 h-4 text-blue-400" />
          </div>
          <div>
            <h3 className="text-sm font-semibold text-blue-300">{t.adminCapSolverTitle}</h3>
            <p className="text-xs text-muted-foreground mt-0.5">
              {t.adminCapSolverDesc}
            </p>
          </div>
        </div>
        <div className="rounded-lg border border-border/40 bg-black/20 p-3 text-xs text-muted-foreground">
          <p>{t.adminCapSolverHowTo}</p>
        </div>
        <div className="flex gap-2">
          <Input
            className="flex-1 text-xs font-mono bg-background/50"
            placeholder="CAP-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
            value={capsolverKey}
            onChange={(e) => setCapsolverKey(e.target.value)}
            spellCheck={false}
          />
          <Button
            size="sm"
            disabled={capsolverKey.trim().length < 10 || savingCapsolver}
            onClick={handleSaveCapsolver}
            className="bg-blue-500 hover:bg-blue-600 text-white shrink-0"
          >
            {savingCapsolver ? <RefreshCw className="w-3.5 h-3.5 animate-spin" /> : t.adminCapSolverSet}
          </Button>
        </div>
      </div>
    </div>
  );
}

function ConfigPanel() {
  const { t } = useLang();
  const { toast } = useToast();
  const { data: config = [], refetch } = useQuery({ queryKey: ["adminConfig"], queryFn: fetchConfig });
  const [editing, setEditing] = useState<Record<string, string>>({});
  const [saving, setSaving] = useState<string | null>(null);
  const [visible, setVisible] = useState<Record<string, boolean>>({});

  const handleSave = async (key: string) => {
    const value = editing[key];
    if (!value) return;
    setSaving(key);
    try {
      const r = await fetch(`${API_BASE}/config`, {
        method: "PUT",
        credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ key: KEY_MAP[key] ?? key, value }),
      });
      if (!r.ok) throw new Error("Failed");
      await refetch();
      setEditing((p) => { const n = { ...p }; delete n[key]; return n; });
      toast({ description: t.adminConfigSaved });
    } catch {
      toast({ variant: "destructive", description: t.adminError });
    }
    setSaving(null);
  };

  const maskValue = (v: string) => v.length > 20 ? v.slice(0, 12) + "..." + v.slice(-6) : v;
  const LABELS: Record<string, string> = {
    geminigen_refresh_token: "Refresh Token",
    geminigen_bearer_token: "Access Token",
  };
  const KEY_MAP: Record<string, string> = {
    geminigen_refresh_token: "refresh_token",
    geminigen_bearer_token: "access_token",
  };

  return (
    <div className="space-y-4">
      <QuickTokenUpdate />
      <AccountPoolCard />
      <AutoRenewalCard />
      <TokenGuide />
      {config.length === 0 && (
        <div className="text-center py-8 text-muted-foreground text-sm">{t.adminConfigEmpty}</div>
      )}
      {config.map((row) => (
        <div key={row.key} className="rounded-xl border border-border/50 p-4 space-y-3">
          <div className="flex items-center justify-between">
            <div>
              <span className="font-medium text-sm text-foreground">{LABELS[row.key] || row.key}</span>
              <span className="text-xs text-muted-foreground ml-2">{t.adminConfigUpdated}: {new Date(row.updatedAt).toLocaleString()}</span>
            </div>
            <button
              onClick={() => setVisible(p => ({ ...p, [row.key]: !p[row.key] }))}
              className="text-muted-foreground hover:text-foreground"
            >
              {visible[row.key] ? <EyeOff className="w-3.5 h-3.5" /> : <Eye className="w-3.5 h-3.5" />}
            </button>
          </div>
          <div className="font-mono text-xs bg-black/30 rounded-lg px-3 py-2 text-emerald-300 break-all">
            {visible[row.key] ? row.value : maskValue(row.value)}
          </div>
          <div className="flex gap-2">
            <Input
              className="flex-1 text-xs font-mono bg-background/50 border-border/60"
              placeholder={t.adminConfigNewValue}
              value={editing[row.key] || ""}
              onChange={(e) => setEditing(p => ({ ...p, [row.key]: e.target.value }))}
            />
            <Button
              size="sm"
              disabled={!editing[row.key] || saving === row.key}
              onClick={() => handleSave(row.key)}
            >
              {saving === row.key ? <RefreshCw className="w-3.5 h-3.5 animate-spin" /> : t.adminConfigSaveBtn}
            </Button>
          </div>
        </div>
      ))}
    </div>
  );
}

export function Admin() {
  const { t } = useLang();
  const { user, isAdmin, isLoaded } = useAuth();
  const [, navigate] = useLocation();
  const qc = useQueryClient();
  const { toast } = useToast();
  const [tab, setTab] = useState<"users" | "config">("users");

  const { data: stats } = useQuery({ queryKey: ["adminStats"], queryFn: fetchStats, enabled: isAdmin });
  const { data: users = [], isLoading: usersLoading } = useQuery({
    queryKey: ["adminUsers"], queryFn: fetchUsers, enabled: isAdmin && tab === "users",
  });

  const updateUser = async (id: number, data: Record<string, unknown>) => {
    const r = await fetch(`${API_BASE}/users/${id}`, {
      method: "PUT",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data),
    });
    if (!r.ok) throw new Error("Failed");
    qc.invalidateQueries({ queryKey: ["adminUsers"] });
  };

  const deleteUser = async (id: number) => {
    const r = await fetch(`${API_BASE}/users/${id}`, { method: "DELETE", credentials: "include" });
    if (!r.ok) {
      const d = await r.json();
      throw new Error(d.error || "Failed");
    }
    qc.invalidateQueries({ queryKey: ["adminUsers"] });
  };

  if (isLoaded && !isAdmin) {
    return (
      <div className="container mx-auto px-4 py-16 max-w-lg text-center space-y-4">
        <AlertCircle className="w-12 h-12 mx-auto text-destructive/60" />
        <h1 className="text-xl font-bold text-foreground">{t.adminForbiddenTitle}</h1>
        <p className="text-muted-foreground text-sm">{t.adminForbiddenDesc}</p>
        <Button onClick={() => navigate("/")}>{t.adminBackHome}</Button>
      </div>
    );
  }

  return (
    <div className="container mx-auto px-4 py-8 max-w-4xl space-y-8">
      <div className="flex items-center gap-3">
        <div className="w-10 h-10 rounded-xl bg-yellow-500/15 border border-yellow-500/30 flex items-center justify-center">
          <Shield className="w-5 h-5 text-yellow-400" />
        </div>
        <div>
          <h1 className="text-2xl font-bold text-foreground">{t.adminTitle}</h1>
          <p className="text-muted-foreground text-sm">{t.adminSubtitle}</p>
        </div>
      </div>

      {stats && (
        <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
          <StatCard icon={Users} label={t.adminStatUsers} value={stats.users} color="bg-blue-500/15 border border-blue-500/20 text-blue-400" />
          <StatCard icon={ImageIcon} label={t.adminStatImages} value={stats.images} color="bg-purple-500/15 border border-purple-500/20 text-purple-400" />
          <StatCard icon={Key} label={t.adminStatApiKeys} value={stats.apiKeys} color="bg-green-500/15 border border-green-500/20 text-green-400" />
        </div>
      )}

      <div className="flex border-b border-border/50 gap-1">
        {(["users", "config"] as const).map((t2) => (
          <button
            key={t2}
            onClick={() => setTab(t2)}
            className={`px-4 py-2 text-sm font-medium rounded-t-lg transition-colors ${
              tab === t2
                ? "bg-card border border-b-card border-border/60 text-foreground -mb-px"
                : "text-muted-foreground hover:text-foreground"
            }`}
          >
            {t2 === "users" ? (
              <span className="flex items-center gap-2"><Users className="w-4 h-4" />{t.adminTabUsers}</span>
            ) : (
              <span className="flex items-center gap-2"><Settings className="w-4 h-4" />{t.adminTabConfig}</span>
            )}
          </button>
        ))}
      </div>

      {tab === "users" && (
        <div className="space-y-2">
          {usersLoading ? (
            <div className="text-center py-8 text-muted-foreground text-sm">Loading...</div>
          ) : users.length === 0 ? (
            <div className="text-center py-8 text-muted-foreground text-sm">{t.adminNoUsers}</div>
          ) : (
            users.map((u) => (
              <UserRow
                key={u.id}
                user={u}
                currentUserId={user!.id}
                onUpdate={updateUser}
                onDelete={deleteUser}
              />
            ))
          )}
        </div>
      )}

      {tab === "config" && <ConfigPanel />}
    </div>
  );
}
