import { useEffect, useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { toast as sonnerToast } from "sonner";
import {
  Tv,
  LogOut,
  Plus,
  Trash2,
  Save,
  RefreshCcw,
  Calendar,
  MessageCircle,
  Server,
  Loader2,
  Upload,
  FileText,
  X,
  ChevronDown,
  Sparkles,
  Heart,
  ShieldCheck,
  PlayCircle,
  Users,
  UserPlus,
  Library,
  Sliders,
  Megaphone,
  AlertTriangle,
} from "lucide-react";
import StalkerTestButton from "@/components/StalkerTestButton";
import ProxyStatsWidget from "@/components/admin/ProxyStatsWidget";
import { useNavigate } from "react-router-dom";
import LiveStatsCard from "@/components/LiveStatsCard";
import { useTranslation } from "react-i18next";
import { useAuth } from "@/hooks/useAuth";
import LanguageSelect from "@/components/LanguageSelect";
import { FocusableInput } from "@/components/focusable";
import {
  apiCreateUser,
  apiDeleteUser,
  apiGetSettings,
  apiListUsers,
  apiUpdateSettings,
  apiUpdateUser,
  apiAdminAlerts,
  API_BASE,
  type NadiUser,
  type Settings,
  type SharedProfile,
  type UnconfiguredUser,
} from "@/lib/nadiAuth";
import { APP_VERSION, compareVersions, resolveInstalledVersion } from "@/lib/appInfo";

// Reusable click-to-expand card. The user explicitly asked for "every one
// have button click" — each major admin block (Update / Creator / Support /
// Player notice / Shared Profiles / Create / Subscribers) is wrapped in
// this so the page is calm by default and reveals one section at a time.
const AccordionCard = ({
  id,
  open,
  onToggle,
  icon: Icon,
  title,
  subtitle,
  badge,
  testId,
  children,
}: {
  id: string;
  open: boolean;
  onToggle: () => void;
  icon: React.ComponentType<{ className?: string }>;
  title: string;
  subtitle?: string;
  badge?: React.ReactNode;
  testId?: string;
  children: React.ReactNode;
}) => {
  return (
    <section
      className="glass-card rounded-2xl overflow-hidden"
      data-testid={testId ?? `acc-${id}`}
    >
      <button
        type="button"
        onClick={onToggle}
        data-testid={`acc-${id}-btn`}
        className={`w-full flex items-center gap-3 px-5 sm:px-6 py-4 text-left transition-colors ${
          open
            ? "bg-primary/8 border-b border-primary/20"
            : "hover:bg-primary/5"
        }`}
      >
        <span
          className={`flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border transition-colors ${
            open
              ? "border-primary/50 bg-primary/15 text-primary"
              : "border-border/60 bg-muted/30 text-muted-foreground"
          }`}
        >
          <Icon className="w-5 h-5" />
        </span>
        <span className="flex-1 min-w-0">
          <span className="block font-display text-base sm:text-lg tracking-[0.18em] gold-text uppercase">
            {title}
          </span>
          {subtitle && (
            <span className="block text-[11px] sm:text-xs text-muted-foreground mt-0.5 truncate">
              {subtitle}
            </span>
          )}
        </span>
        {badge && <span className="shrink-0">{badge}</span>}
        <ChevronDown
          className={`w-5 h-5 text-muted-foreground transition-transform ${
            open ? "rotate-180 text-primary" : ""
          }`}
        />
      </button>
      <AnimatePresence initial={false}>
        {open && (
          <motion.div
            key="body"
            initial={{ height: 0, opacity: 0 }}
            animate={{ height: "auto", opacity: 1 }}
            exit={{ height: 0, opacity: 0 }}
            transition={{ duration: 0.25, ease: "easeOut" }}
            className="overflow-hidden"
          >
            <div className="p-5 sm:p-6">{children}</div>
          </motion.div>
        )}
      </AnimatePresence>
    </section>
  );
};


/**
 * Reads the *real* installed version from the native app (Capacitor →
 * versionName from build.gradle) and shows it next to the admin's
 * "Latest version" target so they can immediately see whether THIS device
 * will see the popup. Crucial sanity check: if the banner says "you're on
 * v1.0.1 ✓ already up-to-date", the admin knows the new APK was installed
 * correctly and won't get the popup.
 */
const InstalledVersionBanner = ({ latest }: { latest: string }) => {
  const [installed, setInstalled] = useState<string>(APP_VERSION);
  useEffect(() => {
    let cancelled = false;
    void resolveInstalledVersion().then((v) => {
      if (!cancelled) setInstalled(v);
    });
    return () => { cancelled = true; };
  }, []);
  const cmp = compareVersions(installed, latest || installed);
  const upToDate = cmp >= 0;
  return (
    <div
      className={`mb-3 flex flex-wrap items-center gap-x-3 gap-y-1 rounded-xl border px-3 py-2 text-[11px] ${
        upToDate
          ? "border-emerald-500/30 bg-emerald-500/5 text-emerald-300"
          : "border-amber-500/30 bg-amber-500/5 text-amber-300"
      }`}
      data-testid="installed-version-banner"
    >
      <span className="font-medium tracking-[0.18em] uppercase">
        This device
      </span>
      <span className="opacity-80">
        v<span data-testid="installed-version-value">{installed}</span>
      </span>
      <span className="opacity-50">→</span>
      <span className="opacity-80">
        target v<span data-testid="latest-version-value">{latest || "—"}</span>
      </span>
      <span className="sm:ml-auto">
        {upToDate ? "✓ up-to-date — no popup" : "popup will appear"}
      </span>
    </div>
  );
};



const Admin = () => {
  const navigate = useNavigate();
  const { t } = useTranslation();
  const { user, logout } = useAuth();
  const [users, setUsers] = useState<NadiUser[]>([]);
  const [settings, setSettings] = useState<Settings | null>(null);
  const [loading, setLoading] = useState(true);
  const [toast, setToast] = useState<string | null>(null);
  const [unconfiguredUsers, setUnconfiguredUsers] = useState<UnconfiguredUser[]>([]);
  const [alertsDismissed, setAlertsDismissed] = useState(false);
  // Accordion: which section is currently open. `null` = all collapsed.
  // The user requested every block to be a clickable button — opening one
  // closes the others, so the page never feels overwhelming.
  const [openSection, setOpenSection] = useState<string | null>("update");

  // New user form
  const [nuUsername, setNuUsername] = useState("");
  const [nuPassword, setNuPassword] = useState("");
  const [nuDays, setNuDays] = useState(30);
  const [nuMode, setNuMode] = useState<"shared" | "own">("shared");
  const [nuServer, setNuServer] = useState("");
  const [nuXUser, setNuXUser] = useState("");
  const [nuXPass, setNuXPass] = useState("");
  const [creating, setCreating] = useState(false);

  const showToast = (msg: string) => {
    setToast(msg);
    window.setTimeout(() => setToast(null), 2400);
  };

  useEffect(() => {
    if (!user || user.role !== "admin") {
      navigate("/welcome");
      return;
    }
    void refreshAll();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [user]);

  const refreshAll = async () => {
    setLoading(true);
    try {
      const [u, s] = await Promise.all([apiListUsers(), apiGetSettings()]);
      setUsers(u);
      setSettings(s);
      // Fetch admin alerts (non-blocking)
      try {
        const alerts = await apiAdminAlerts();
        setUnconfiguredUsers(alerts.unconfigured_own_users || []);
        setAlertsDismissed(false);
      } catch { /* alerts are non-critical */ }
    } catch (e) {
      showToast(e instanceof Error ? e.message : t("admin.loadFailed"));
    } finally {
      setLoading(false);
    }
  };

  const handleCreate = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!nuUsername || !nuPassword) return;
    setCreating(true);
    try {
      await apiCreateUser({
        username: nuUsername.trim(),
        password: nuPassword,
        days: nuDays,
        xtream_mode: nuMode,
        xtream_server: nuServer || undefined,
        xtream_username: nuXUser || undefined,
        xtream_password: nuXPass || undefined,
      });
      setNuUsername("");
      setNuPassword("");
      setNuDays(30);
      setNuMode("shared");
      setNuServer("");
      setNuXUser("");
      setNuXPass("");
      showToast(t("admin.userCreated"));
      await refreshAll();
    } catch (e) {
      showToast(e instanceof Error ? e.message : t("admin.opFailed"));
    } finally {
      setCreating(false);
    }
  };

  const handleLogout = () => {
    logout();
    navigate("/welcome");
  };

  return (
    <div
      data-testid="admin-page"
      // BUG FIX (2026-01) — was `min-h-screen overflow-hidden` which
      // worked only because html/body let the document grow. Now that
      // html/body are locked at viewport height with overflow:hidden,
      // we make the admin page itself a hard 100dvh shell with an
      // INTERNAL scrolling <main>. This is the same contract as
      // PageLayout uses for Live TV / Movies / Series.
      className="relative h-screen w-full overflow-hidden"
      style={{ height: "100dvh" }}
    >
      <div
        className="absolute inset-0 bg-cover bg-center"
        style={{ backgroundImage: "url('/images/nebula-bg.png')" }}
      />
      <div className="absolute inset-0 bg-background/70" />

      <div className="relative z-10 h-full flex flex-col min-h-0">
        {/* Header */}
        <header className="flex flex-wrap items-center justify-between px-4 sm:px-6 md:px-10 pt-6 gap-3">
          <div className="flex items-center gap-3">
            <div
              className="w-10 h-10 sm:w-12 sm:h-12 rounded-xl glass flex items-center justify-center"
              style={{ border: "1px solid hsla(40, 80%, 55%, 0.4)" }}
            >
              <Tv className="w-5 h-5 text-primary gold-glow" />
            </div>
            <div>
              <h1 className="font-display text-lg sm:text-xl md:text-2xl tracking-[0.2em] sm:tracking-[0.3em] gold-text">
                {t("admin.title")}
              </h1>
              <p className="text-muted-foreground text-[9px] sm:text-[10px] tracking-[0.3em] uppercase">
                {t("admin.subtitle")}
              </p>
            </div>
          </div>
          <div className="flex items-center gap-2">
            <LanguageSelect align="right" />
            <button
              onClick={() => navigate("/admin/broadcast")}
              data-testid="admin-broadcast-btn"
              className="hidden sm:flex items-center gap-2 px-3 py-2 rounded-full glass text-muted-foreground hover:text-primary hover:border-primary/40 transition-colors text-xs"
              title="Broadcast notification"
            >
              <Megaphone className="w-4 h-4" />
              <span className="hidden md:inline">Broadcast</span>
            </button>
            <button
              onClick={refreshAll}
              data-testid="admin-refresh-btn"
              className="w-10 h-10 sm:w-11 sm:h-11 rounded-full glass flex items-center justify-center text-muted-foreground hover:text-primary hover:border-primary/40 transition-colors"
              title={t("common.refresh")}
            >
              <RefreshCcw className={`w-5 h-5 ${loading ? "animate-spin" : ""}`} />
            </button>
            <button
              onClick={handleLogout}
              data-testid="admin-logout-btn"
              className="flex items-center gap-2 px-3 sm:px-4 py-2 rounded-full glass text-muted-foreground hover:text-foreground hover:border-primary/40 transition-colors text-xs sm:text-sm"
            >
              <LogOut className="w-4 h-4" /> <span className="hidden sm:inline">{t("admin.logout")}</span>
            </button>
          </div>
        </header>

        {/* Toast */}
        {toast && (
          <motion.div
            initial={{ opacity: 0, y: -10 }}
            animate={{ opacity: 1, y: 0 }}
            className="fixed top-6 left-1/2 -translate-x-1/2 z-50 glass-card rounded-full px-5 py-2 text-sm text-primary border border-primary/30"
          >
            {toast}
          </motion.div>
        )}

        <main className="flex-1 min-h-0 overflow-y-auto px-3 sm:px-4 md:px-10 py-6 sm:py-8 space-y-4 sm:space-y-5 max-w-7xl mx-auto w-full">
          {/* Stream Proxy stats — auto-polls /api/proxy/stats every 5 s.
              Verifies that PHP cPanel proxy / FastAPI proxy is alive
              and reports cache hit-rate, in-flight upstreams, etc. */}
          <ProxyStatsWidget apiBase={API_BASE} />
          {/* Live engagement stats — auto-refresh every 30 s */}
          <LiveStatsCard />

          {/* Admin alerts: unconfigured own-mode users */}
          {!alertsDismissed && unconfiguredUsers.length > 0 && (
            <motion.div
              initial={{ opacity: 0, y: -8 }}
              animate={{ opacity: 1, y: 0 }}
              data-testid="admin-alert-unconfigured"
              className="glass-card rounded-2xl border border-amber-500/40 p-4"
            >
              <div className="flex items-start gap-3">
                <div className="w-9 h-9 rounded-lg bg-amber-500/15 flex items-center justify-center shrink-0 mt-0.5">
                  <AlertTriangle className="w-5 h-5 text-amber-400" />
                </div>
                <div className="flex-1 min-w-0">
                  <p className="text-foreground text-sm font-medium">
                    {unconfiguredUsers.length} subscriber{unconfiguredUsers.length > 1 ? "s" : ""} on "Own Server" with no credentials
                  </p>
                  <p className="text-muted-foreground text-[11px] mt-1 leading-relaxed">
                    These users are set to per-user mode but haven't had any Xtream/M3U/Stalker
                    credentials configured. They see an empty app until you add their server details.
                  </p>
                  <div className="flex flex-wrap gap-2 mt-3">
                    {unconfiguredUsers.map((u) => (
                      <span
                        key={u.id}
                        className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-amber-500/10 border border-amber-500/25 text-[11px] text-amber-300"
                      >
                        <Users className="w-3 h-3" />
                        <span className="font-medium">{u.username}</span>
                        {u.days_remaining != null && (
                          <span className="text-muted-foreground">({u.days_remaining}d left)</span>
                        )}
                      </span>
                    ))}
                  </div>
                  <p className="text-muted-foreground text-[10px] mt-2">
                    Open the Subscribers section below and edit each user's ADVANCED settings to add their Xtream credentials.
                  </p>
                </div>
                <button
                  onClick={() => setAlertsDismissed(true)}
                  className="w-7 h-7 rounded-lg glass flex items-center justify-center text-muted-foreground hover:text-foreground shrink-0"
                  data-testid="admin-alert-dismiss"
                >
                  <X className="w-3.5 h-3.5" />
                </button>
              </div>
            </motion.div>
          )}
          {/* Settings (accordion sections inside) */}
          <SettingsPanel
            settings={settings}
            openSection={openSection}
            setOpenSection={setOpenSection}
            onSaved={(s) => {
              setSettings(s);
              showToast(t("admin.settingsSaved"));
            }}
          />

          {/* Create user */}
          <AccordionCard
            id="create"
            open={openSection === "create"}
            onToggle={() => setOpenSection(openSection === "create" ? null : "create")}
            icon={UserPlus}
            title={t("admin.createHeading")}
            subtitle="Add a new subscriber account"
            testId="admin-section-create"
          >
            <form
              onSubmit={handleCreate}
              className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3"
            >
              <Input
                label={t("admin.usernameLabel")}
                value={nuUsername}
                onChange={setNuUsername}
                testId="nu-username"
                required
              />
              <Input
                label={t("admin.passwordLabel")}
                value={nuPassword}
                onChange={setNuPassword}
                type="text"
                testId="nu-password"
                required
              />
              <Input
                label={t("admin.daysLabel")}
                value={String(nuDays)}
                onChange={(v) => setNuDays(Math.max(1, parseInt(v || "0") || 1))}
                type="number"
                testId="nu-days"
              />
              <div>
                <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
                  {t("admin.xtreamMode")}
                </label>
                <select
                  value={nuMode}
                  onChange={(e) => setNuMode(e.target.value as "shared" | "own")}
                  data-testid="nu-mode"
                  className="w-full glass-input rounded-lg px-3 py-2 text-sm text-foreground outline-none"
                >
                  <option value="shared">{t("admin.modeShared")}</option>
                  <option value="own">{t("admin.modeOwn")}</option>
                </select>
              </div>
              {nuMode === "own" && (
                <>
                  <Input
                    label={t("admin.serverUrl")}
                    value={nuServer}
                    onChange={setNuServer}
                    testId="nu-server"
                  />
                  <Input
                    label={t("admin.xtreamUsername")}
                    value={nuXUser}
                    onChange={setNuXUser}
                    testId="nu-xuser"
                  />
                  <Input
                    label={t("admin.xtreamPassword")}
                    value={nuXPass}
                    onChange={setNuXPass}
                    testId="nu-xpass"
                  />
                </>
              )}
              <div className="md:col-span-2 lg:col-span-4 flex justify-end">
                <button
                  type="submit"
                  aria-busy={creating || undefined} data-loading={creating || undefined}
                  data-testid="nu-submit"
                  className="flex items-center gap-2 px-5 py-2.5 rounded-xl bg-primary/80 hover:bg-primary text-primary-foreground font-medium text-sm transition-colors disabled:opacity-60"
                >
                  {creating ? (
                    <Loader2 className="w-4 h-4 animate-spin" />
                  ) : (
                    <Plus className="w-4 h-4" />
                  )}
                  {creating ? t("admin.creating") : t("admin.createUser")}
                </button>
              </div>
            </form>
          </AccordionCard>

          {/* User list */}
          <AccordionCard
            id="subscribers"
            open={openSection === "subscribers"}
            onToggle={() => setOpenSection(openSection === "subscribers" ? null : "subscribers")}
            icon={Users}
            title={t("admin.subscribersHeading", { count: users.length })}
            subtitle={`${users.length} active subscribers`}
            testId="admin-section-subscribers"
            badge={
              <span className="text-[10px] px-2 py-0.5 rounded-full bg-primary/15 text-primary tracking-widest">
                {users.length}
              </span>
            }
          >
            {users.length === 0 ? (
              <p className="text-muted-foreground text-sm">{t("admin.noSubscribers")}</p>
            ) : (
              <div className="space-y-3">
                {users.map((u) => (
                  <UserRow
                    key={u.id}
                    user={u}
                    onChanged={refreshAll}
                    onToast={showToast}
                  />
                ))}
              </div>
            )}
          </AccordionCard>
        </main>
      </div>
    </div>
  );
};

