// screens-dashboard.jsx

const _claimToRow = (c) => ({
  time: c.time ? new Date(c.time).toTimeString().slice(0, 8) : "—",
  plat: c.platform || "—",
  code: c.code || "—",
  elapsed: c.elapsed_ms ? `${c.elapsed_ms}ms` : "—",
  res: c.status === "claimed" ? "ok" : "err",
  src: c.source || "api",
});

const Sparkline = ({ data, color = "var(--accent)" }) => {
  const w = 240, h = 40;
  const max = Math.max(...data, 1);
  const pts = data.map((v, i) => `${(i/(data.length-1))*w},${h - (v/max)*h}`).join(" ");
  return (
    <svg className="spark" viewBox={`0 0 ${w} ${h}`}>
      <polyline points={pts} fill="none" stroke={color} strokeWidth="2" strokeLinejoin="round" />
      <polyline points={`${pts} ${w},${h} 0,${h}`} fill={color} opacity=".12" />
    </svg>
  );
};

const FeedTable = ({ rows }) => (
  <div className="log">
    <div className="log-row head">
      <span>time</span><span>plat</span><span>code</span><span>elapsed</span><span>res</span>
    </div>
    {rows.map((r, i) => (
      <div key={r.time + r.code} className={"log-row " + (r._new ? "appear" : "")}>
        <span className="muted">{r.time}</span>
        <span style={{ fontSize: 11 }}>{r.plat.replace("stake_", ".").replace("shuffle","shuf").replace("thrill","thrl")}</span>
        <span style={{ fontWeight: 600 }}>{r.code}</span>
        <span>{r.elapsed}</span>
        <span className={r.res === "ok" ? "ok" : r.res === "pending" ? "pending" : "err"}>
          {r.res === "ok" ? "✓" : r.res === "pending" ? "…" : "✕"}
        </span>
      </div>
    ))}
  </div>
);

const Sidebar = ({ active, setActive, user }) => {
  const items = [
    ["dashboard", "gauge",   "Overview"],
    ["codes",     "code",    "Codes"],
    ["claims",    "bolt",    "Claims"],
    ["platforms", "globe",   "Platforms"],
  ];
  const admin = [
    ["users",        "users",   "Users"],
    ["broadcast",    "code",    "Send Code"],
    ["admin-claims", "bolt",    "Claim History"],
    ["promos",       "credit",  "Promos"],
    ["revenue",      "chart",   "Revenue"],
    ["health",       "shield",  "Health"],
  ];
  return (
    <aside className="sidebar">
      <div className="group-label">Workspace</div>
      {items.map(([id, ic, label]) => (
        <div key={id} className={"nav-item " + (active === id ? "active" : "")} onClick={() => setActive(id)}>
          <Icon name={ic} /> <span>{label}</span>
        </div>
      ))}
      <div className="nav-item" style={{ opacity: 0.4, cursor: "not-allowed" }}>
        <Icon name="puzzle" /> <span>Extension</span>
        <span style={{ marginLeft: "auto", fontSize: 10, color: "var(--text-3)" }}>soon</span>
      </div>
      <div className="group-label">Account</div>
      <div className={"nav-item " + (active === "billing"  ? "active" : "")} onClick={() => setActive("billing")}><Icon name="credit" /> <span>Billing</span></div>
      <div className={"nav-item " + (active === "settings" ? "active" : "")} onClick={() => setActive("settings")}><Icon name="settings" /> <span>Settings</span></div>
      {user?.is_admin && (
        <>
          <div className="group-label">Admin · staff</div>
          {admin.map(([id, ic, label]) => (
            <div key={id} className={"nav-item " + (active === id ? "active" : "")} onClick={() => setActive(id)}>
              <Icon name={ic} /> <span>{label}</span>
            </div>
          ))}
        </>
      )}
    </aside>
  );
};

const Dashboard = ({ user, path, plan, goto, addToast }) => {
  const [feed, setFeed]   = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [active, setActive] = React.useState("dashboard");
  const [tokens, setTokens] = React.useState({ com: 0, us: 0 });
  const [refreshing, setRefreshing] = React.useState(false);

  const stats = React.useMemo(() => {
    const ok = feed.filter(r => r.res === "ok");
    const api = ok.filter(r => r.src === "api");
    const ext = ok.filter(r => r.src === "ext");
    return {
      claims7d: feed.length,
      fromApi: api.length,
      fromExt: ext.length,
      successRate: feed.length ? Math.round(ok.length / feed.length * 100) : 0,
    };
  }, [feed]);

  const fetchFeed = React.useCallback(async (showRefresh) => {
    const token = localStorage.getItem("cc_token");
    if (!token) return;
    if (showRefresh) setRefreshing(true);
    try {
      const [cr, hr] = await Promise.all([
        fetch("/api/claims", { headers: { Authorization: `Bearer ${token}` } }),
        fetch("/health"),
      ]);
      if (cr.ok) {
        const d = await cr.json();
        setFeed((d.claims || []).map(_claimToRow));
      }
      if (hr.ok) {
        const h = await hr.json();
        const ts = h.turnstile || {};
        setTokens({ com: ts.stake_com?.size ?? 0, us: ts.stake_us?.size ?? 0 });
      }
    } catch (_) {}
    setLoading(false);
    setRefreshing(false);
  }, []);

  React.useEffect(() => {
    fetchFeed(false);
    const t = setInterval(() => fetchFeed(false), 15000);
    return () => clearInterval(t);
  }, [fetchFeed]);

  const isAdmin = ["users", "broadcast", "admin-claims", "promos", "revenue", "health"].includes(active);
  React.useEffect(() => {
    if (isAdmin && !user?.is_admin) setActive("dashboard");
  }, [isAdmin, user]);

  return (
    <div className="container fade-in" style={{ maxWidth: 1300 }}>
      <div className="dash">
        <Sidebar active={active} setActive={setActive} user={user} />

        {isAdmin && user?.is_admin
          ? <AdminPanel active={active} user={user} />
          : active === "claims"
            ? <ClaimsPanel user={user} />
            : active === "codes"
              ? <CodesPanel />
              : active === "billing"
                ? <BillingPanel user={user} />
                : active === "settings"
                  ? <SettingsPanel user={user} />
                  : active === "platforms"
                    ? <PlatformsPanel path={path} />
                    : <MainPanel
                    user={user} plan={plan} path={path}
                    feed={feed} stats={stats} tokens={tokens}
                    loading={loading} refreshing={refreshing}
                    onRefresh={() => fetchFeed(true)}
                    goto={goto}
                  />
        }
      </div>
    </div>
  );
};

const MainPanel = ({ user, plan, path, feed, stats, tokens, loading, refreshing, onRefresh, goto }) => (
  <div className="stack-lg" style={{ minWidth: 0 }}>
    {/* header */}
    <div className="row between wrap" style={{ gap: 12 }}>
      <div>
        <div className="row" style={{ gap: 8, marginBottom: 6 }}>
          <Pill kind="live" dot>API · cloud</Pill>
          <Pill>{plan || "free"}</Pill>
          {tokens.com > 0 && <Pill kind="ok" dot>turnstile · com {tokens.com}</Pill>}
          {tokens.us > 0 && <Pill kind="ok" dot>us {tokens.us}</Pill>}
        </div>
        <h2 style={{ fontSize: 28 }}>
          Hi {user?.username || user?.name || "there"}.
        </h2>
        <p className="muted" style={{ fontSize: 13, marginTop: 4 }}>
          {loading ? "Loading your claims…" : `${stats.claims7d} claims recorded · ${stats.successRate}% success rate`}
        </p>
      </div>
      <Btn sm onClick={onRefresh} disabled={refreshing}>
        <Icon name="refresh" /> {refreshing ? "Refreshing…" : "Refresh"}
      </Btn>
    </div>

    {/* stats */}
    <div className="grid-4">
      <Stat k="total claims" n={stats.claims7d} />
      <Stat k="from api" n={stats.fromApi} />
      <Stat k="from ext" n={stats.fromExt} />
      <Stat k="success rate" n={stats.claims7d ? `${stats.successRate}%` : "—"} />
    </div>

    {/* two engine cards */}
    <div className="grid-2">
      <Card accent style={{ background: "color-mix(in oklab, var(--surf-2) 70%, var(--accent-2) 30%)" }}>
        <div className="row between" style={{ marginBottom: 10 }}>
          <span className="row" style={{ gap: 8 }}>
            <Icon name="cloud" style={{ color: "var(--accent)" }} />
            <strong style={{ fontSize: 15 }}>API · Stake.com / Stake.us</strong>
          </span>
          <Pill kind="live" dot>online</Pill>
        </div>
        <Sparkline data={feed.slice(-13).map((r,i,a) => a.filter((_,j)=>j<=i&&_.res==="ok").length)} />
        <div className="row between" style={{ marginTop: 10, fontSize: 12 }}>
          <span className="muted">
            {stats.fromApi} successful API claims
          </span>
          <span className="row" style={{ gap: 6 }}>
            {tokens.com > 0 && <Pill kind="ok" dot>com token ready</Pill>}
            {tokens.us  > 0 && <Pill kind="ok" dot>us token ready</Pill>}
            {tokens.com === 0 && tokens.us === 0 && <Pill>no tokens yet</Pill>}
          </span>
        </div>
        <div className="divider"></div>
        <div className="row between" style={{ fontSize: 12 }}>
          <span className="muted">Decodo residential proxy · rotates per claim</span>
        </div>
      </Card>

      <Card>
        <div className="row between" style={{ marginBottom: 10 }}>
          <span className="row" style={{ gap: 8 }}>
            <Icon name="puzzle" style={{ color: "var(--accent)" }} />
            <strong style={{ fontSize: 15 }}>Extension · Shuffle / Thrill</strong>
          </span>
          <Pill>not available yet</Pill>
        </div>
        <Sparkline data={[0,0,0,0,0,0,0,0,0,0,0,0,0]} color="var(--text-3)" />
        <div className="row between" style={{ marginTop: 10, fontSize: 12 }}>
          <span className="muted">Browser extension coming soon</span>
        </div>
        <div className="divider"></div>
        <div className="row between" style={{ fontSize: 12 }}>
          <span className="muted">Shuffle &amp; Thrill support in development</span>
        </div>
      </Card>
    </div>

    {/* feed */}
    <div className="grid-2" style={{ gridTemplateColumns: "1.5fr 1fr" }}>
      <Card style={{ padding: 0 }}>
        <div className="row between" style={{ padding: 14, borderBottom: "1px solid var(--border)" }}>
          <span className="row" style={{ gap: 8 }}>
            <span className="glow-ring"></span>
            <strong style={{ fontSize: 13 }}>Claim history</strong>
          </span>
          <Pill kind={feed.length ? "live" : ""}>{loading ? "loading…" : feed.length ? `${feed.length} records` : "no claims yet"}</Pill>
        </div>
        {feed.length === 0 && !loading
          ? <p className="muted" style={{ padding: 24, fontSize: 13 }}>No claims yet. Codes are claimed automatically when BoostMonitor sends them.</p>
          : <FeedTable rows={feed.slice(0, 20)} />}
      </Card>

      <div>
        <p className="muted" style={{ fontSize: 12, marginBottom: 8 }}>API status</p>
        <Card>
          <div className="stack-sm">
            <div className="row between">
              <span className="muted" style={{ fontSize: 12 }}>Total claims</span>
              <strong>{stats.claims7d}</strong>
            </div>
            <div className="row between">
              <span className="muted" style={{ fontSize: 12 }}>API claims</span>
              <strong>{stats.fromApi}</strong>
            </div>
            <div className="row between">
              <span className="muted" style={{ fontSize: 12 }}>Success rate</span>
              <strong>{stats.claims7d ? `${stats.successRate}%` : "—"}</strong>
            </div>
            <div className="divider"></div>
            <div className="row between">
              <span className="muted" style={{ fontSize: 12 }}>Last claim</span>
              <span style={{ fontSize: 12 }}>{feed[0] ? `${feed[0].code} · ${feed[0].elapsed}` : "—"}</span>
            </div>
          </div>
        </Card>
      </div>
    </div>
  </div>
);