// ---- Sub-components ----

const M3UFileField = ({
  idx,
  content,
  onChange,
}: {
  idx: number;
  content: string;
  onChange: (text: string) => void;
}) => {
  const [fileName, setFileName] = useState<string>("");
  const [busy, setBusy] = useState(false);

  const handleFile = async (file: File | null) => {
    if (!file) return;
    setBusy(true);
    try {
      const text = await file.text();
      onChange(text);
      setFileName(file.name);
    } finally {
      setBusy(false);
    }
  };

  const clear = () => {
    onChange("");
    setFileName("");
  };

  const hasContent = !!(content && content.trim().length);
  const lineCount = hasContent ? content.split(/\r?\n/).filter(Boolean).length : 0;

  return (
    <div>
      <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
        M3U File (optional)
      </label>
      <div className="flex items-center gap-2 flex-wrap">
        <label
          data-testid={`profile-m3u-file-${idx}`}
          className="cursor-pointer flex items-center gap-2 px-3 py-2 rounded-lg glass text-xs text-primary hover:border-primary/40 transition-colors"
        >
          {busy ? (
            <Loader2 className="w-3.5 h-3.5 animate-spin" />
          ) : (
            <Upload className="w-3.5 h-3.5" />
          )}
          <span>{busy ? "Reading…" : "Upload .m3u"}</span>
          <input
            type="file"
            accept=".m3u,.m3u8,audio/x-mpegurl,application/vnd.apple.mpegurl,text/plain"
            onChange={(e) => void handleFile(e.target.files?.[0] ?? null)}
            className="hidden"
          />
        </label>
        {hasContent && (
          <div className="flex items-center gap-2 flex-1 min-w-0 text-xs text-muted-foreground">
            <FileText className="w-3.5 h-3.5 text-primary shrink-0" />
            <span className="truncate">
              {fileName || "uploaded file"} · {lineCount} lines
            </span>
            <button
              type="button"
              onClick={clear}
              data-testid={`profile-m3u-file-clear-${idx}`}
              className="ml-1 text-muted-foreground hover:text-destructive"
              title="Remove uploaded file"
            >
              <X className="w-3.5 h-3.5" />
            </button>
          </div>
        )}
      </div>
      <p className="text-[10px] text-muted-foreground mt-1">
        Upload a playlist file directly. When set, this is used instead of the URL above.
      </p>
    </div>
  );
};