const ExtensionPanel = ({ user }) => {
  const [token, setToken] = React.useState("");
  const [copied, setCopied] = React.useState(false);
  const [error, setError] = React.useState("");

  const hasAccess = user?.extension_access;

  const downloadUrl = (browser) =>
    `/api/extension/download/${browser}?token=${encodeURIComponent(token)}`;

  const copyToken = () => {
    navigator.clipboard.writeText(token).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    });
  };

  return (
    <div className="stack-lg">
      <div>
        <span className="eyebrow">extension</span>
        <h2 style={{ fontSize: 24, marginTop: 4 }}>Browser Extension</h2>
        <p className="muted" style={{ fontSize: 13, marginTop: 6 }}>
          Paste your token (from support / your approval email), then download the zip for your browser.
          Each zip is personal — your token is baked in.
        </p>
      </div>

      {!hasAccess && (
        <Card>
          <div className="row" style={{ gap: 10 }}>
            <Icon name="lock" style={{ color: "var(--warn)" }} />
            <div>
              <strong>Extension access required</strong>
              <p className="muted" style={{ fontSize: 13, margin: "4px 0 0" }}>
                Extension access is not yet available. Check back soon.
              </p>
            </div>
          </div>
        </Card>
      )}

      <Card lift>
        <div className="stack">
          <Field label="Your extension token" hint="Provided by admin when your account is approved">
            <div className="row" style={{ gap: 8 }}>
              <Input
                type="password"
                placeholder="paste token here…"
                value={token}
                onChange={e => { setToken(e.target.value); setError(""); }}
                style={{ flex: 1, fontFamily: "var(--font-mono)" }}
              />
              {token && (
                <Btn sm onClick={copyToken}><Icon name="copy"/> {copied ? "Copied!" : "Copy"}</Btn>
              )}
            </div>
          </Field>
          {error && <p style={{ color: "var(--err)", fontSize: 13, margin: 0 }}>{error}</p>}
        </div>
      </Card>

      <div>
        <div className="eyebrow" style={{ marginBottom: 12 }}>download for your browser</div>
        <div className="grid-3" style={{ gap: 14 }}>
          {[
            { id: "chrome",  label: "Chrome / Brave", sub: "Manifest V3 · load unpacked" },
            { id: "firefox", label: "Firefox",         sub: "Manifest V2 · about:debugging" },
            { id: "safari",  label: "Safari",          sub: "Requires Xcode — contact support" },
          ].map(b => (
            <Card key={b.id} style={{ textAlign: "center" }}>
              <Browser name={b.id === "chrome" ? "chrome" : b.id === "firefox" ? "firefox" : "safari"} size={40} />
              <div style={{ fontWeight: 600, fontSize: 14, marginTop: 10 }}>{b.label}</div>
              <div className="muted" style={{ fontSize: 11, marginTop: 4, marginBottom: 14 }}>{b.sub}</div>
              {b.id === "safari" ? (
                <Btn sm block kind="ghost" disabled>Contact support</Btn>
              ) : (
                <a
                  href={token ? downloadUrl(b.id) : "#"}
                  onClick={e => { if (!token) { e.preventDefault(); setError("Paste your token first."); } }}
                  style={{ textDecoration: "none", display: "block" }}>
                  <Btn kind={token ? "primary" : "ghost"} block sm disabled={!token}>
                    <Icon name="external"/> Download zip
                  </Btn>
                </a>
              )}
            </Card>
          ))}
        </div>
      </div>

      <Card flat style={{ borderStyle: "dashed" }}>
        <div className="eyebrow" style={{ marginBottom: 8 }}>install guide</div>
        <div className="stack" style={{ fontSize: 13 }}>
          <div className="row" style={{ gap: 10, alignItems: "flex-start" }}>
            <Pill>1</Pill>
            <span>Paste your token above and click Download for your browser.</span>
          </div>
          <div className="row" style={{ gap: 10, alignItems: "flex-start" }}>
            <Pill>2</Pill>
            <span><strong>Chrome/Brave:</strong> go to <code style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>chrome://extensions</code>, enable Developer Mode, click "Load unpacked", select the unzipped folder.</span>
          </div>
          <div className="row" style={{ gap: 10, alignItems: "flex-start" }}>
            <Pill>2</Pill>
            <span><strong>Firefox:</strong> go to <code style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>about:debugging#/runtime/this-firefox</code>, click "Load Temporary Add-on", select <code style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>manifest.json</code>.</span>
          </div>
          <div className="row" style={{ gap: 10, alignItems: "flex-start" }}>
            <Pill>3</Pill>
            <span>Pin the extension icon. Log into Shuffle / Thrill in a normal tab — the extension detects your session and starts listening automatically.</span>
          </div>
          <div className="row" style={{ gap: 10, alignItems: "flex-start" }}>
            <Pill kind="warn">!</Pill>
            <span>Your token is personal — do <strong>not</strong> share your zip or token. If compromised, contact support to get it revoked and re-issued.</span>
          </div>
        </div>
      </Card>
    </div>
  );
};

const PlatformsPanel = ({ path }) => (
  <div className="stack-lg">
    <div className="row between">
      <div>
        <span className="eyebrow">platforms</span>
        <h2 style={{ fontSize: 24, marginTop: 4 }}>Connections &amp; sessions</h2>
      </div>
      <Btn sm><Icon name="settings"/> Manage proxies</Btn>
    </div>
    <div className="grid-2">
      {[
        { id: "stake_com", via: "API · cloud",       note: "24/7 server-side claiming" },
        { id: "stake_us",  via: "API · cloud",       note: "Sweeps only · Texas proxy" },
        { id: "shuffle",   via: "Extension",         note: "Not available yet", disabled: true },
        { id: "thrill",    via: "Extension",         note: "Not available yet", disabled: true },
      ].map(p => (
        <Card key={p.id} style={p.disabled ? { opacity: 0.5 } : {}}>
          <div className="row between">
            <Platform name={p.id} />
            <Pill kind={p.disabled ? "" : "live"} dot={!p.disabled}>{p.disabled ? "coming soon" : "active"}</Pill>
          </div>
          <p className="muted" style={{ fontSize: 12, marginTop: 8 }}>{p.note}</p>
          <div className="row between" style={{ marginTop: 12, fontSize: 12 }}>
            <span className="muted">via · {p.via}</span>
          </div>
        </Card>
      ))}
    </div>
  </div>
);

const ClaimsPanel = ({ user }) => {
  const [claims, setClaims] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const token = localStorage.getItem("cc_token");

  React.useEffect(() => {
    fetch("/api/claims", { headers: { Authorization: `Bearer ${token}` } })
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d?.claims) setClaims(d.claims); setLoading(false); })
      .catch(() => setLoading(false));
  }, []);

  const ok    = claims.filter(c => c.status === "claimed").length;
  const total = claims.length;

  return (
    <div className="stack-lg">
      <div>
        <span className="eyebrow">account · history</span>
        <h2 style={{ fontSize: 24, marginTop: 4 }}>
          {loading ? "…" : total ? `${ok} / ${total} claimed` : "No claims yet"}
        </h2>
        <p className="muted" style={{ fontSize: 13, marginTop: 4 }}>Your last 100 claim attempts across all platforms.</p>
      </div>
      <Card style={{ padding: 0 }}>
        {loading ? <p className="muted" style={{ padding: 20 }}>Loading…</p> : total === 0 ? (
          <p className="muted" style={{ padding: 24, fontSize: 13 }}>No claims recorded yet. Codes are claimed automatically when BoostMonitor sends them.</p>
        ) : (
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
              <thead>
                <tr style={{ borderBottom: "1px solid var(--border)", textAlign: "left" }}>
                  {["Status", "Code", "Platform", "Value", "Speed", "Time"].map(h => (
                    <th key={h} style={{ padding: "8px 12px", color: "var(--text-3)", fontWeight: 500, whiteSpace: "nowrap" }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {claims.map(c => {
                  const isOk = c.status === "claimed";
                  const ts = c.time ? new Date(c.time).toLocaleString([], { month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" }) : "—";
                  const val = c.value && c.currency ? `${c.value} ${c.currency}` : (isOk ? "—" : (c.message || "—"));
                  return (
                    <tr key={c.id} style={{ borderBottom: "1px solid var(--border)" }}>
                      <td style={{ padding: "8px 12px" }}><Pill kind={isOk ? "ok" : "err"} dot>{isOk ? "claimed" : "failed"}</Pill></td>
                      <td style={{ padding: "8px 12px", fontWeight: 600, fontFamily: "var(--font-mono)", fontSize: 12 }}>{c.code || "—"}</td>
                      <td style={{ padding: "8px 12px" }}>{(c.platform || "—").replace("stake_", "Stake.").replace("shuffle", "Shuffle")}</td>
                      <td style={{ padding: "8px 12px", fontSize: 12 }}>{val}</td>
                      <td style={{ padding: "8px 12px" }}>{c.elapsed_ms ? `${c.elapsed_ms}ms` : "—"}</td>
                      <td style={{ padding: "8px 12px", color: "var(--text-3)", fontSize: 12 }}>{ts}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </Card>
    </div>
  );
};

const CodesPanel = () => {
  const [claims, setClaims] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const token = localStorage.getItem("cc_token");

  React.useEffect(() => {
    fetch("/api/claims", { headers: { Authorization: `Bearer ${token}` } })
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d?.claims) setClaims(d.claims); setLoading(false); })
      .catch(() => setLoading(false));
  }, []);

  // Dedupe by code, keep first occurrence (most recent)
  const seen = new Set();
  const codes = claims.filter(c => {
    if (!c.code || seen.has(c.code)) return false;
    seen.add(c.code);
    return true;
  });

  return (
    <div className="stack-lg">
      <div>
        <span className="eyebrow">workspace · codes</span>
        <h2 style={{ fontSize: 24, marginTop: 4 }}>
          {loading ? "…" : `${codes.length} unique codes`}
        </h2>
        <p className="muted" style={{ fontSize: 13, marginTop: 4 }}>Bonus codes that were broadcast to your account.</p>
      </div>
      <Card style={{ padding: 0 }}>
        {loading ? <p className="muted" style={{ padding: 20 }}>Loading…</p> : codes.length === 0 ? (
          <p className="muted" style={{ padding: 24, fontSize: 13 }}>No codes yet. They appear here automatically when broadcast.</p>
        ) : (
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
              <thead>
                <tr style={{ borderBottom: "1px solid var(--border)", textAlign: "left" }}>
                  {["Code", "Platform", "Result", "Value", "Claimed at"].map(h => (
                    <th key={h} style={{ padding: "8px 12px", color: "var(--text-3)", fontWeight: 500, whiteSpace: "nowrap" }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {codes.map(c => {
                  const isOk = c.status === "claimed";
                  const ts = c.time ? new Date(c.time).toLocaleString([], { month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" }) : "—";
                  const val = c.value && c.currency ? `${c.value} ${c.currency}` : "—";
                  return (
                    <tr key={c.id} style={{ borderBottom: "1px solid var(--border)" }}>
                      <td style={{ padding: "8px 12px", fontWeight: 700, fontFamily: "var(--font-mono)", fontSize: 13, letterSpacing: ".04em" }}>{c.code}</td>
                      <td style={{ padding: "8px 12px" }}>{(c.platform || "—").replace("stake_", "Stake.").replace("shuffle", "Shuffle")}</td>
                      <td style={{ padding: "8px 12px" }}><Pill kind={isOk ? "ok" : "err"} dot>{isOk ? "claimed" : "failed"}</Pill></td>
                      <td style={{ padding: "8px 12px", fontSize: 12 }}>{val}</td>
                      <td style={{ padding: "8px 12px", color: "var(--text-3)", fontSize: 12 }}>{ts}</td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </Card>
    </div>
  );
};

const AdminPanel = ({ active, user }) => {
  if (active === "users")        return <AdminUsers />;
  if (active === "broadcast")    return <AdminBroadcast />;
  if (active === "admin-claims") return <AdminClaims />;
  if (active === "promos")       return <AdminPromos />;
  if (active === "revenue")      return <AdminRevenue />;
  return <AdminHealth />;
};

const AdminBroadcast = () => {
  const authHeader = () => ({ Authorization: `Bearer ${localStorage.getItem("cc_token")}`, "content-type": "application/json" });

  const PLATFORMS = [
    { id: "stake_com", label: "Stake.com", desc: "API claim for all active Stake.com subscribers", color: "var(--accent)" },
    { id: "stake_us",  label: "Stake.us",  desc: "API claim for all active Stake.us subscribers", color: "var(--accent)" },
    { id: "shuffle",   label: "Shuffle",   desc: "Push to all connected extension users (coming soon)", color: "var(--ok)" },
    { id: "thrill",    label: "Thrill",    desc: "Push to all connected extension users (coming soon)", color: "var(--ok)" },
  ];

  const [platform, setPlatform] = React.useState("stake_com");
  const [code, setCode]         = React.useState("");
  const [sending, setSending]   = React.useState(false);
  const [result, setResult]     = React.useState(null); // { ok, message }
  const [history, setHistory]   = React.useState([]);   // last few sends

  const send = async () => {
    if (!code.trim()) return;
    setSending(true); setResult(null);
    try {
      const r = await fetch("/api/admin/broadcast", {
        method: "POST", headers: authHeader(),
        body: JSON.stringify({ code: code.trim(), platform }),
      });
      const d = await r.json();
      const plat = PLATFORMS.find(p => p.id === platform);
      const entry = { code: code.trim(), platform, label: plat.label, ok: !!d.ok, time: new Date().toLocaleTimeString() };
      setHistory(h => [entry, ...h].slice(0, 10));
      setResult(d.ok ? { ok: true, message: `Dispatched — all ${plat.label} users notified` } : { ok: false, message: d.error || "Server error" });
      if (d.ok) setCode("");
    } catch (_) {
      setResult({ ok: false, message: "Network error" });
    }
    setSending(false);
  };

  const plat = PLATFORMS.find(p => p.id === platform);

  return (
    <div className="stack-lg" style={{ maxWidth: 600 }}>
      <div>
        <span className="eyebrow">admin · send code</span>
        <h2 style={{ fontSize: 24, marginTop: 4 }}>Manual broadcast</h2>
        <p className="muted" style={{ marginTop: 4, fontSize: 13 }}>
          Stake codes trigger API claims instantly. Shuffle/Thrill codes push to connected extensions.
        </p>
      </div>

      {/* Platform picker */}
      <Card>
        <div style={{ fontWeight: 600, marginBottom: 12 }}>Platform</div>
        <div className="grid-2" style={{ gap: 8 }}>
          {PLATFORMS.map(p => (
            <div key={p.id}
              onClick={() => setPlatform(p.id)}
              style={{
                padding: "12px 14px", borderRadius: "var(--radius-sm)", cursor: "pointer",
                border: `2px solid ${platform === p.id ? p.color : "var(--border)"}`,
                background: platform === p.id ? "var(--surf-3)" : "var(--surf-2)",
                transition: "border-color .15s",
              }}>
              <div style={{ fontWeight: 700, fontSize: 14, color: platform === p.id ? p.color : "var(--text)" }}>{p.label}</div>
              <div style={{ fontSize: 11, color: "var(--text-3)", marginTop: 3 }}>{p.desc}</div>
            </div>
          ))}
        </div>
      </Card>

      {/* Code input */}
      <Card>
        <div style={{ fontWeight: 600, marginBottom: 12 }}>Code</div>
        <div className="row" style={{ gap: 8 }}>
          <Input
            value={code}
            onChange={e => { setCode(e.target.value); setResult(null); }}
            onKeyDown={e => e.key === "Enter" && !sending && send()}
            placeholder={`e.g. BOOST100`}
            style={{ flex: 1, fontFamily: "var(--font-mono)", letterSpacing: ".06em", fontSize: 15 }}
          />
          <Btn kind="primary" disabled={sending || !code.trim()} onClick={send} style={{ minWidth: 100 }}>
            {sending ? "Sending…" : `Send → ${plat.label}`}
          </Btn>
        </div>
        {result && (
          <div style={{ marginTop: 10, padding: "8px 12px", borderRadius: "var(--radius-sm)",
            background: result.ok ? "rgba(0,255,136,.08)" : "rgba(255,80,80,.08)",
            border: `1px solid ${result.ok ? "var(--ok)" : "var(--err)"}`,
            color: result.ok ? "var(--ok)" : "var(--err)", fontSize: 13 }}>
            {result.ok ? "✓" : "✕"} {result.message}
          </div>
        )}
      </Card>

      {/* Recent sends */}
      {history.length > 0 && (
        <Card style={{ padding: 0 }}>
          <div style={{ padding: "10px 14px", borderBottom: "1px solid var(--border)", fontWeight: 600, fontSize: 13 }}>Recent sends</div>
          {history.map((h, i) => (
            <div key={i} className="row between" style={{ padding: "9px 14px", borderBottom: i < history.length - 1 ? "1px solid var(--border)" : "none", fontSize: 13 }}>
              <div className="row" style={{ gap: 10 }}>
                <span style={{ color: h.ok ? "var(--ok)" : "var(--err)" }}>{h.ok ? "✓" : "✕"}</span>
                <code style={{ fontFamily: "var(--font-mono)", fontWeight: 600 }}>{h.code}</code>
                <Pill>{h.label}</Pill>
              </div>
              <span className="muted" style={{ fontSize: 11 }}>{h.time}</span>
            </div>
          ))}
        </Card>
      )}
    </div>
  );
};

const AdminUsers = () => {
  const [users, setUsers]     = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [search, setSearch]   = React.useState("");
  const [busy, setBusy]       = React.useState({});
  const [revealed, setRevealed] = React.useState({});
  const [granting, setGranting] = React.useState({}); // userId → { plan, days } | null
  const [grantOk, setGrantOk]   = React.useState({});
  const [slots, setSlots]       = React.useState({}); // userId → slot[] | "loading"
  const [slotBusy, setSlotBusy] = React.useState({}); // slotId → true

  const authHeader = () => ({ Authorization: `Bearer ${localStorage.getItem("cc_token")}`, "content-type": "application/json" });

  const load = () => {
    fetch("/api/admin/users", { headers: authHeader() })
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d?.users) setUsers(d.users); setLoading(false); })
      .catch(() => setLoading(false));
  };
  React.useEffect(load, []);

  // Toggle the per-user slots panel; fetch slots on first open
  const toggleSlots = (userId) => {
    if (slots[userId] !== undefined) {
      setSlots(s => { const n = { ...s }; delete n[userId]; return n; });
      return;
    }
    setSlots(s => ({ ...s, [userId]: "loading" }));
    fetch(`/api/admin/users/${userId}/slots`, { headers: authHeader() })
      .then(r => r.ok ? r.json() : null)
      .then(d => setSlots(s => ({ ...s, [userId]: d?.slots || [] })))
      .catch(() => setSlots(s => ({ ...s, [userId]: [] })));
  };

  const setSlotActive = async (userId, slotId, active) => {
    setSlotBusy(b => ({ ...b, [slotId]: true }));
    try {
      const r = await fetch(`/api/admin/slots/${slotId}/active`, {
        method: "POST", headers: authHeader(),
        body: JSON.stringify({ active }),
      });
      const d = await r.json();
      if (d.ok) {
        setSlots(s => ({
          ...s,
          [userId]: (s[userId] || []).map(sl => sl.id === slotId ? { ...sl, active } : sl),
        }));
      }
    } catch (_) {}
    setSlotBusy(b => ({ ...b, [slotId]: false }));
  };

  const act = async (userId, action) => {
    setBusy(b => ({ ...b, [userId]: action }));
    const url = `/api/admin/users/${userId}/${action === "suspend" ? "suspend" : action + "-extension"}`;
    try {
      const r = await fetch(url, { method: "POST", headers: authHeader(), body: JSON.stringify({}) });
      const d = await r.json();
      if (action === "approve" && d.token) {
        setRevealed(rv => ({ ...rv, [userId]: d.token }));
      }
      load();
    } catch (_) {}
    setBusy(b => ({ ...b, [userId]: null }));
  };

  const grant = async (userId) => {
    const g = granting[userId] || { plan: "stake_com", days: 30 };
    setBusy(b => ({ ...b, [userId]: "grant" }));
    try {
      const r = await fetch(`/api/admin/users/${userId}/grant`, {
        method: "POST", headers: authHeader(),
        body: JSON.stringify({ plan: g.plan, days: parseInt(g.days) || 30 }),
      });
      const d = await r.json();
      if (d.ok) { setGrantOk(o => ({ ...o, [userId]: true })); load(); }
    } catch (_) {}
    setBusy(b => ({ ...b, [userId]: null }));
    setTimeout(() => setGrantOk(o => ({ ...o, [userId]: false })), 3000);
  };

  const filtered = users.filter(u => {
    if (!search) return true;
    const q = search.toLowerCase();
    return (u.username || "").includes(q) || (u.email || "").includes(q);
  });

  const PLAN_OPTS = [
    { value: "house_cut",   label: "The House Cut — $10/slot" },
    { value: "prime_cut",   label: "The Prime Cut — $15/slot" },
    { value: "grand_feast", label: "The Grand Feast — $30/slot" },
  ];

  return (
    <div className="stack-lg">
      <div className="row between">
        <div>
          <span className="eyebrow">admin · users</span>
          <h2 style={{ fontSize: 24, marginTop: 4 }}>{loading ? "…" : `${users.length} users`}</h2>
        </div>
        <Btn sm onClick={load}><Icon name="refresh"/> Refresh</Btn>
      </div>
      <Card style={{ padding: 0 }}>
        <div className="row" style={{ padding: 12, gap: 8, borderBottom: "1px solid var(--border)" }}>
          <Input placeholder="search by username or email…" value={search} onChange={e => setSearch(e.target.value)} style={{ flex: 1 }} />
        </div>
        {loading ? <p className="muted" style={{ padding: 20 }}>Loading…</p> : (
          <div>
            {filtered.map((u) => {
              const hasExt = false; // extension not yet available
              const isBusy = busy[u.id];
              const token  = revealed[u.id];
              const g      = granting[u.id] || { plan: "stake_com", days: "30" };
              return (
                <div key={u.id} style={{ borderBottom: "1px solid var(--border)", padding: "12px 14px" }}>
                  <div className="row between" style={{ flexWrap: "wrap", gap: 8 }}>
                    <div>
                      <span style={{ fontWeight: 600, fontSize: 14 }}>{u.username || "—"}</span>
                      <span className="muted" style={{ fontSize: 12, marginLeft: 10 }}>{u.email || "telegram"}</span>
                    </div>
                    <div className="row" style={{ gap: 6, flexWrap: "wrap" }}>
                      <Pill kind={u.plan !== "free" ? "ok" : ""} dot={u.plan !== "free"}>{u.plan_display || u.plan}</Pill>
                      {u.plan_expires_at && <span className="muted" style={{ fontSize: 11 }}>exp {new Date(u.plan_expires_at).toLocaleDateString()}</span>}
                      {u.is_admin && <Pill kind="warn" dot>admin</Pill>}
                    </div>

                  </div>

                  {/* Grant free subscription */}
                  <div className="row" style={{ marginTop: 10, gap: 8, flexWrap: "wrap", alignItems: "center" }}>
                    <select value={g.plan} onChange={e => setGranting(gr => ({ ...gr, [u.id]: { ...g, plan: e.target.value } }))}
                      style={{ fontSize: 12, padding: "4px 8px", background: "var(--surf-2)", color: "var(--text)", border: "1px solid var(--border-2)", borderRadius: "var(--radius-sm)", cursor: "pointer" }}>
                      {PLAN_OPTS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
                    </select>
                    <Input value={g.days} onChange={e => setGranting(gr => ({ ...gr, [u.id]: { ...g, days: e.target.value } }))}
                      placeholder="days" style={{ width: 60, fontSize: 12, padding: "4px 8px" }} />
                    <Btn sm kind="primary" disabled={!!isBusy} onClick={() => grant(u.id)}>
                      {isBusy === "grant" ? "…" : grantOk[u.id] ? "✓ Granted!" : "Grant free sub"}
                    </Btn>
                    <Btn sm kind="ghost" disabled={!!isBusy} onClick={() => act(u.id, "suspend")}
                      style={{ color: "var(--warn)" }}>
                      {isBusy === "suspend" ? "…" : "Suspend"}
                    </Btn>
                    <Btn sm kind="ghost" onClick={() => toggleSlots(u.id)}>
                      {slots[u.id] !== undefined ? "Hide slots" : "API slots"}
                    </Btn>
                  </div>

                  {/* Per-slot enable/disable — for wager-requirement enforcement */}
                  {slots[u.id] !== undefined && (
                    <div style={{ marginTop: 8, padding: "8px 10px", background: "var(--surf-2)", borderRadius: "var(--radius-sm)", border: "1px solid var(--border)" }}>
                      {slots[u.id] === "loading" ? (
                        <span className="muted" style={{ fontSize: 12 }}>Loading slots…</span>
                      ) : slots[u.id].length === 0 ? (
                        <span className="muted" style={{ fontSize: 12 }}>No API slots configured.</span>
                      ) : (
                        <div className="stack-sm">
                          {slots[u.id].map(sl => (
                            <div key={sl.id} className="row between" style={{ fontSize: 12, gap: 8 }}>
                              <span className="row" style={{ gap: 8 }}>
                                <Pill kind={sl.active ? "ok" : "err"} dot>{sl.active ? "active" : "disabled"}</Pill>
                                <strong>{PLAT_LABEL[sl.platform] || sl.platform}</strong>
                                <span className="muted">slot {sl.slot_index} · {sl.currency}</span>
                                <code style={{ fontFamily: "var(--font-mono)", color: "var(--text-3)" }}>{sl.api_key_masked}</code>
                              </span>
                              <Btn sm kind="ghost" disabled={!!slotBusy[sl.id]}
                                onClick={() => setSlotActive(u.id, sl.id, !sl.active)}
                                style={{ color: sl.active ? "var(--err)" : "var(--ok)" }}>
                                {slotBusy[sl.id] ? "…" : sl.active ? "Disable" : "Enable"}
                              </Btn>
                            </div>
                          ))}
                        </div>
                      )}
                    </div>
                  )}

                  {/* Extension controls — only for ext-capable plans */}
                  {hasExt && (
                    <div className="row" style={{ marginTop: 8, gap: 8, flexWrap: "wrap" }}>
                      <Btn sm kind="ghost" disabled={!!isBusy} onClick={() => act(u.id, "approve")}>
                        {isBusy === "approve" ? "…" : <><Icon name="key"/> Approve ext token</>}
                      </Btn>
                      <Btn sm kind="ghost" disabled={!!isBusy} onClick={() => act(u.id, "revoke")}
                        style={{ color: "var(--err)", borderColor: "var(--err)" }}>
                        {isBusy === "revoke" ? "…" : "Revoke token"}
                      </Btn>
                    </div>
                  )}

                  {token && (
                    <div style={{ marginTop: 8, padding: "8px 10px", background: "var(--surf-3)", borderRadius: "var(--radius-sm)", border: "1px solid var(--accent-3)" }}>
                      <div className="row between" style={{ gap: 8 }}>
                        <span style={{ fontSize: 11, color: "var(--text-3)" }}>
                          Extension token — copy and share with {u.username}. Not shown again.
                        </span>
                        <Btn sm kind="ghost" onClick={() => navigator.clipboard.writeText(token)}><Icon name="copy"/></Btn>
                      </div>
                      <code style={{ fontSize: 11, fontFamily: "var(--font-mono)", color: "var(--accent)", wordBreak: "break-all" }}>{token}</code>
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        )}
      </Card>
    </div>
  );
};

const PLAT_LABEL = { stake_com: "Stake.com", stake_us: "Stake.us", shuffle: "Shuffle", thrill: "Thrill" };

const AdminClaims = () => {
  const [claims, setClaims]     = React.useState([]);
  const [loading, setLoading]   = React.useState(true);
  const [platform, setPlatform] = React.useState("");
  const [search, setSearch]     = React.useState("");

  const authHeader = () => ({ Authorization: `Bearer ${localStorage.getItem("cc_token")}` });

  const load = (plat) => {
    setLoading(true);
    const qs = plat ? `?platform=${plat}` : "";
    fetch(`/api/admin/claims${qs}`, { headers: authHeader() })
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d?.claims) setClaims(d.claims); setLoading(false); })
      .catch(() => setLoading(false));
  };
  React.useEffect(() => load(platform), [platform]);

  const ok    = claims.filter(c => c.status === "claimed").length;
  const total = claims.length;
  const rate  = total ? Math.round(ok / total * 100) : 0;

  const filtered = claims.filter(c => {
    if (!search) return true;
    const q = search.toLowerCase();
    return (c.code || "").includes(q) || (c.username || "").includes(q) || (c.platform || "").includes(q);
  });

  return (
    <div className="stack-lg">
      <div className="row between" style={{ flexWrap: "wrap", gap: 12 }}>
        <div>
          <span className="eyebrow">admin · claim history</span>
          <h2 style={{ fontSize: 24, marginTop: 4 }}>
            {loading ? "…" : `${ok} / ${total} claimed · ${rate}%`}
          </h2>
        </div>
        <div className="row" style={{ gap: 8, flexWrap: "wrap" }}>
          {["", "stake_com", "stake_us", "shuffle", "thrill"].map(p => (
            <Btn key={p} sm kind={platform === p ? "primary" : "ghost"} onClick={() => setPlatform(p)}>
              {p ? PLAT_LABEL[p] : "All"}
            </Btn>
          ))}
          <Btn sm onClick={() => load(platform)}><Icon name="refresh"/> Refresh</Btn>
        </div>
      </div>

      <Card style={{ padding: 0 }}>
        <div style={{ padding: "10px 12px", borderBottom: "1px solid var(--border)" }}>
          <Input placeholder="search code, user, platform…" value={search}
            onChange={e => setSearch(e.target.value)} style={{ width: "100%" }} />
        </div>
        {loading ? <p className="muted" style={{ padding: 20 }}>Loading…</p> : (
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
              <thead>
                <tr style={{ borderBottom: "1px solid var(--border)", textAlign: "left" }}>
                  {["Status", "Code", "User", "Platform", "Value", "Speed", "Time"].map(h => (
                    <th key={h} style={{ padding: "8px 12px", color: "var(--text-3)", fontWeight: 500, whiteSpace: "nowrap" }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {filtered.map(c => {
                  const ok = c.status === "claimed";
                  const ts = c.time ? new Date(c.time).toLocaleString([], { month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" }) : "—";
                  const speed = c.elapsed_ms ? `${c.elapsed_ms}ms` : "—";
                  const val = c.value && c.currency ? `${c.value} ${c.currency}` : (c.message && !ok ? c.message : "—");
                  return (
                    <tr key={c.id} style={{ borderBottom: "1px solid var(--border)" }}>
                      <td style={{ padding: "8px 12px" }}>
                        <Pill kind={ok ? "ok" : "err"} dot>{ok ? "claimed" : "failed"}</Pill>
                      </td>
                      <td style={{ padding: "8px 12px", fontFamily: "var(--font-mono)", fontSize: 12 }}>{c.code}</td>
                      <td style={{ padding: "8px 12px", color: "var(--text-2)" }}>{c.username}</td>
                      <td style={{ padding: "8px 12px", color: "var(--text-3)" }}>{PLAT_LABEL[c.platform] || c.platform}</td>
                      <td style={{ padding: "8px 12px", color: ok ? "var(--ok)" : "var(--err)", fontSize: 12 }}>{val}</td>
                      <td style={{ padding: "8px 12px", color: c.elapsed_ms < 400 ? "var(--ok)" : "var(--text-3)", fontSize: 12 }}>{speed}</td>
                      <td style={{ padding: "8px 12px", color: "var(--text-3)", fontSize: 12, whiteSpace: "nowrap" }}>{ts}</td>
                    </tr>
                  );
                })}
                {!filtered.length && (
                  <tr><td colSpan={7} style={{ padding: 20, color: "var(--text-3)", textAlign: "center" }}>No claims found.</td></tr>
                )}
              </tbody>
            </table>
          </div>
        )}
      </Card>
    </div>
  );
};

const AdminPromos = () => {
  const [promos, setPromos]   = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [form, setForm]       = React.useState({ code: "", promo_type: "free_days", value: "7", max_uses: "", note: "" });
  const [saving, setSaving]   = React.useState(false);
  const [err, setErr]         = React.useState("");

  const authHeader = () => ({ Authorization: `Bearer ${localStorage.getItem("cc_token")}`, "content-type": "application/json" });

  const load = () => {
    setLoading(true);
    fetch("/api/admin/promos", { headers: authHeader() })
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d?.promos) setPromos(d.promos); setLoading(false); })
      .catch(() => setLoading(false));
  };
  React.useEffect(load, []);

  const create = async () => {
    setErr(""); setSaving(true);
    try {
      const r = await fetch("/api/admin/promos", {
        method: "POST", headers: authHeader(),
        body: JSON.stringify({
          code: form.code.toUpperCase(),
          promo_type: form.promo_type,
          value: parseInt(form.value) || 0,
          max_uses: form.max_uses ? parseInt(form.max_uses) : null,
          note: form.note,
        }),
      });
      const d = await r.json();
      if (d.error) { setErr(d.error); } else { setForm({ code: "", promo_type: "free_days", value: "7", max_uses: "", note: "" }); load(); }
    } catch (_) { setErr("Network error"); }
    setSaving(false);
  };

  const deactivate = async (id) => {
    await fetch(`/api/admin/promos/${id}`, { method: "DELETE", headers: authHeader() });
    load();
  };

  const PRESET_TYPES = [
    { type: "free_days", value: 7,  label: "7 days free" },
    { type: "discount_pct", value: 50, label: "50% off" },
  ];

  return (
    <div className="stack-lg">
      <div>
        <span className="eyebrow">admin · promos</span>
        <h2 style={{ fontSize: 24, marginTop: 4 }}>Promo Codes</h2>
      </div>

      <Card>
        <div style={{ fontWeight: 600, marginBottom: 14 }}>Create promo</div>
        <div className="row" style={{ gap: 8, marginBottom: 10, flexWrap: "wrap" }}>
          {PRESET_TYPES.map(p => (
            <Btn key={p.label} sm kind={form.promo_type === p.type && parseInt(form.value) === p.value ? "primary" : "ghost"}
              onClick={() => setForm(f => ({ ...f, promo_type: p.type, value: String(p.value) }))}>
              {p.label}
            </Btn>
          ))}
        </div>
        <div className="row" style={{ gap: 8, flexWrap: "wrap", alignItems: "flex-end" }}>
          <div style={{ flex: "1 1 130px" }}>
            <div className="muted" style={{ fontSize: 11, marginBottom: 4 }}>Code</div>
            <Input value={form.code} onChange={e => setForm(f => ({ ...f, code: e.target.value.toUpperCase() }))}
              placeholder="e.g. WELCOME7" style={{ textTransform: "uppercase", letterSpacing: ".06em" }} />
          </div>
          <div style={{ flex: "0 0 120px" }}>
            <div className="muted" style={{ fontSize: 11, marginBottom: 4 }}>Type</div>
            <select value={form.promo_type} onChange={e => setForm(f => ({ ...f, promo_type: e.target.value }))}
              style={{ width: "100%", fontSize: 13, padding: "8px 10px", background: "var(--surf-2)", color: "var(--text)", border: "1px solid var(--border-2)", borderRadius: "var(--radius-sm)" }}>
              <option value="free_days">Free days</option>
              <option value="discount_pct">% Discount</option>
            </select>
          </div>
          <div style={{ flex: "0 0 80px" }}>
            <div className="muted" style={{ fontSize: 11, marginBottom: 4 }}>{form.promo_type === "free_days" ? "Days" : "% off"}</div>
            <Input value={form.value} onChange={e => setForm(f => ({ ...f, value: e.target.value }))} type="number" min="1" />
          </div>
          <div style={{ flex: "0 0 80px" }}>
            <div className="muted" style={{ fontSize: 11, marginBottom: 4 }}>Max uses</div>
            <Input value={form.max_uses} onChange={e => setForm(f => ({ ...f, max_uses: e.target.value }))} placeholder="∞" type="number" min="1" />
          </div>
          <div style={{ flex: "1 1 150px" }}>
            <div className="muted" style={{ fontSize: 11, marginBottom: 4 }}>Note (admin only)</div>
            <Input value={form.note} onChange={e => setForm(f => ({ ...f, note: e.target.value }))} placeholder="optional memo" />
          </div>
          <Btn kind="primary" disabled={saving || !form.code || !form.value} onClick={create}>
            {saving ? "…" : "Create"}
          </Btn>
        </div>
        {err && <p style={{ color: "var(--err)", fontSize: 13, marginTop: 8 }}>{err}</p>}
      </Card>

      <Card style={{ padding: 0 }}>
        {loading ? <p className="muted" style={{ padding: 20 }}>Loading…</p> : (
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
            <thead>
              <tr style={{ borderBottom: "1px solid var(--border)", textAlign: "left" }}>
                {["Code", "Type", "Value", "Used", "Max", "Note", ""].map(h => (
                  <th key={h} style={{ padding: "8px 12px", color: "var(--text-3)", fontWeight: 500 }}>{h}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {promos.map(p => (
                <tr key={p.id} style={{ borderBottom: "1px solid var(--border)", opacity: p.active ? 1 : 0.45 }}>
                  <td style={{ padding: "8px 12px", fontFamily: "var(--font-mono)", letterSpacing: ".06em", fontWeight: 600 }}>{p.code}</td>
                  <td style={{ padding: "8px 12px" }}>
                    <Pill kind={p.promo_type === "free_days" ? "ok" : "warn"}>
                      {p.promo_type === "free_days" ? "free days" : "% off"}
                    </Pill>
                  </td>
                  <td style={{ padding: "8px 12px", color: "var(--accent)" }}>
                    {p.promo_type === "free_days" ? `${p.value}d` : `${p.value}%`}
                  </td>
                  <td style={{ padding: "8px 12px", color: "var(--text-2)" }}>{p.used_count}</td>
                  <td style={{ padding: "8px 12px", color: "var(--text-3)" }}>{p.max_uses ?? "∞"}</td>
                  <td style={{ padding: "8px 12px", color: "var(--text-3)", fontSize: 12 }}>{p.note || "—"}</td>
                  <td style={{ padding: "8px 12px" }}>
                    {p.active && (
                      <Btn sm kind="ghost" onClick={() => deactivate(p.id)} style={{ color: "var(--err)", borderColor: "var(--err)" }}>
                        Deactivate
                      </Btn>
                    )}
                    {!p.active && <span className="muted" style={{ fontSize: 11 }}>inactive</span>}
                  </td>
                </tr>
              ))}
              {!promos.length && (
                <tr><td colSpan={7} style={{ padding: 20, color: "var(--text-3)", textAlign: "center" }}>No promos yet.</td></tr>
              )}
            </tbody>
          </table>
        )}
      </Card>
    </div>
  );
};

const SettingsPanel = ({ user }) => {
  const token = () => localStorage.getItem("cc_token");
  const auth  = () => ({ Authorization: `Bearer ${token()}`, "content-type": "application/json" });

  // Toggles — seed from user prop
  const [reload,     setReload]     = React.useState(user?.addons?.reload       || false);
  const [daily,      setDaily]      = React.useState(user?.addons?.daily_dollar  || false);
  const [proxyCom,   setProxyCom]   = React.useState(user?.proxy?.com_enabled   ?? true);
  const [proxyUs,    setProxyUs]    = React.useState(user?.proxy?.us_enabled    ?? true);
  const [comRegion,  setComRegion]  = React.useState(user?.proxy?.com_region    || "norway");
  const [saving,     setSaving]     = React.useState(false);
  const [saveMsg,    setSaveMsg]    = React.useState("");

  // Turnstile slot status
  const [slots,      setSlots]      = React.useState([]);
  const [slotsLoading, setSlotsLoading] = React.useState(true);

  React.useEffect(() => {
    fetch("/api/me/slots/status", { headers: { Authorization: `Bearer ${token()}` } })
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d?.slots) setSlots(d.slots); })
      .catch(() => {})
      .finally(() => setSlotsLoading(false));
  }, []);

  const saveSettings = async () => {
    setSaving(true); setSaveMsg("");
    try {
      await fetch("/api/me/settings", {
        method: "POST", headers: auth(),
        body: JSON.stringify({ reload_enabled: reload, daily_dollar_enabled: daily, proxy_com_enabled: proxyCom, proxy_us_enabled: proxyUs }),
      });
      if (proxyCom) {
        await fetch("/api/me/proxy-region", {
          method: "POST", headers: auth(),
          body: JSON.stringify({ com_region: comRegion }),
        });
      }
      setSaveMsg("Saved.");
    } catch { setSaveMsg("Error saving — try again"); }
    setSaving(false);
    setTimeout(() => setSaveMsg(""), 3000);
  };

  const COM_REGIONS = [
    { value: "norway", label: "Norway (recommended)" },
    { value: "malta",  label: "Malta" },
    { value: "japan",  label: "Japan" },
  ];

  const Toggle = ({ label, hint, value, onChange, disabled, futureUse }) => (
    <div className="row between" style={{ padding: "14px 0", borderBottom: "1px solid var(--border)" }}>
      <div>
        <div className="row" style={{ gap: 8 }}>
          <strong style={{ fontSize: 14 }}>{label}</strong>
          {futureUse && <Pill style={{ fontSize: 10, opacity: 0.7 }}>for future use</Pill>}
        </div>
        {hint && <p className="muted" style={{ fontSize: 12, marginTop: 3 }}>{hint}</p>}
      </div>
      <button
        onClick={() => !disabled && onChange(!value)}
        style={{
          width: 44, height: 24, borderRadius: 999, border: "none", cursor: disabled ? "not-allowed" : "pointer",
          background: value ? "var(--accent)" : "var(--surf-3)",
          position: "relative", transition: "background .2s", opacity: disabled ? 0.4 : 1, flexShrink: 0,
        }}>
        <span style={{
          position: "absolute", top: 3, left: value ? 22 : 3,
          width: 18, height: 18, borderRadius: 999,
          background: value ? "#0f0c0a" : "var(--text-3)",
          transition: "left .2s",
        }} />
      </button>
    </div>
  );

  const tokenAge = (s) => {
    if (!s.has_token) return "—";
    if (s.age_seconds == null) return "unknown";
    if (s.age_seconds < 60) return `${s.age_seconds}s old`;
    return `${Math.round(s.age_seconds / 60)}m old`;
  };

  return (
    <div className="stack-lg" style={{ maxWidth: 680 }}>
      <div>
        <span className="eyebrow">settings</span>
        <h2 style={{ fontSize: 24, marginTop: 4 }}>Account settings</h2>
      </div>

      {/* ── Proxy settings ── */}
      <Card>
        <div className="eyebrow" style={{ marginBottom: 14 }}>Proxy</div>
        <Toggle
          label="Stake.com proxy"
          hint="Routes claims through a Decodo residential IP in your chosen region"
          value={proxyCom} onChange={setProxyCom}
        />
        {proxyCom && (
          <div style={{ padding: "12px 0", borderBottom: "1px solid var(--border)" }}>
            <label className="field-label">Stake.com region</label>
            <Select value={comRegion} onChange={e => setComRegion(e.target.value)} options={COM_REGIONS} />
          </div>
        )}
        <Toggle
          label="Stake.us proxy"
          hint="Texas residential proxy — Stake.us geo-fences to the US"
          value={proxyUs} onChange={setProxyUs}
        />
      </Card>

      {/* ── Features ── */}
      <Card>
        <div className="eyebrow" style={{ marginBottom: 14 }}>Features</div>
        <Toggle
          label="Auto-reload"
          hint="Automatically claims your reload bonus on a set interval"
          value={reload} onChange={setReload} futureUse
        />
        <Toggle
          label="Daily Dollar (Stake.us)"
          hint="Automatically claims the Stake.us daily $1 bonus"
          value={daily} onChange={setDaily} futureUse
        />
      </Card>

      <Btn kind="primary" onClick={saveSettings} disabled={saving}>
        {saving ? <><span className="spin" style={{ display: "inline-block" }}>◐</span> Saving…</> : "Save settings"}
      </Btn>
      {saveMsg && <p style={{ color: saveMsg === "Saved." ? "var(--ok)" : "var(--err)", fontSize: 13 }}>{saveMsg}</p>}

      {/* ── Turnstile token table ── */}
      <div>
        <div className="eyebrow" style={{ marginBottom: 10 }}>Turnstile tokens · per slot</div>
        {slotsLoading ? (
          <p className="muted" style={{ fontSize: 13 }}>Loading…</p>
        ) : slots.length === 0 ? (
          <Card><p className="muted" style={{ fontSize: 13 }}>No active slots — add an API key first.</p></Card>
        ) : (
          <Card style={{ padding: 0, overflow: "hidden" }}>
            <div className="log">
              <div className="log-row head">
                <span>platform</span><span>slot</span><span>token</span><span>age</span><span>status</span>
              </div>
              {slots.map((s, i) => (
                <div key={i} className="log-row">
                  <span style={{ fontSize: 11 }}>{s.platform === "stake_com" ? "Stake.com" : "Stake.us"}</span>
                  <span className="muted" style={{ fontSize: 11 }}>{s.slot_id?.slice(0, 8)}…</span>
                  <span>{s.has_token ? "✓" : "—"}</span>
                  <span className="muted" style={{ fontSize: 11 }}>{tokenAge(s)}</span>
                  <span className={s.fresh ? "ok" : s.has_token ? "" : "err"} style={{ fontSize: 11 }}>
                    {s.fresh ? "fresh" : s.has_token ? "stale" : "missing"}
                  </span>
                </div>
              ))}
            </div>
          </Card>
        )}
      </div>
    </div>
  );
};

const BillingPanel = ({ user }) => {
  const [chosen, setChosen]     = React.useState("house_cut");
  const [slotCount, setSlots]   = React.useState(1);
  const [promoCode, setPromoCode] = React.useState("");
  const [promoInfo, setPromoInfo] = React.useState(null);
  const [promoErr, setPromoErr]   = React.useState("");
  const [checking, setChecking]   = React.useState(false);
  const [checkingOut, setCheckingOut] = React.useState(false);
  const [payErr, setPayErr]       = React.useState("");
  const [success, setSuccess]     = React.useState(false);

  const token = localStorage.getItem("cc_token");
  const authHeader = () => ({ Authorization: `Bearer ${token}`, "content-type": "application/json" });

  const PLANS = [
    { id: "house_cut",   name: "The House Cut",   price: 10, blurb: "Regular bonus codes · both platforms" },
    { id: "prime_cut",   name: "The Prime Cut",   price: 15, blurb: "Regular + highroller codes", featured: true },
    { id: "grand_feast", name: "The Grand Feast", price: 30, blurb: "Every code — incl. Saturday stream" },
  ];

  const checkPromo = async () => {
    if (!promoCode.trim()) return;
    setPromoErr(""); setChecking(true); setPromoInfo(null);
    try {
      const r = await fetch("/api/promo/check", {
        method: "POST", headers: authHeader(),
        body: JSON.stringify({ code: promoCode.trim() }),
      });
      const d = await r.json();
      if (d.error) { setPromoErr(d.error); } else { setPromoInfo(d); }
    } catch (_) { setPromoErr("Network error"); }
    setChecking(false);
  };

  const checkout = async () => {
    setPayErr(""); setCheckingOut(true);
    try {
      const r = await fetch("/api/payments/create", {
        method: "POST", headers: authHeader(),
        body: JSON.stringify({
          plan: chosen,
          slot_count: slotCount,
          promo_code: promoCode.trim() || undefined,
        }),
      });
      const d = await r.json();
      if (d.error) { setPayErr(d.error); setCheckingOut(false); return; }
      if (d.dev_mode || !d.invoice_url) {
        setSuccess(true);
        setTimeout(() => window.location.reload(), 2000);
      } else {
        window.location.href = d.invoice_url;
      }
    } catch (_) { setPayErr("Network error — try again"); setCheckingOut(false); }
  };

  const plan = PLANS.find(p => p.id === chosen);
  const baseTotal = plan.price * slotCount;
  const discountedPrice = promoInfo?.promo_type === "discount_pct"
    ? (baseTotal * (1 - promoInfo.value / 100)).toFixed(2)
    : null;

  if (success) return (
    <div className="stack-lg" style={{ textAlign: "center", paddingTop: 60 }}>
      <div style={{ fontSize: 48 }}>🎮</div>
      <h2>Access granted.</h2>
      <p className="muted">Refreshing your dashboard…</p>
    </div>
  );

  return (
    <div className="stack-lg">
      <div>
        <span className="eyebrow">account · billing</span>
        <h2 style={{ fontSize: 24, marginTop: 4 }}>Upgrade plan</h2>
        {user?.plan && user.plan !== "free" && (
          <p className="muted" style={{ marginTop: 4 }}>
            Current: <strong>{user.plan_display || user.plan}</strong>
            {user.plan_expires_at && ` · expires ${new Date(user.plan_expires_at).toLocaleDateString()}`}
          </p>
        )}
      </div>

      <div className="grid-3">
        {PLANS.map(p => (
          <div key={p.id}
            className={"path-card " + (chosen === p.id ? "selected " : "") + (p.featured ? "featured" : "")}
            onClick={() => setChosen(p.id)}>
            {p.featured && <span className="ribbon">recommended</span>}
            <strong style={{ fontSize: 16 }}>{p.name}</strong>
            <p className="muted" style={{ fontSize: 12, marginTop: 4 }}>{p.blurb}</p>
            <div style={{ marginTop: 10, display: "flex", alignItems: "baseline", gap: 4 }}>
              <span style={{ fontFamily: "var(--font-num)", fontSize: 36, fontWeight: 700, color: "var(--text)" }}>
                ${p.price}
              </span>
              <span className="muted" style={{ fontSize: 12 }}>/mo</span>
            </div>
          </div>
        ))}
      </div>

      <Card>
        <div style={{ fontWeight: 600, marginBottom: 12 }}>Promo code</div>
        <div className="row" style={{ gap: 8 }}>
          <Input value={promoCode} onChange={e => { setPromoCode(e.target.value.toUpperCase()); setPromoInfo(null); setPromoErr(""); }}
            placeholder="ENTER CODE" style={{ flex: 1, textTransform: "uppercase", letterSpacing: ".08em" }} />
          <Btn sm kind="ghost" onClick={checkPromo} disabled={checking || !promoCode.trim()}>
            {checking ? "…" : "Apply"}
          </Btn>
        </div>
        {promoInfo && (
          <div className="row" style={{ marginTop: 8, gap: 8 }}>
            <Pill kind="ok" dot>Applied</Pill>
            <span style={{ fontSize: 13, color: "var(--ok)" }}>{promoInfo.description}</span>
          </div>
        )}
        {promoErr && <p style={{ color: "var(--err)", fontSize: 13, marginTop: 6 }}>{promoErr}</p>}
      </Card>

      <Card>
        <div style={{ fontWeight: 600, marginBottom: 12 }}>How many API slots?</div>
        <div className="row" style={{ gap: 6, marginBottom: 14 }}>
          {[1, 2, 3, 4].map(n => (
            <button key={n} onClick={() => setSlots(n)} style={{
              padding: "6px 14px", borderRadius: 999, cursor: "pointer",
              border: `1px solid ${slotCount === n ? "var(--accent)" : "var(--border-2)"}`,
              background: slotCount === n ? "var(--accent)" : "transparent",
              color: slotCount === n ? "#07090c" : "var(--text-2)",
              fontFamily: "var(--font-display)", fontSize: 12, fontWeight: 700,
            }}>{n} slot{n > 1 ? "s" : ""}</button>
          ))}
        </div>
        <div className="row between" style={{ fontSize: 14, marginBottom: 6 }}>
          <span>{plan.name} × {slotCount}</span>
          <span>${plan.price} × {slotCount} = ${baseTotal}/mo</span>
        </div>
        <div className="row between" style={{ fontSize: 12, marginBottom: 6, color: "var(--text-3)" }}>
          <span>Reloads + Stake.us daily dollar</span>
          <span>included</span>
        </div>
        {promoInfo?.promo_type === "free_days" && (
          <div className="row between" style={{ fontSize: 13, color: "var(--ok)", marginBottom: 6 }}>
            <span>+ {promoInfo.value} free days</span>
            <span>free</span>
          </div>
        )}
        {discountedPrice && (
          <div className="row between" style={{ fontSize: 13, color: "var(--ok)", marginBottom: 6 }}>
            <span>{promoInfo.value}% discount</span>
            <span>−${(baseTotal - parseFloat(discountedPrice)).toFixed(2)}</span>
          </div>
        )}
        <div className="divider" />
        <div className="row between" style={{ fontSize: 16, fontWeight: 700 }}>
          <span>Total</span>
          <span>${discountedPrice ?? baseTotal}/mo</span>
        </div>
        {payErr && <p style={{ color: "var(--err)", fontSize: 13, marginTop: 8 }}>{payErr}</p>}
        <Btn kind="primary" lg style={{ width: "100%", marginTop: 16 }} onClick={checkout} disabled={checkingOut}>
          {checkingOut ? "Starting…" : "Pay with crypto →"}
        </Btn>
        <p className="muted" style={{ fontSize: 11, textAlign: "center", marginTop: 8 }}>
          Powered by NOWPayments · BTC, ETH, USDT and more
        </p>
      </Card>
    </div>
  );
};

const PLAN_LABELS = {
  free:        "Free Taste",
  house_cut:   "The House Cut",
  prime_cut:   "The Prime Cut",
  grand_feast: "The Grand Feast",
  // Legacy IDs still possible on in-flight rows mid-deploy
  stake_com: "The House Cut", stake_us: "The House Cut",
  bundle:    "The House Cut", shuffle:  "The House Cut",
  wild_card: "The House Cut", stake_runner: "The House Cut", god_mode: "The House Cut",
};
const PLAN_PRICES = { house_cut: 10, prime_cut: 15, grand_feast: 30 };

const AdminRevenue = () => {
  const [rev, setRev]     = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const token = localStorage.getItem("cc_token");

  React.useEffect(() => {
    fetch("/api/admin/revenue", { headers: { Authorization: `Bearer ${token}` } })
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d) setRev(d); setLoading(false); })
      .catch(() => setLoading(false));
  }, []);

  if (loading) return <p className="muted" style={{ padding: 20 }}>Loading…</p>;
  if (!rev) return <p className="muted" style={{ padding: 20 }}>Failed to load revenue data.</p>;

  const byPlan = rev.by_plan || {};

  return (
    <div className="stack-lg">
      <div>
        <span className="eyebrow">admin · revenue</span>
        <h2 style={{ fontSize: 24, marginTop: 4 }}>
          ${rev.mrr.toFixed(2)} <span style={{ fontSize: 16, color: "var(--text-3)", fontWeight: 400 }}>MRR</span>
        </h2>
        <p className="muted" style={{ fontSize: 13, marginTop: 4 }}>{rev.active_subs} active subscribers · ${rev.arpu} ARPU</p>
      </div>
      <div className="grid-3">
        <Stat k="MRR" n={`$${rev.mrr.toFixed(2)}`} />
        <Stat k="active subs" n={rev.active_subs} />
        <Stat k="ARPU" n={`$${rev.arpu}`} />
      </div>
      <Card>
        <strong style={{ display: "block", marginBottom: 14 }}>Subscribers by plan</strong>
        <div className="stack">
          {Object.entries(byPlan).map(([plan, count]) => {
            const price = PLAN_PRICES[plan] || 0;
            const label = PLAN_LABELS[plan] || plan;
            const planMrr = count * price;
            return (
              <div key={plan} className="row between" style={{ fontSize: 13 }}>
                <span className="muted">{label}</span>
                <span className="row" style={{ gap: 10 }}>
                  <Pill kind={count > 0 ? "ok" : ""} dot={count > 0}>{count} users</Pill>
                  <strong>${planMrr}/mo</strong>
                </span>
              </div>
            );
          })}
        </div>
      </Card>
    </div>
  );
};

const AdminHealth = () => {
  const [stats, setStats]   = React.useState(null);
  const [services, setServices] = React.useState(null);
  const [loading, setLoading] = React.useState(true);

  const authHeader = () => ({ Authorization: `Bearer ${localStorage.getItem("cc_token")}` });

  const load = () => {
    setLoading(true);
    Promise.all([
      fetch("/api/admin/stats",    { headers: authHeader() }).then(r => r.ok ? r.json() : null),
      fetch("/api/admin/services", { headers: authHeader() }).then(r => r.ok ? r.json() : null),
    ]).then(([s, sv]) => {
      if (s)  setStats(s);
      if (sv) setServices(sv);
      setLoading(false);
    }).catch(() => setLoading(false));
  };

  React.useEffect(() => { load(); }, []);

  if (loading) return <p className="muted" style={{ padding: 20 }}>Loading…</p>;
  if (!stats)  return <p className="muted" style={{ padding: 20 }}>Not authorised or failed to load.</p>;

  // turnstile pool — shape: { backend, solver_enabled, stake_com:{tokens,max},
  //   stake_us:{tokens,max}, solves:{ok,failed,last_ok_at,last_error,last_error_at} }
  const ts      = stats.turnstile || {};
  const comPool = ts.stake_com?.tokens ?? 0;
  const comMax  = ts.stake_com?.max    ?? 0;
  const usPool  = ts.stake_us?.tokens  ?? 0;
  const usMax   = ts.stake_us?.max     ?? 0;
  // Solver is "erroring" only if its most recent failure is newer than its
  // most recent success — a stale error after recovery shouldn't alarm.
  const solverErroring = !!ts.solves?.last_error &&
    (ts.solves.last_error_at || 0) > (ts.solves.last_ok_at || 0);

  // services — shape: { summary:{running,dead,cancelled}, cache_age_s, reload_users, daily_users, tasks:[…] }
  const sum   = services?.summary || { running: 0, dead: 0, cancelled: 0 };
  const tasks = services?.tasks || [];
  const fmtAgo = (epoch) => {
    if (!epoch) return "never";
    const s = Math.max(0, Math.round(Date.now() / 1000 - epoch));
    if (s < 60)    return `${s}s ago`;
    if (s < 3600)  return `${Math.round(s / 60)}m ago`;
    return `${Math.round(s / 3600)}h ago`;
  };

  return (
    <div className="stack-lg">
      <div className="row between">
        <div>
          <span className="eyebrow">admin · service health</span>
          <h2 style={{ fontSize: 24, marginTop: 4 }}>Service health</h2>
        </div>
        <span className="row" style={{ gap: 6 }}>
          <Pill kind="ok" dot>claimer · live</Pill>
          <Pill kind={stats.sse_live > 0 ? "ok" : ""} dot={stats.sse_live > 0}>{stats.sse_live} SSE</Pill>
          <Pill kind={sum.dead > 0 ? "err" : "ok"} dot>
            {sum.dead > 0 ? `${sum.dead} task(s) dead` : `${sum.running} task(s) live`}
          </Pill>
          <Pill kind={solverErroring ? "err" : "ok"} dot>
            {solverErroring ? "solver erroring" : "solver ok"}
          </Pill>
          <Btn sm onClick={load}><Icon name="refresh"/> Refresh</Btn>
        </span>
      </div>

      <div className="grid-4">
        <Stat k="total users"  n={stats.total_users} />
        <Stat k="active subs"  n={stats.active_users} />
        <Stat k="total claims" n={stats.total_claims} />
        <Stat k="success rate" n={`${stats.success_rate}%`} />
      </div>

      <div className="grid-2">
        <Card>
          <strong>Turnstile pool</strong>
          <div className="grid-2" style={{ marginTop: 12, gap: 10 }}>
            <Stat k=".com tokens" n={`${comPool} / ${comMax}`} />
            <Stat k=".us tokens"  n={`${usPool} / ${usMax}`} />
          </div>
          <div className="divider" style={{ margin: "10px 0" }}></div>
          <div className="stack-sm" style={{ fontSize: 12 }}>
            <div className="row between">
              <span className="muted">solver backend</span>
              <strong>{ts.backend || "—"}</strong>
            </div>
            <div className="row between">
              <span className="muted">solver enabled</span>
              <Pill kind={ts.solver_enabled ? "ok" : "warn"} dot>{ts.solver_enabled ? "yes" : "no"}</Pill>
            </div>
            <div className="row between">
              <span className="muted">solves (ok / failed)</span>
              <strong>{(ts.solves?.ok ?? 0)} / {(ts.solves?.failed ?? 0)}</strong>
            </div>
            <div className="row between">
              <span className="muted">last successful solve</span>
              <strong>{fmtAgo(ts.solves?.last_ok_at)}</strong>
            </div>
            {ts.solves?.last_error && (
              <div className="row between">
                <span className="muted">last solver error</span>
                <Pill kind="err" dot>{ts.solves.last_error}</Pill>
              </div>
            )}
            <div className="row between">
              <span className="muted">user cache age</span>
              <strong>{services?.cache_age_s != null ? `${services.cache_age_s}s` : "—"}</strong>
            </div>
          </div>
        </Card>
        <Card>
          <strong>Plans breakdown</strong>
          <div className="stack" style={{ marginTop: 10 }}>
            {Object.entries(stats.by_plan || {}).map(([plan, count]) => (
              <div key={plan} className="row between" style={{ fontSize: 13 }}>
                <span className="muted">{PLAN_LABELS[plan] || plan}</span>
                <strong>{count}</strong>
              </div>
            ))}
          </div>
        </Card>
      </div>

      {/* Claim engines — reload + daily-dollar background tasks */}
      <div>
        <div className="row between" style={{ marginBottom: 10 }}>
          <div className="eyebrow">Claim engines · reload + daily-dollar</div>
          <span className="row" style={{ gap: 6 }}>
            <Pill kind="ok" dot>{sum.running} running</Pill>
            {sum.dead > 0 && <Pill kind="err" dot>{sum.dead} dead</Pill>}
            <span className="muted" style={{ fontSize: 11 }}>
              {services?.reload_users ?? 0} reload · {services?.daily_users ?? 0} daily
            </span>
          </span>
        </div>
        <Card style={{ padding: 0 }}>
          {tasks.length === 0 ? (
            <p className="muted" style={{ padding: 20, fontSize: 13 }}>
              No background tasks running — no users have reload or daily-dollar enabled.
            </p>
          ) : (
            <div style={{ overflowX: "auto" }}>
              <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
                <thead>
                  <tr style={{ borderBottom: "1px solid var(--border)", textAlign: "left" }}>
                    {["Engine", "Platform", "User", "State", "Last claim"].map(h => (
                      <th key={h} style={{ padding: "8px 12px", color: "var(--text-3)", fontWeight: 500, whiteSpace: "nowrap" }}>{h}</th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {tasks.map((t, i) => (
                    <tr key={i} style={{ borderBottom: "1px solid var(--border)" }}>
                      <td style={{ padding: "8px 12px", fontWeight: 600 }}>
                        {t.engine === "daily_dollar" ? "Daily dollar" : "Reload"}
                      </td>
                      <td style={{ padding: "8px 12px" }}>{PLAT_LABEL[t.platform] || t.platform}</td>
                      <td style={{ padding: "8px 12px", fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-3)" }}>
                        {(t.user_id || "").slice(0, 8)}
                      </td>
                      <td style={{ padding: "8px 12px" }}>
                        <Pill kind={t.state === "running" ? "ok" : t.state === "dead" ? "err" : "warn"} dot>
                          {t.state}
                        </Pill>
                      </td>
                      <td style={{ padding: "8px 12px", color: "var(--text-3)" }}>{fmtAgo(t.last_claim)}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </Card>
      </div>
    </div>
  );
};

Object.assign(window, { Dashboard });