const Input = ({
  label,
  value,
  onChange,
  type = "text",
  testId,
  required,
  focusKey,
}: {
  label: string;
  value: string;
  onChange: (v: string) => void;
  type?: string;
  testId?: string;
  required?: boolean;
  /** Optional explicit focusKey. Defaults to `admin-input-<testId|label>`. */
  focusKey?: string;
}) => {
  // Derive a stable, unique focusKey when none was provided. We
  // prefer the testId because admin testers identify rows by it.
  const resolvedFocusKey =
    focusKey ?? `admin-input-${testId ?? label.replace(/\s+/g, "-").toLowerCase()}`;
  const allowedTypes: ReadonlyArray<string> = [
    "text",
    "password",
    "tel",
    "email",
    "url",
  ];
  const safeType = (allowedTypes.includes(type) ? type : "text") as
    | "text"
    | "password"
    | "tel"
    | "email"
    | "url";
  return (
    <div>
      <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
        {label}
        {required ? <span className="text-destructive ml-1">*</span> : null}
      </label>
      <FocusableInput
        focusKey={resolvedFocusKey}
        type={safeType}
        value={value}
        onChange={onChange}
        testId={testId}
        className="w-full"
      />
    </div>
  );
};

const SettingsPanel = ({
  settings,
  onSaved,
  openSection,
  setOpenSection,
}: {
  settings: Settings | null;
  onSaved: (s: Settings) => void;
  openSection: string | null;
  setOpenSection: (s: string | null) => void;
}) => {
  const { t } = useTranslation();
  const [wa, setWa] = useState(settings?.whatsapp_number ?? "");
  const [profiles, setProfiles] = useState<SharedProfile[]>(
    settings?.shared_profiles ?? [],
  );
  const [externalPlayer, setExternalPlayer] = useState<boolean>(
    settings?.external_player_enabled ?? false,
  );
  const [playerNoticeEnabled, setPlayerNoticeEnabled] = useState<boolean>(
    settings?.player_notice_enabled ?? false,
  );
  const [inlinePreviewEnabled, setInlinePreviewEnabled] = useState<boolean>(
    settings?.inline_preview_enabled ?? true,
  );
  // Push notifications kill-switch (default OFF — see usePushNotifications.ts).
  const [pushEnabled, setPushEnabled] = useState<boolean>(
    settings?.push_enabled ?? false,
  );
  // ── In-app update / about / support ──
  const [updateEnabled, setUpdateEnabled] = useState<boolean>(
    settings?.update_enabled ?? false,
  );
  const [appVersion, setAppVersion] = useState<string>(
    settings?.app_version ?? "1.0.0",
  );
  const [minVersion, setMinVersion] = useState<string>(
    settings?.min_supported_version ?? "1.0.0",
  );
  const [apkUrl, setApkUrl] = useState<string>(settings?.update_apk_url ?? "");
  const [playUrl, setPlayUrl] = useState<string>(
    settings?.update_play_url ?? "",
  );
  const [changelog, setChangelog] = useState<string>(
    settings?.update_changelog ?? "",
  );
  const [popupDelay, setPopupDelay] = useState<number>(
    typeof settings?.popup_delay_seconds === "number"
      ? settings.popup_delay_seconds
      : 10,
  );
  const [waMsg, setWaMsg] = useState<string>(settings?.whatsapp_message ?? "");
  const [supportEmail, setSupportEmail] = useState<string>(
    settings?.support_email ?? "",
  );
  const [creatorName, setCreatorName] = useState<string>(
    settings?.creator_name ?? "",
  );
  const [creatorRole, setCreatorRole] = useState<string>(
    settings?.creator_role ?? "",
  );
  const [creatorAvatar, setCreatorAvatar] = useState<string>(
    settings?.creator_avatar_url ?? "",
  );
  const [creatorBio, setCreatorBio] = useState<string>(
    settings?.creator_bio ?? "",
  );
  const [privacyText, setPrivacyText] = useState<string>(
    settings?.privacy_policy_text ?? "",
  );
  // FEATURE (2026-01) — Terms & Conditions text. Same admin-editable
  // pattern as privacy_policy_text; rendered verbatim by the About
  // menu modal on /account.
  const [termsText, setTermsText] = useState<string>(
    settings?.terms_policy_text ?? "",
  );
  // ── Ads / AdMob ──
  const [adsEnabled, setAdsEnabled] = useState<boolean>(
    settings?.ads_enabled ?? false,
  );
  // BUG-2 FIX (2026-05) — Users-vs-Guests sub-toggles (admin can show
  // ads to one segment but not the other). Defaults preserve the
  // legacy behaviour (guests on, users off) if the backend doesn't
  // return these fields yet.
  const [adsForUsers, setAdsForUsers] = useState<boolean>(
    typeof settings?.ads_enabled_for_users === "boolean"
      ? settings.ads_enabled_for_users
      : false,
  );
  const [adsForGuests, setAdsForGuests] = useState<boolean>(
    typeof settings?.ads_enabled_for_guests === "boolean"
      ? settings.ads_enabled_for_guests
      : (settings?.ads_enabled ?? false),
  );
  const [adsTesting, setAdsTesting] = useState<boolean>(
    settings?.ads_testing_mode ?? true,
  );
  const [adsAppId, setAdsAppId] = useState<string>(settings?.ads_app_id ?? "");
  const [adsBannerId, setAdsBannerId] = useState<string>(
    settings?.ads_banner_id ?? "",
  );
  const [adsInterstitialId, setAdsInterstitialId] = useState<string>(
    settings?.ads_interstitial_id ?? "",
  );
  const [adsNativeId, setAdsNativeId] = useState<string>(
    settings?.ads_native_id ?? "",
  );
  const [adsRewardedId, setAdsRewardedId] = useState<string>(
    settings?.ads_rewarded_id ?? "",
  );
  const [adsInterstitialEvery, setAdsInterstitialEvery] = useState<number>(
    typeof settings?.ads_interstitial_every === "number"
      ? settings.ads_interstitial_every
      : 5,
  );
  // ── Smart-TV custom "House Ad" banner (FEATURE 2026-01) ──
  const [tvBannerEnabled, setTvBannerEnabled] = useState<boolean>(
    settings?.tv_banner_enabled ?? false,
  );
  const [tvBannerType, setTvBannerType] = useState<"image" | "html">(
    settings?.tv_banner_type === "html" ? "html" : "image",
  );
  const [tvBannerHtml, setTvBannerHtml] = useState<string>(
    settings?.tv_banner_html ?? "",
  );
  const [tvBannerImageUrl, setTvBannerImageUrl] = useState<string>(
    settings?.tv_banner_image_url ?? "",
  );
  const [tvBannerClickUrl, setTvBannerClickUrl] = useState<string>(
    settings?.tv_banner_click_url ?? "",
  );
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    setWa(settings?.whatsapp_number ?? "");
    setProfiles(settings?.shared_profiles ?? []);
    setExternalPlayer(settings?.external_player_enabled ?? false);
    setPlayerNoticeEnabled(settings?.player_notice_enabled ?? false);
    setInlinePreviewEnabled(settings?.inline_preview_enabled ?? true);
    setPushEnabled(settings?.push_enabled ?? false);
    setUpdateEnabled(settings?.update_enabled ?? false);
    setAppVersion(settings?.app_version ?? "1.0.0");
    setMinVersion(settings?.min_supported_version ?? "1.0.0");
    setApkUrl(settings?.update_apk_url ?? "");
    setPlayUrl(settings?.update_play_url ?? "");
    setChangelog(settings?.update_changelog ?? "");
    setPopupDelay(
      typeof settings?.popup_delay_seconds === "number"
        ? settings.popup_delay_seconds
        : 10,
    );
    setWaMsg(settings?.whatsapp_message ?? "");
    setSupportEmail(settings?.support_email ?? "");
    setCreatorName(settings?.creator_name ?? "");
    setCreatorRole(settings?.creator_role ?? "");
    setCreatorAvatar(settings?.creator_avatar_url ?? "");
    setCreatorBio(settings?.creator_bio ?? "");
    setPrivacyText(settings?.privacy_policy_text ?? "");
    setTermsText(settings?.terms_policy_text ?? "");
    setAdsEnabled(settings?.ads_enabled ?? false);
    setAdsForUsers(
      typeof settings?.ads_enabled_for_users === "boolean"
        ? settings.ads_enabled_for_users
        : false,
    );
    setAdsForGuests(
      typeof settings?.ads_enabled_for_guests === "boolean"
        ? settings.ads_enabled_for_guests
        : (settings?.ads_enabled ?? false),
    );
    setAdsTesting(settings?.ads_testing_mode ?? true);
    setAdsAppId(settings?.ads_app_id ?? "");
    setAdsBannerId(settings?.ads_banner_id ?? "");
    setAdsInterstitialId(settings?.ads_interstitial_id ?? "");
    setAdsNativeId(settings?.ads_native_id ?? "");
    setAdsRewardedId(settings?.ads_rewarded_id ?? "");
    setAdsInterstitialEvery(
      typeof settings?.ads_interstitial_every === "number"
        ? settings.ads_interstitial_every
        : 5,
    );
    // FEATURE (2026-01) — Smart-TV custom banner
    setTvBannerEnabled(settings?.tv_banner_enabled ?? false);
    setTvBannerType(settings?.tv_banner_type === "html" ? "html" : "image");
    setTvBannerHtml(settings?.tv_banner_html ?? "");
    setTvBannerImageUrl(settings?.tv_banner_image_url ?? "");
    setTvBannerClickUrl(settings?.tv_banner_click_url ?? "");
  }, [settings]);

  const addProfile = (kind: "xtream" | "m3u" | "stalker") => {
    setProfiles((prev) => [
      ...prev,
      {
        id: `tmp-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
        name:
          kind === "xtream"
            ? "New Xtream"
            : kind === "stalker"
              ? "New Stalker"
              : "New M3U",
        kind,
        server: "",
        username: "",
        password: "",
        m3u_url: "",
        m3u_content: "",
        portal_url: "",
        mac_address: "",
      },
    ]);
  };

  const updateProfile = (idx: number, patch: Partial<SharedProfile>) =>
    setProfiles((prev) => prev.map((p, i) => (i === idx ? { ...p, ...patch } : p)));

  const removeProfile = (idx: number) =>
    setProfiles((prev) => prev.filter((_, i) => i !== idx));

  const save = async () => {
    setSaving(true);
    try {
      // BUG-2 FIX (2026-05) — verbose payload log to make it trivial
      // to confirm in DevTools that ads_enabled_for_users / _guests
      // are actually being submitted on Save. If you ever see these
      // fields missing here, the JS bundle is stale → run `yarn build`.
      console.log("[admin/save] settings payload:", {
        ads_enabled: adsEnabled,
        ads_enabled_for_users: adsForUsers,
        ads_enabled_for_guests: adsForGuests,
        ads_testing_mode: adsTesting,
      });
      const next = await apiUpdateSettings({
        whatsapp_number: wa,
        shared_profiles: profiles,
        external_player_enabled: externalPlayer,
        player_notice_enabled: playerNoticeEnabled,
        inline_preview_enabled: inlinePreviewEnabled,
        push_enabled: pushEnabled,
        update_enabled: updateEnabled,
        app_version: appVersion,
        min_supported_version: minVersion,
        update_apk_url: apkUrl,
        update_play_url: playUrl,
        update_changelog: changelog,
        popup_delay_seconds: popupDelay,
        whatsapp_message: waMsg,
        support_email: supportEmail,
        creator_name: creatorName,
        creator_role: creatorRole,
        creator_avatar_url: creatorAvatar,
        creator_bio: creatorBio,
        privacy_policy_text: privacyText,
        terms_policy_text: termsText,
        ads_enabled: adsEnabled,
        ads_enabled_for_users: adsForUsers,
        ads_enabled_for_guests: adsForGuests,
        ads_testing_mode: adsTesting,
        ads_app_id: adsAppId,
        ads_banner_id: adsBannerId,
        ads_interstitial_id: adsInterstitialId,
        ads_native_id: adsNativeId,
        ads_rewarded_id: adsRewardedId,
        ads_interstitial_every: adsInterstitialEvery,
        // FEATURE (2026-01) — Smart-TV "House Ad" banner config.
        tv_banner_enabled: tvBannerEnabled,
        tv_banner_type: tvBannerType,
        tv_banner_html: tvBannerHtml,
        tv_banner_image_url: tvBannerImageUrl,
        tv_banner_click_url: tvBannerClickUrl,
      });
      // BUG-2 FIX (2026-05) — invalidate the in-memory ad-config cache
      // so the next render of useEntitlement / useAdsPolicy picks up
      // the freshly-saved Users-vs-Guests toggles immediately. Without
      // this, the admin had to fully reload the app to see ads turn
      // on for the registered-user segment.
      try {
        const { resetAdConfigCache } = await import("@/lib/admob");
        resetAdConfigCache();
      } catch { /* no-op */ }
      try {
        const { resetAdsPolicyCache } = await import("@/hooks/useAdsPolicy");
        resetAdsPolicyCache();
      } catch { /* no-op */ }
      onSaved(next);
    } catch (e) {
      // Samsung Tizen QA forbids native alert() in web apps. Use the
      // in-app sonner toast instead — same UX, no native popup.
      const msg = e instanceof Error ? e.message : "Save failed";
      console.error("[Admin] save failed:", msg);
      sonnerToast.error(msg);
    } finally {
      setSaving(false);
    }
  };

  return (
    <>
      {/* WhatsApp + External Player + Install-popup toggle */}
      <AccordionCard
        id="playback"
        open={openSection === "playback"}
        onToggle={() => setOpenSection(openSection === "playback" ? null : "playback")}
        icon={PlayCircle}
        title="Playback & Popups"
        subtitle="WhatsApp, external player, install-video-player popup"
        testId="admin-section-playback"
      >
        <div className="space-y-4">
          <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
            <Input
              label={t("admin.whatsapp")}
              value={wa}
              onChange={setWa}
              testId="set-whatsapp"
            />
          </div>

          {/* External player toggle */}
          <div className="glass rounded-xl p-4 border border-border/60">
            <label className="flex items-start gap-3 cursor-pointer select-none">
              <input
                type="checkbox"
                checked={externalPlayer}
                onChange={(e) => setExternalPlayer(e.target.checked)}
                data-testid="toggle-external-player"
                className="mt-1 w-4 h-4 accent-primary cursor-pointer"
              />
              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                  <span className="text-sm font-medium text-foreground">
                    External Player
                  </span>
                  <span
                    className={`text-[10px] px-2 py-0.5 rounded-full ${
                      externalPlayer
                        ? "bg-amber-500/20 text-amber-400"
                        : "bg-primary/20 text-primary"
                    }`}
                  >
                    {externalPlayer ? "ON" : "OFF"}
                  </span>
                </div>
                <p className="text-xs text-muted-foreground mt-1 leading-relaxed">
                  {externalPlayer
                    ? "Videos open in VLC / MX Player / Brouken. If users don't have one installed, playback will fail."
                    : "Videos play inside the app using the built-in ExoPlayer. No third-party app needed — recommended."}
                </p>
              </div>
            </label>
          </div>

          {/* "Install a video player" popup toggle (NEW) */}
          <div className="glass rounded-xl p-4 border border-border/60">
            <label className="flex items-start gap-3 cursor-pointer select-none">
              <input
                type="checkbox"
                checked={playerNoticeEnabled}
                onChange={(e) => setPlayerNoticeEnabled(e.target.checked)}
                data-testid="toggle-player-notice"
                className="mt-1 w-4 h-4 accent-primary cursor-pointer"
              />
              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                  <span className="text-sm font-medium text-foreground">
                    "Install Video Player" Popup
                  </span>
                  <span
                    className={`text-[10px] px-2 py-0.5 rounded-full ${
                      playerNoticeEnabled
                        ? "bg-primary/20 text-primary"
                        : "bg-muted/40 text-muted-foreground"
                    }`}
                  >
                    {playerNoticeEnabled ? "ENABLED" : "DISABLED"}
                  </span>
                </div>
                <p className="text-xs text-muted-foreground mt-1 leading-relaxed">
                  {playerNoticeEnabled
                    ? "Users see the \"Install ExoPlayer / VLC\" popup once on first launch (until they tap \"I already have it\")."
                    : "Popup is hidden for everyone. Use this when most users already have a player installed."}
                </p>
              </div>
            </label>
          </div>

          {/* Inline Preview Player toggle (Live TV) */}
          <div className="glass rounded-xl p-4 border border-border/60">
            <label className="flex items-start gap-3 cursor-pointer select-none">
              <input
                type="checkbox"
                checked={inlinePreviewEnabled}
                onChange={(e) => setInlinePreviewEnabled(e.target.checked)}
                data-testid="toggle-inline-preview"
                className="mt-1 w-4 h-4 accent-primary cursor-pointer"
              />              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                  <span className="text-sm font-medium text-foreground">
                    Inline Preview Player (Live TV)
                  </span>
                  <span
                    className={`text-[10px] px-2 py-0.5 rounded-full ${
                      inlinePreviewEnabled
                        ? "bg-primary/20 text-primary"
                        : "bg-muted/40 text-muted-foreground"
                    }`}
                    data-testid="inline-preview-status"
                  >
                    {inlinePreviewEnabled ? "ENABLED" : "DISABLED"}
                  </span>
                </div>
                <p className="text-xs text-muted-foreground mt-1 leading-relaxed">
                  {inlinePreviewEnabled
                    ? "On Live TV (TV / browser only), tapping a channel shows a small preview player with gold icon controls (prev / play-pause / next / fullscreen). Double-tap the video — or tap ⛶ — to go fullscreen. On Android / iOS native apps this setting is ignored — playback always opens directly in the system video player."
                    : "Channels open directly in the player. Small preview on Live TV is disabled for TV / browser users."}
                </p>
              </div>
            </label>
          </div>

          {/* Push Notifications kill-switch (v2.1 — fixes ROG 8 Pro / A14-15 silent crash) */}
          <div className="glass rounded-xl p-4 border border-amber-500/30 bg-amber-500/[0.03]">
            <label className="flex items-start gap-3 cursor-pointer select-none">
              <input
                type="checkbox"
                checked={pushEnabled}
                onChange={(e) => setPushEnabled(e.target.checked)}
                data-testid="toggle-push-enabled"
                className="mt-1 w-4 h-4 accent-primary cursor-pointer"
              />
              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2 flex-wrap">
                  <span className="text-sm font-medium text-foreground">
                    Push Notifications (FCM)
                  </span>
                  <span
                    className={`text-[10px] px-2 py-0.5 rounded-full ${
                      pushEnabled
                        ? "bg-primary/20 text-primary"
                        : "bg-amber-500/20 text-amber-300"
                    }`}
                    data-testid="push-enabled-status"
                  >
                    {pushEnabled ? "ENABLED" : "DISABLED (safe)"}
                  </span>
                </div>
                <p className="text-xs text-muted-foreground mt-1 leading-relaxed">
                  {pushEnabled
                    ? "Devices will register with Firebase Cloud Messaging on the next cold start. Only keep this ON when the latest APK contains a valid google-services.json — otherwise the app will crash silently after login."
                    : "FCM registration is currently DISABLED for every device. This is the safe default — turn it ON only after you've shipped an APK with the firebase config (google-services.json) bundled in. Disabling instantly stops the post-login crash on devices running an older APK."}
                </p>
              </div>
            </label>
          </div>
        </div>
      </AccordionCard>

      {/* ─── In-app Update ─── */}
      <AccordionCard
        id="update"
        open={openSection === "update"}
        onToggle={() => setOpenSection(openSection === "update" ? null : "update")}
        icon={Sliders}
        title="In-App Update"
        subtitle="Version, force-update threshold, popup delay timer, APK & Play Store URLs"
        testId="admin-update-section"
        badge={
          <span
            className={`text-[10px] px-2 py-0.5 rounded-full ${
              updateEnabled
                ? "bg-primary/20 text-primary"
                : "bg-muted/40 text-muted-foreground"
            }`}
          >
            {updateEnabled ? "ENABLED" : "DISABLED"}
          </span>
        }
      >
        <div className="flex items-center justify-end mb-3">
          <label className="flex items-center gap-2 cursor-pointer select-none">
            <input
              type="checkbox"
              checked={updateEnabled}
              onChange={(e) => setUpdateEnabled(e.target.checked)}
              data-testid="set-update-enabled"
              className="w-4 h-4 accent-primary cursor-pointer"
            />
            <span className="text-xs text-muted-foreground">
              Enable update popup for users
            </span>
          </label>
        </div>
        <p className="text-[11px] text-muted-foreground leading-relaxed mb-3">
          When enabled, every user (logged in or guest) sees a popup if their
          installed version is older than{" "}
          <code className="text-primary">Latest version</code>. If their version
          is older than{" "}
          <code className="text-primary">Min supported version</code>, the popup
          BLOCKS the app entirely until they update.
        </p>
        <InstalledVersionBanner latest={appVersion} />
        <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
          <Input
            label="Latest version (e.g. 1.2.0)"
            value={appVersion}
            onChange={setAppVersion}
            testId="set-app-version"
          />
          <Input
            label="Min supported version (force-update threshold)"
            value={minVersion}
            onChange={setMinVersion}
            testId="set-min-version"
          />
          <Input
            label="Direct APK download URL"
            value={apkUrl}
            onChange={setApkUrl}
            testId="set-apk-url"
          />
          <Input
            label="Google Play Store URL"
            value={playUrl}
            onChange={setPlayUrl}
            testId="set-play-url"
          />
          <div className="md:col-span-2 rounded-xl border border-primary/30 bg-primary/5 p-3">
            <label className="text-[11px] text-primary tracking-[0.2em] uppercase block mb-1">
              Popup delay (seconds) — wait this long before showing the popup
            </label>
            <div className="flex items-center gap-3">
              <input
                type="range"
                min={0}
                max={60}
                step={1}
                value={Math.min(60, popupDelay)}
                onChange={(e) => setPopupDelay(parseInt(e.target.value, 10) || 0)}
                data-testid="set-popup-delay-range"
                className="flex-1 accent-primary"
              />
              <input
                type="number"
                min={0}
                max={600}
                step={1}
                value={popupDelay}
                onChange={(e) => setPopupDelay(Math.max(0, Math.min(600, parseInt(e.target.value || "0", 10) || 0)))}
                data-testid="set-popup-delay"
                className="w-20 glass-input rounded-lg px-3 py-2 text-sm text-foreground outline-none text-center"
              />
              <span className="text-xs text-muted-foreground tracking-[0.2em] uppercase">s</span>
            </div>
            <p className="text-[10px] text-muted-foreground mt-1.5 leading-relaxed">
              Increase to <strong>10–14s</strong> (or more) so admins can log in before a forced popup appears.
            </p>
          </div>
        </div>
        <div className="mt-3">
          <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
            What's new (changelog)
          </label>
          <textarea
            value={changelog}
            onChange={(e) => setChangelog(e.target.value)}
            data-testid="set-changelog"
            rows={4}
            placeholder={"• Faster startup\n• Bug fixes\n• New languages"}
            className="w-full glass-input rounded-lg px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground outline-none resize-y"
          />
        </div>
      </AccordionCard>

      {/* ─── Creator Info ─── */}
      <AccordionCard
        id="creator"
        open={openSection === "creator"}
        onToggle={() => setOpenSection(openSection === "creator" ? null : "creator")}
        icon={Heart}
        title="Creator Info"
        subtitle="Shown on every user's Account page under Help & About"
        testId="admin-creator-section"
      >
        <div className="space-y-3">
        <p className="text-[11px] text-muted-foreground">
          Shown on every user's Account page under "Help & About".
        </p>
        <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
          <Input
            label="Creator name"
            value={creatorName}
            onChange={setCreatorName}
            testId="set-creator-name"
          />
          <Input
            label="Role / title (e.g. Developer)"
            value={creatorRole}
            onChange={setCreatorRole}
            testId="set-creator-role"
          />
          <div className="md:col-span-2">
            <Input
              label="Avatar URL (https://…)"
              value={creatorAvatar}
              onChange={setCreatorAvatar}
              testId="set-creator-avatar"
            />
          </div>
        </div>
        <div>
          <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
            Short bio
          </label>
          <textarea
            value={creatorBio}
            onChange={(e) => setCreatorBio(e.target.value)}
            data-testid="set-creator-bio"
            rows={3}
            className="w-full glass-input rounded-lg px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground outline-none resize-y"
          />
        </div>
        </div>
      </AccordionCard>

      {/* ─── Support & Privacy ─── */}
      <AccordionCard
        id="support"
        open={openSection === "support"}
        onToggle={() => setOpenSection(openSection === "support" ? null : "support")}
        icon={ShieldCheck}
        title="Support & Privacy"
        subtitle="Email, WhatsApp message, privacy policy text"
        testId="admin-support-section"
      >
        <div className="space-y-3">
        <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
          <Input
            label="Support email"
            value={supportEmail}
            onChange={setSupportEmail}
            testId="set-support-email"
          />
          <Input
            label="WhatsApp prefilled message"
            value={waMsg}
            onChange={setWaMsg}
            testId="set-wa-message"
          />
        </div>
        <div>
          <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
            Privacy policy text
          </label>
          <textarea
            value={privacyText}
            onChange={(e) => setPrivacyText(e.target.value)}
            data-testid="set-privacy-text"
            rows={6}
            className="w-full glass-input rounded-lg px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground outline-none resize-y leading-relaxed"
          />
          <p className="text-[10px] text-muted-foreground mt-1">
            Plain text or markdown — shown verbatim on the /privacy page.
          </p>
        </div>
        <div>
          <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
            Terms &amp; Conditions text
          </label>
          <textarea
            value={termsText}
            onChange={(e) => setTermsText(e.target.value)}
            data-testid="set-terms-text"
            rows={6}
            className="w-full glass-input rounded-lg px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground outline-none resize-y leading-relaxed"
            placeholder="Your Terms &amp; Conditions content. Plain text or markdown — shown verbatim in the About → Terms modal on Account."
          />
          <p className="text-[10px] text-muted-foreground mt-1">
            Plain text or markdown — shown verbatim in the About menu's Terms modal.
          </p>
        </div>
        </div>
      </AccordionCard>

      {/* ─── Ads (AdMob) ─── */}
      <AccordionCard
        id="ads"
        open={openSection === "ads"}
        onToggle={() => setOpenSection(openSection === "ads" ? null : "ads")}
        icon={Megaphone}
        title="Ads Settings"
        subtitle="Google AdMob — banner + interstitial on player screens"
        testId="admin-ads-section"
        badge={
          <span className={`text-[10px] px-2 py-0.5 rounded-full tracking-widest ${
            adsEnabled
              ? adsTesting
                ? "bg-amber-500/20 text-amber-400"
                : "bg-green-500/20 text-green-400"
              : "bg-muted/40 text-muted-foreground"
          }`}>
            {!adsEnabled ? "OFF" : adsTesting ? "TEST MODE" : "LIVE"}
          </span>
        }
      >
        <div className="space-y-3">
          {/* Master on/off */}
          <div className="glass rounded-xl p-4 border border-border/60">
            <label className="flex items-start gap-3 cursor-pointer select-none">
              <input
                type="checkbox"
                checked={adsEnabled}
                onChange={(e) => setAdsEnabled(e.target.checked)}
                data-testid="toggle-ads-enabled"
                className="mt-1 w-4 h-4 accent-primary cursor-pointer"
              />
              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                  <span className="text-sm font-medium text-foreground">
                    Enable Ads
                  </span>
                  <span
                    className={`text-[10px] px-2 py-0.5 rounded-full ${
                      adsEnabled
                        ? "bg-amber-500/20 text-amber-400"
                        : "bg-muted/40 text-muted-foreground"
                    }`}
                  >
                    {adsEnabled ? "ON" : "OFF"}
                  </span>
                </div>
                <p className="text-xs text-muted-foreground mt-1 leading-relaxed">
                  When ON, a banner is shown at the bottom of Live TV / Movie
                  player screens, and an interstitial fires every N channel
                  switches. When OFF, the app mounts no ad views at all.
                </p>
              </div>
            </label>
          </div>

          {/* Test mode toggle */}
          <div className="glass rounded-xl p-4 border border-border/60">
            <label className="flex items-start gap-3 cursor-pointer select-none">
              <input
                type="checkbox"
                checked={adsTesting}
                onChange={(e) => setAdsTesting(e.target.checked)}
                data-testid="toggle-ads-testing"
                className="mt-1 w-4 h-4 accent-primary cursor-pointer"
              />
              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                  <span className="text-sm font-medium text-foreground">
                    Testing Mode (safe)
                  </span>
                  <span
                    className={`text-[10px] px-2 py-0.5 rounded-full ${
                      adsTesting
                        ? "bg-green-500/20 text-green-400"
                        : "bg-red-500/20 text-red-400"
                    }`}
                  >
                    {adsTesting ? "TEST ADS" : "LIVE ADS"}
                  </span>
                </div>
                <p className="text-xs text-muted-foreground mt-1 leading-relaxed">
                  {adsTesting
                    ? "Devices see Google's universal TEST banners/interstitials. Your AdMob account is NOT billed. Safe for development."
                    : "⚠️ Devices see YOUR real ads. Invalid clicks can get your AdMob account flagged — only flip this once placements are verified."}
                </p>
              </div>
            </label>
          </div>

          {/* BUG-2 FIX (2026-05) — Users vs Guests audience toggles */}
          <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
            <div className="glass rounded-xl p-4 border border-border/60">
              <label className="flex items-start gap-3 cursor-pointer select-none">
                <input
                  type="checkbox"
                  checked={adsForUsers}
                  onChange={(e) => setAdsForUsers(e.target.checked)}
                  data-testid="toggle-ads-for-users"
                  className="mt-1 w-4 h-4 accent-primary cursor-pointer"
                />
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2">
                    <span className="text-sm font-medium text-foreground">
                      Show Ads to Users
                    </span>
                    <span className={`text-[10px] px-2 py-0.5 rounded-full ${
                      adsForUsers ? "bg-amber-500/20 text-amber-400" : "bg-muted/40 text-muted-foreground"
                    }`}>
                      {adsForUsers ? "ON" : "OFF"}
                    </span>
                  </div>
                  <p className="text-xs text-muted-foreground mt-1 leading-relaxed">
                    When ON, registered (logged-in) users see banner / interstitial / native ads exactly like guests.
                    Per-user overrides on the Subscriber card still win.
                  </p>
                </div>
              </label>
            </div>
            <div className="glass rounded-xl p-4 border border-border/60">
              <label className="flex items-start gap-3 cursor-pointer select-none">
                <input
                  type="checkbox"
                  checked={adsForGuests}
                  onChange={(e) => setAdsForGuests(e.target.checked)}
                  data-testid="toggle-ads-for-guests"
                  className="mt-1 w-4 h-4 accent-primary cursor-pointer"
                />
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2">
                    <span className="text-sm font-medium text-foreground">
                      Show Ads to Guests
                    </span>
                    <span className={`text-[10px] px-2 py-0.5 rounded-full ${
                      adsForGuests ? "bg-amber-500/20 text-amber-400" : "bg-muted/40 text-muted-foreground"
                    }`}>
                      {adsForGuests ? "ON" : "OFF"}
                    </span>
                  </div>
                  <p className="text-xs text-muted-foreground mt-1 leading-relaxed">
                    When ON, anyone using the app without logging in sees ads.
                  </p>
                </div>
              </label>
            </div>
          </div>

          {/* Ad Unit IDs */}
          <div className="grid grid-cols-1 gap-3">
            <Input
              label="AdMob App ID"
              value={adsAppId}
              onChange={setAdsAppId}
              testId="set-ads-app-id"
            />
            <Input
              label="Banner Ad Unit ID"
              value={adsBannerId}
              onChange={setAdsBannerId}
              testId="set-ads-banner-id"
            />
            <Input
              label="Interstitial Ad Unit ID"
              value={adsInterstitialId}
              onChange={setAdsInterstitialId}
              testId="set-ads-interstitial-id"
            />
            <Input
              label="Native Ad Unit ID"
              value={adsNativeId}
              onChange={setAdsNativeId}
              testId="set-ads-native-id"
            />
            <Input
              label="Rewarded Ad Unit ID"
              value={adsRewardedId}
              onChange={setAdsRewardedId}
              testId="set-ads-rewarded-id"
            />
          </div>

          {/* Interstitial frequency */}
          <div>
            <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
              Interstitial every N channel switches
            </label>
            <div className="flex items-center gap-3">
              <input
                type="number"
                min={0}
                max={100}
                value={adsInterstitialEvery}
                onChange={(e) =>
                  setAdsInterstitialEvery(Math.max(0, Math.min(100, parseInt(e.target.value) || 0)))
                }
                data-testid="set-ads-interstitial-every"
                className="w-24 glass-input rounded-lg px-3 py-2 text-sm text-foreground outline-none"
              />
              <span className="text-xs text-muted-foreground">
                0 = never · 3–10 recommended · default 5
              </span>
            </div>
          </div>

          <div className="glass rounded-xl p-3 border border-primary/20 bg-primary/5">
            <p className="text-[11px] text-muted-foreground leading-relaxed">
              <strong className="text-primary">Note:</strong> The App ID must
              also be baked into AndroidManifest.xml at build time (already
              done for v1.2.5). If you change the App ID later, you'll need
              to rebuild the APK. Banner + interstitial IDs are live-swappable
              from this panel — no rebuild needed.
            </p>
          </div>
        </div>
      </AccordionCard>

      {/* ─── Smart-TV House Banner (FEATURE 2026-01) ───
          AdMob is mobile-only, so on Samsung Tizen / LG webOS the React
          app mounts <TVBanner /> instead — pulling the snippet / image
          configured here. This entire section is HARMLESS on mobile
          (the TV component is a no-op outside isSmartTV()) so we
          surface it in the same admin UI rather than hide it. */}
      <AccordionCard
        id="tv-banner"
        open={openSection === "tv-banner"}
        onToggle={() => setOpenSection(openSection === "tv-banner" ? null : "tv-banner")}
        icon={Tv}
        title="Smart-TV House Banner"
        subtitle="Tizen / webOS only — custom HTML or image banner at the bottom of the TV screen"
        testId="admin-tv-banner-section"
        badge={
          <span
            className={`text-[10px] px-2 py-0.5 rounded-full tracking-widest ${
              tvBannerEnabled
                ? "bg-amber-500/20 text-amber-400"
                : "bg-muted/40 text-muted-foreground"
            }`}
          >
            {tvBannerEnabled ? "ON" : "OFF"}
          </span>
        }
      >
        <div className="space-y-3">
          {/* Master toggle */}
          <div className="glass rounded-xl p-4 border border-border/60">
            <label className="flex items-start gap-3 cursor-pointer select-none">
              <input
                type="checkbox"
                checked={tvBannerEnabled}
                onChange={(e) => setTvBannerEnabled(e.target.checked)}
                data-testid="toggle-tv-banner-enabled"
                className="mt-1 w-4 h-4 accent-primary cursor-pointer"
              />
              <div className="flex-1 min-w-0">
                <div className="flex items-center gap-2">
                  <span className="text-sm font-medium text-foreground">
                    Enable TV Banner
                  </span>
                  <span
                    className={`text-[10px] px-2 py-0.5 rounded-full ${
                      tvBannerEnabled
                        ? "bg-amber-500/20 text-amber-400"
                        : "bg-muted/40 text-muted-foreground"
                    }`}
                  >
                    {tvBannerEnabled ? "ON" : "OFF"}
                  </span>
                </div>
                <p className="text-xs text-muted-foreground mt-1 leading-relaxed">
                  When ON, Tizen / webOS devices render the banner you
                  configure below at the bottom of every screen. Mobile
                  users keep seeing AdMob instead.
                </p>
              </div>
            </label>
          </div>

          {/* Banner type chooser */}
          <div>
            <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
              Banner type
            </label>
            <select
              value={tvBannerType}
              onChange={(e) =>
                setTvBannerType(e.target.value === "html" ? "html" : "image")
              }
              data-testid="set-tv-banner-type"
              className="w-full glass-input rounded-lg px-3 py-2 text-sm text-foreground outline-none"
            >
              <option value="image" className="bg-background">
                Image URL + Click URL
              </option>
              <option value="html" className="bg-background">
                Raw HTML snippet
              </option>
            </select>
            <p className="text-[11px] text-muted-foreground mt-1 leading-relaxed">
              Both payloads are saved — switching modes does not erase
              the other one. Only the selected mode renders on TV.
            </p>
          </div>

          {/* Image + Click URL — shown only when type === "image" */}
          {tvBannerType === "image" && (
            <div className="space-y-3 glass rounded-xl p-4 border border-border/60">
              <Input
                label="Image URL"
                value={tvBannerImageUrl}
                onChange={setTvBannerImageUrl}
                testId="set-tv-banner-image-url"
              />
              <p className="text-[11px] text-muted-foreground -mt-2 leading-relaxed">
                Recommended size: 1280×120 (≈10.7:1) so it fits the TV
                bottom strip without letterboxing.
              </p>
              <Input
                label="Click URL (optional)"
                value={tvBannerClickUrl}
                onChange={setTvBannerClickUrl}
                testId="set-tv-banner-click-url"
              />
              <p className="text-[11px] text-muted-foreground -mt-2 leading-relaxed">
                When empty, the image renders without a link.
              </p>
            </div>
          )}

          {/* Raw HTML — shown only when type === "html" */}
          {tvBannerType === "html" && (
            <div className="space-y-2 glass rounded-xl p-4 border border-border/60">
              <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block">
                HTML snippet
              </label>
              <textarea
                value={tvBannerHtml}
                onChange={(e) => setTvBannerHtml(e.target.value)}
                rows={6}
                placeholder='<a href="https://..." target="_blank"><img src="https://..." alt="House ad" style="height:100%"/></a>'
                data-testid="set-tv-banner-html"
                className="w-full glass-input rounded-lg px-3 py-2 text-xs text-foreground placeholder:text-muted-foreground outline-none font-mono"
              />
              <p className="text-[11px] text-muted-foreground leading-relaxed">
                Rendered verbatim inside the banner container. Use inline
                styles. Only paste markup you trust — same trust model as
                AdMob's native ad creatives.
              </p>
            </div>
          )}
        </div>
      </AccordionCard>

      <AccordionCard
        id="profiles"
        open={openSection === "profiles"}
        onToggle={() => setOpenSection(openSection === "profiles" ? null : "profiles")}
        icon={Library}
        title="Shared Profiles"
        subtitle="Xtream / M3U / Stalker profiles available to logged-in users"
        testId="admin-profiles-section"
        badge={
          <span className="text-[10px] px-2 py-0.5 rounded-full bg-primary/15 text-primary tracking-widest">
            {profiles.length}
          </span>
        }
      >
        <div>
        <div className="flex items-center justify-between mb-3">
          <span className="text-xs text-muted-foreground">
            Add a profile and save settings to make it available
          </span>
          <div className="flex gap-2">
            <button
              onClick={() => addProfile("xtream")}
              data-testid="add-xtream-profile"
              className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-lg glass hover:border-primary/40 text-foreground"
            >
              <Plus className="w-3.5 h-3.5" /> Xtream
            </button>
            <button
              onClick={() => addProfile("m3u")}
              data-testid="add-m3u-profile"
              className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-lg glass hover:border-primary/40 text-foreground"
            >
              <Plus className="w-3.5 h-3.5" /> M3U
            </button>
            <button
              onClick={() => addProfile("stalker")}
              data-testid="add-stalker-profile"
              className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-lg glass hover:border-primary/40 text-foreground"
            >
              <Plus className="w-3.5 h-3.5" /> Stalker
            </button>
          </div>
        </div>

        {profiles.length === 0 ? (
          <p className="text-muted-foreground text-xs bg-muted/30 border border-border rounded-lg px-3 py-3">
            No shared profiles yet. Add one above — logged-in users will be able
            to pick it from the playlist dialog. Guests never see these.
          </p>
        ) : (
          <div className="space-y-3">
            {profiles.map((p, idx) => (
              <div
                key={p.id || idx}
                data-testid={`profile-row-${idx}`}
                className="glass rounded-xl p-3 border border-border/60"
              >
                <div className="flex items-center gap-2 mb-2">
                  <span className="text-[10px] uppercase tracking-widest text-primary/80 bg-primary/10 px-2 py-0.5 rounded">
                    {p.kind === "m3u"
                      ? "M3U"
                      : p.kind === "stalker"
                        ? "Stalker"
                        : "Xtream"}
                  </span>
                  <button
                    onClick={() => removeProfile(idx)}
                    data-testid={`remove-profile-${idx}`}
                    className="ml-auto text-muted-foreground hover:text-destructive transition-colors"
                    aria-label="Remove"
                  >
                    <Trash2 className="w-4 h-4" />
                  </button>
                </div>
                <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
                  <Input
                    label="Profile Name"
                    value={p.name}
                    onChange={(v) => updateProfile(idx, { name: v })}
                    testId={`profile-name-${idx}`}
                  />
                  {p.kind === "xtream" ? (
                    <>
                      <Input
                        label="Server URL"
                        value={p.server ?? ""}
                        onChange={(v) => updateProfile(idx, { server: v })}
                        testId={`profile-server-${idx}`}
                      />
                      <Input
                        label="Username"
                        value={p.username ?? ""}
                        onChange={(v) => updateProfile(idx, { username: v })}
                        testId={`profile-user-${idx}`}
                      />
                      <Input
                        label="Password"
                        value={p.password ?? ""}
                        onChange={(v) => updateProfile(idx, { password: v })}
                        testId={`profile-pass-${idx}`}
                      />
                    </>
                  ) : p.kind === "stalker" ? (
                    <>
                      <Input
                        label="Portal URL"
                        value={p.portal_url ?? ""}
                        onChange={(v) => updateProfile(idx, { portal_url: v })}
                        testId={`profile-portal-${idx}`}
                      />
                      <Input
                        label="MAC Address (00:1A:79:XX:XX:XX)"
                        value={p.mac_address ?? ""}
                        onChange={(v) =>
                          updateProfile(idx, {
                            mac_address: v
                              .replace(/[^0-9A-Fa-f]/g, "")
                              .toUpperCase()
                              .slice(0, 12)
                              .match(/.{1,2}/g)
                              ?.join(":") ?? "",
                          })
                        }
                        testId={`profile-mac-${idx}`}
                      />
                      <div className="md:col-span-2">
                        <StalkerTestButton
                          portalUrl={p.portal_url ?? ""}
                          mac={p.mac_address ?? ""}
                          testId={`profile-stalker-test-${idx}`}
                        />
                      </div>
                    </>
                  ) : (
                    <div className="md:col-span-2 space-y-2">
                      <Input
                        label="M3U URL"
                        value={p.m3u_url ?? ""}
                        onChange={(v) => updateProfile(idx, { m3u_url: v })}
                        testId={`profile-m3u-${idx}`}
                      />
                      <M3UFileField
                        idx={idx}
                        content={p.m3u_content ?? ""}
                        onChange={(c) => updateProfile(idx, { m3u_content: c })}
                      />
                    </div>
                  )}
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
      </AccordionCard>

      {/* Sticky Save button — saves everything in all sections at once */}
      <div className="flex justify-end pt-2">
        <button
          onClick={save}
          aria-busy={saving || undefined} data-loading={saving || undefined}
          data-testid="set-save"
          className="flex items-center gap-2 px-6 py-3 rounded-2xl bg-primary hover:brightness-110 text-primary-foreground font-semibold text-sm transition-all disabled:opacity-60 shadow-[0_8px_30px_hsla(40,80%,55%,0.35)]"
        >
          {saving ? <Loader2 className="w-4 h-4 animate-spin" /> : <Save className="w-4 h-4" />}
          {saving ? t("common.saving") : t("admin.saveSettings")}
        </button>
      </div>
    </>
  );
};

const UserRow = ({
  user,
  onChanged,
  onToast,
}: {
  user: NadiUser;
  onChanged: () => void;
  onToast: (m: string) => void;
}) => {
  const { t } = useTranslation();
  const [busy, setBusy] = useState(false);
  const [pwd, setPwd] = useState("");
  const [mode, setMode] = useState<"shared" | "own">(user.xtream_mode || "shared");
  const [xs, setXs] = useState(user.xtream_server || "");
  const [xu, setXu] = useState(user.xtream_username || "");
  const [xp, setXp] = useState(user.xtream_password || "");

  // Hybrid dual-source
  const [liveType, setLiveType] = useState(user.live_source_type || "");
  const [liveUrl, setLiveUrl] = useState(user.live_url || "");
  const [liveUser, setLiveUser] = useState(user.live_user || "");
  const [livePass, setLivePass] = useState(user.live_pass || "");
  const [liveMac, setLiveMac] = useState(user.live_mac || "");
  const [vodType, setVodType] = useState(user.vod_source_type || "");
  const [vodUrl, setVodUrl] = useState(user.vod_url || "");
  const [vodUser, setVodUser] = useState(user.vod_user || "");
  const [vodPass, setVodPass] = useState(user.vod_pass || "");
  const [vodMac, setVodMac] = useState(user.vod_mac || "");

  // Per-user ad override. Default = follow global (no explicit override).
  //
  // BUG-1 FIX (2026-05): the previous default fell back to the bogus
  // expression `!user.is_expired === false` — which, for any non-expired
  // user (the common case), evaluates to `false` (because `!false ===
  // false` → `true === false` → `false`). Combined with the missing
  // useEffect-sync below, that's why the toggle visually "reverted to
  // Disabled" the moment the parent refreshed user data after save.
  //
  // The correct default is simply the persisted boolean if present, or
  // `false` (= no override / inherit global). Never read the inverse of
  // an unrelated column.
  const initialAds: boolean =
    typeof user.ads_enabled === "boolean" ? user.ads_enabled : false;
  const [adsEnabled, setAdsEnabled] = useState<boolean>(initialAds);

  // BUG-1 FIX: keep local toggle state in sync with the server-side
  // value when the parent re-fetches the user list after any save
  // (toggleAds, saveXtream, extendDays, etc.). Without this, `useState`
  // initialiser would only run on the first mount and stale state could
  // mask a successful save — or worse, an actually-failed save would
  // still look "ON" locally. We trust the server's value here.
  useEffect(() => {
    if (typeof user.ads_enabled === "boolean") {
      setAdsEnabled(user.ads_enabled);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [user.ads_enabled]);

  const toggleAds = async (next: boolean) => {
    setAdsEnabled(next);
    setBusy(true);
    try {
      await apiUpdateUser(user.id, { ads_enabled: next });
      onToast(
        next
          ? t("admin.adsForcedOn", "Ads forced ON for this user")
          : t("admin.adsForcedOff", "Ads disabled for this user"),
      );
      onChanged();
    } catch (e) {
      // revert on failure
      setAdsEnabled(!next);
      onToast(e instanceof Error ? e.message : t("admin.opFailed"));
    } finally {
      setBusy(false);
    }
  };

  const extendDays = async (days: number) => {
    setBusy(true);
    try {
      await apiUpdateUser(user.id, { extend_days: days });
      onToast(days > 0 ? t("admin.dayAdded", { count: days }) : t("admin.dayRemoved", { count: -days }));
      onChanged();
    } catch (e) {
      onToast(e instanceof Error ? e.message : t("admin.opFailed"));
    } finally {
      setBusy(false);
    }
  };

  const savePassword = async () => {
    if (!pwd) return;
    setBusy(true);
    try {
      await apiUpdateUser(user.id, { password: pwd });
      onToast(t("admin.passwordUpdated"));
      setPwd("");
      onChanged();
    } catch (e) {
      onToast(e instanceof Error ? e.message : t("admin.opFailed"));
    } finally {
      setBusy(false);
    }
  };

  const saveXtream = async () => {
    setBusy(true);
    try {
      // BUG-1 FIX (2026-05): also bundle the current ad-toggle state so
      // saving Xtream from this card is atomic — admin no longer has to
      // remember to flip the toggle separately. The toggle still saves
      // standalone via `toggleAds()` for instant feedback.
      await apiUpdateUser(user.id, {
        xtream_mode: mode,
        xtream_server: xs,
        xtream_username: xu,
        xtream_password: xp,
        ads_enabled: adsEnabled,
      });
      onToast(t("admin.xtreamSaved"));
      onChanged();
    } catch (e) {
      onToast(e instanceof Error ? e.message : t("admin.opFailed"));
    } finally {
      setBusy(false);
    }
  };

  const saveDualSource = async () => {
    setBusy(true);
    try {
      await apiUpdateUser(user.id, {
        live_source_type: liveType || undefined,
        live_url: liveUrl || undefined,
        live_user: liveUser || undefined,
        live_pass: livePass || undefined,
        live_mac: liveMac || undefined,
        vod_source_type: vodType || undefined,
        vod_url: vodUrl || undefined,
        vod_user: vodUser || undefined,
        vod_pass: vodPass || undefined,
        vod_mac: vodMac || undefined,
      });
      onToast("Hybrid sources saved");
      onChanged();
    } catch (e) {
      onToast(e instanceof Error ? e.message : t("admin.opFailed"));
    } finally {
      setBusy(false);
    }
  };

  const remove = async () => {
    // Samsung Tizen QA bans native confirm() — use sonner toast with an
    // action button instead (same user-confirmation UX, fully styled,
    // dismissible with the TV remote).
    sonnerToast.warning(
      t("admin.confirmDeleteUser", { username: user.username }),
      {
        action: {
          label: t("admin.deleteUser"),
          onClick: async () => {
            setBusy(true);
            try {
              await apiDeleteUser(user.id);
              onToast(t("admin.userDeleted"));
              onChanged();
            } catch (e) {
              onToast(e instanceof Error ? e.message : t("admin.opFailed"));
            } finally {
              setBusy(false);
            }
          },
        },
        duration: 8000,
      },
    );
  };

  const statusColor = user.is_expired
    ? "text-destructive"
    : (user.days_remaining ?? 0) <= 3
      ? "text-amber-400"
      : "text-primary";

  return (
    <div className="rounded-xl border border-border/40 glass p-4">
      <div className="flex flex-col md:flex-row md:items-center md:justify-between gap-3">
        <div className="flex items-center gap-4">
          <div className="w-10 h-10 rounded-full glass flex items-center justify-center">
            <Tv className="w-4 h-4 text-primary" />
          </div>
          <div>
            <p data-testid={`user-${user.username}-name`} className="text-foreground font-medium">
              {user.username}
            </p>
            <p className="text-muted-foreground text-xs flex items-center gap-2">
              <Calendar className="w-3 h-3" />
              {user.expiry_at ? new Date(user.expiry_at).toLocaleDateString() : t("admin.noExpiry")}
              <span className={`ms-2 ${statusColor}`}>
                {user.is_expired
                  ? t("admin.expired")
                  : user.days_remaining != null
                    ? t("admin.daysLeft", { count: user.days_remaining })
                    : ""}
              </span>
            </p>
          </div>
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <button
            onClick={() => extendDays(30)}
            aria-busy={busy || undefined} data-loading={busy || undefined}
            data-testid={`user-${user.username}-add30`}
            className="px-3 py-1.5 rounded-lg glass text-xs text-primary hover:border-primary/40 transition-colors disabled:opacity-60"
          >
            {t("admin.addDays", { n: 30 })}
          </button>
          <button
            onClick={() => extendDays(7)}
            aria-busy={busy || undefined} data-loading={busy || undefined}
            className="px-3 py-1.5 rounded-lg glass text-xs text-primary hover:border-primary/40 transition-colors disabled:opacity-60"
          >
            {t("admin.addDays", { n: 7 })}
          </button>
          <button
            onClick={() => extendDays(-7)}
            aria-busy={busy || undefined} data-loading={busy || undefined}
            className="px-3 py-1.5 rounded-lg glass text-xs text-muted-foreground hover:border-destructive/40 transition-colors disabled:opacity-60"
          >
            {t("admin.subDays", { n: 7 })}
          </button>
          <button
            onClick={remove}
            aria-busy={busy || undefined} data-loading={busy || undefined}
            data-testid={`user-${user.username}-delete`}
            className="px-3 py-1.5 rounded-lg glass text-xs text-destructive hover:border-destructive/40 transition-colors disabled:opacity-60 flex items-center gap-1"
          >
            <Trash2 className="w-3 h-3" /> {t("admin.deleteUser")}
          </button>
        </div>
      </div>

      {/* Advanced: xtream + password */}
      <details className="mt-3">
        <summary className="cursor-pointer text-xs text-muted-foreground tracking-[0.2em] uppercase hover:text-primary">
          {t("admin.advanced")}
        </summary>

        {/* Per-user Ads toggle (admin override) */}
        <div className="mt-3 rounded-xl border border-border/40 bg-background/30 p-3 flex items-center justify-between gap-3">
          <div className="min-w-0">
            <p className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase">
              {t("admin.adsToggleLabel", "Ads")}
            </p>
            <p className="text-foreground text-xs mt-0.5">
              {adsEnabled
                ? t("admin.adsToggleOn", "Enabled — this user sees ads")
                : t("admin.adsToggleOff", "Disabled — this user is ad-free")}
            </p>
          </div>
          <button
            type="button"
            onClick={() => toggleAds(!adsEnabled)}
            aria-busy={busy || undefined} data-loading={busy || undefined}
            data-testid={`user-${user.username}-ads-toggle`}
            aria-pressed={adsEnabled}
            className={`relative w-12 h-6 rounded-full transition-colors disabled:opacity-50 shrink-0 ${
              adsEnabled ? "bg-primary/80" : "bg-muted/50"
            }`}
          >
            <span
              className={`absolute top-0.5 ${adsEnabled ? "right-0.5" : "left-0.5"} w-5 h-5 rounded-full bg-background shadow transition-all`}
            />
          </button>
        </div>

        <div className="mt-3 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3">
          <div>
            <label className="text-[11px] text-muted-foreground tracking-[0.2em] uppercase block mb-1">
              {t("admin.xtreamMode")}
            </label>
            <select
              value={mode}
              onChange={(e) => setMode(e.target.value as "shared" | "own")}
              className="w-full glass-input rounded-lg px-3 py-2 text-sm text-foreground outline-none"
            >
              <option value="shared">{t("admin.modeShared")}</option>
              <option value="own">{t("admin.modeOwn")}</option>
            </select>
          </div>
          <Input label={t("admin.server")} value={xs} onChange={setXs} />
          <Input label={t("admin.xtUser")} value={xu} onChange={setXu} />
          <Input label={t("admin.xtPass")} value={xp} onChange={setXp} />
          <div className="lg:col-span-4 flex gap-2 justify-end">
            <button
              onClick={saveXtream}
              aria-busy={busy || undefined} data-loading={busy || undefined}
              className="flex items-center gap-2 px-4 py-2 rounded-lg glass text-xs text-primary hover:border-primary/40 transition-colors disabled:opacity-60"
            >
              <Server className="w-3 h-3" /> {t("admin.saveXtream")}
            </button>
          </div>
        </div>

        {/* Password */}
        <div className="mt-3 flex items-center gap-2">
          <input type="text" value={pwd} onChange={(e) => setPwd(e.target.value)}
            placeholder={t("admin.newPassword")}
            className="flex-1 glass-input rounded-lg px-3 py-2 text-sm text-foreground outline-none" />
          <button onClick={() => { if (!busy && pwd) savePassword(); }} aria-busy={busy || undefined} data-loading={busy || undefined} disabled={!pwd}
            className="px-4 py-2 rounded-lg glass text-xs text-primary hover:border-primary/40 transition-colors disabled:opacity-60">
            {t("admin.updatePassword")}
          </button>
        </div>

        {/* Hybrid Dual-Source */}
        <details className="mt-3">
          <summary className="cursor-pointer text-xs text-primary/80 tracking-[0.2em] uppercase hover:text-primary font-bold">
            HYBRID SOURCES (LIVE + VOD)
          </summary>
          <div className="mt-2 space-y-3">
            <div className="rounded-lg border border-primary/20 bg-primary/5 p-3">
              <p className="text-[10px] text-primary tracking-[0.2em] uppercase font-bold mb-2">Source A — Live TV</p>
              <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-2">
                <div>
                  <label className="text-[10px] text-muted-foreground block mb-1">Type</label>
                  <select value={liveType} onChange={(e) => setLiveType(e.target.value)}
                    className="w-full glass-input rounded-lg px-2 py-1.5 text-xs text-foreground outline-none">
                    <option value="">None</option>
                    <option value="xtream">Xtream</option>
                    <option value="m3u">M3U</option>
                    <option value="stalker">Stalker</option>
                  </select>
                </div>
                <Input label="URL" value={liveUrl} onChange={setLiveUrl} />
                {liveType === "xtream" && <Input label="User" value={liveUser} onChange={setLiveUser} />}
                {liveType === "xtream" && <Input label="Pass" value={livePass} onChange={setLivePass} />}
                {liveType === "stalker" && <Input label="MAC" value={liveMac} onChange={setLiveMac} />}
              </div>
            </div>
            <div className="rounded-lg border border-blue-500/20 bg-blue-500/5 p-3">
              <p className="text-[10px] text-blue-400 tracking-[0.2em] uppercase font-bold mb-2">Source B — Movies & Series</p>
              <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-2">
                <div>
                  <label className="text-[10px] text-muted-foreground block mb-1">Type</label>
                  <select value={vodType} onChange={(e) => setVodType(e.target.value)}
                    className="w-full glass-input rounded-lg px-2 py-1.5 text-xs text-foreground outline-none">
                    <option value="">None</option>
                    <option value="xtream">Xtream</option>
                    <option value="m3u">M3U</option>
                    <option value="stalker">Stalker</option>
                  </select>
                </div>
                <Input label="URL" value={vodUrl} onChange={setVodUrl} />
                {vodType === "xtream" && <Input label="User" value={vodUser} onChange={setVodUser} />}
                {vodType === "xtream" && <Input label="Pass" value={vodPass} onChange={setVodPass} />}
                {vodType === "stalker" && <Input label="MAC" value={vodMac} onChange={setVodMac} />}
              </div>
            </div>
            <div className="flex justify-end">
              <button onClick={saveDualSource} aria-busy={busy || undefined} data-loading={busy || undefined}
                className="flex items-center gap-2 px-4 py-2 rounded-lg glass text-xs text-primary hover:border-primary/40 transition-colors disabled:opacity-60">
                <Server className="w-3 h-3" /> Save Hybrid Sources
              </button>
            </div>
          </div>
        </details>
      </details>
    </div>
  );
};

// Unused lucide import — keep for potential future use (lint appeasement)
export const _unused = MessageCircle;

export default Admin;
