// Admin page host. A thin shell with an internal sub-tab bar holding the AWS
// Resources view (<AwsResources/>) and User Management (<AdminUsers/>). Reached
// from the ☰ menu (admin-only — the entry is gated on user.is_admin from
// /api/auth/me, and every /api/admin/* + /api/aws/* route is gated server-side,
// so this page can't be reached by forging the hash). Sub-tab is kept in the URL
// hash (#admin/aws) so reloads/links restore it.

// Hooks via React.useState/etc. (not top-level destructured) to avoid redeclaring
// the globals App.jsx binds in the shared text/babel scope.

const ADMIN_TABS = [
  { key: "aws", label: "AWS Resources", render: () => <AwsResources /> },
  { key: "sip", label: "SIP Data", render: () => <SipCapture /> },
  { key: "tape", label: "Market Data", render: () => <DataInventory /> },
  { key: "users", label: "Users", render: () => <AdminUsers /> },
];

function _adminSubFromHash() {
  const h = location.hash.slice(1);             // e.g. "admin/aws"
  const sub = h.split("/")[1];
  return ADMIN_TABS.some(t => t.key === sub) ? sub : ADMIN_TABS[0].key;
}

function Admin() {
  const [sub, setSub] = React.useState(_adminSubFromHash);

  // Keep the sub-tab in the hash without clobbering the top-level "admin" route.
  const pick = (key) => { setSub(key); history.replaceState(null, "", "#admin/" + key); };
  React.useEffect(() => {
    const onHash = () => setSub(_adminSubFromHash());
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);

  const active = ADMIN_TABS.find(t => t.key === sub) || ADMIN_TABS[0];

  return (
    <div>
      <div style={{ display: "flex", gap: 6, marginBottom: 18, borderBottom: `1px solid ${UI.c.borderSoft}`, paddingBottom: 2 }}>
        {ADMIN_TABS.map(t => (
          <button key={t.key} className={"tab" + (t.key === sub ? " active" : "")} onClick={() => pick(t.key)}>{t.label}</button>
        ))}
      </div>
      {active.render()}
    </div>
  );
}

// Market-data inventory — how much we've captured per day, per type, in the
// TimescaleDB store (GET /api/tape/inventory, admin-only). Entry counts now;
// on-disk MB is added once the real Timescale instance exists (chunk sizes).
function DataInventory() {
  const [rows, setRows] = React.useState(null);   // [{date, channel, records}]
  React.useEffect(() => {
    (async () => {
      try { setRows(await (await apiFetch("/api/tape/inventory")).json()); }
      catch { setRows({ error: true }); }
    })();
  }, []);

  if (rows && rows.error) return <EmptyState title="Couldn't load the market-data inventory." />;
  if (!rows) return <Skeleton />;

  // Pivot to one row per day with a column per channel.
  const channels = Array.from(new Set(rows.map(r => r.channel))).sort();
  const byDate = {};
  for (const r of rows) (byDate[r.date] = byDate[r.date] || {})[r.channel] = r.records;
  const dates = Object.keys(byDate).sort().reverse();
  const totals = channels.map(c => rows.filter(r => r.channel === c).reduce((s, r) => s + r.records, 0));

  return (
    <div>
      <PageHeader title="Market data captured"
        subtitle="Rows ingested into the market-data store (TimescaleDB), per UTC day and type." />
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))", gap: 12, marginBottom: 14 }}>
        {channels.map((c, i) => <Stat key={c} label={`Total ${c}`} value={totals[i].toLocaleString()} />)}
      </div>
      <Card title="By day">
        {dates.length === 0 ? <EmptyState title="No market data captured yet." /> : (
          <table className="tbl">
            <thead><tr><th>Date (UTC)</th>{channels.map(c => <th key={c} style={{ textAlign: "right" }}>{c}</th>)}</tr></thead>
            <tbody>
              {dates.map(d => (
                <tr key={d}>
                  <td>{d}</td>
                  {channels.map(c => (
                    <td key={c} style={{ textAlign: "right" }}>
                      {byDate[d][c] != null ? byDate[d][c].toLocaleString() : "—"}
                    </td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </Card>
    </div>
  );
}

// User management — lists every auth-store user and lets an admin promote/demote
// others. The first admin is seeded out-of-band via `./cmd/manage.sh set-admin`.
function AdminUsers() {
  const [data, setData] = React.useState(null);   // GET /api/admin/users
  const [msg, setMsg] = React.useState(null);      // {ok, text}
  const [busyId, setBusyId] = React.useState(null);

  const load = async () => {
    try {
      const d = await (await apiFetch("/api/admin/users")).json();
      setData(d);
    } catch { setData({ error: true }); }
  };
  React.useEffect(() => { load(); }, []);

  const setAdmin = async (u, isAdmin) => {
    if (!isAdmin && !window.confirm(`Revoke admin rights from ${u.email}?`)) return;
    setBusyId(u.id); setMsg(null);
    try {
      const r = await apiPost(`/api/admin/users/${u.id}/admin`, { is_admin: isAdmin });
      const d = await r.json();
      if (!r.ok) setMsg({ ok: false, text: d.detail || "Update failed." });
      else {
        setMsg({ ok: true, text: `${u.email} is ${isAdmin ? "now an admin" : "no longer an admin"}.` });
        await load();
      }
    } catch (e) { setMsg({ ok: false, text: String(e) }); }
    setBusyId(null);
  };

  if (!data) return <Skeleton height={260} />;

  if (data.error) {
    return <Card><div style={{ color: UI.c.red, fontSize: 13 }}>Couldn't load users.</div></Card>;
  }

  if (data.auth_enabled === false) {
    return (
      <Card><div style={{ color: UI.c.dim, fontSize: 13 }}>
        Auth is disabled (local/dev mode) — there are no per-user accounts to manage.
        Enable <code>AUTH_ENABLED</code> and sign in with Google to manage users.
      </div></Card>
    );
  }

  const users = data.users || [];
  const adminCount = users.filter(u => u.is_admin).length;
  const th = { textAlign: "left", padding: "8px 12px", fontSize: 11, color: UI.c.faint,
               textTransform: "uppercase", letterSpacing: 0.5, borderBottom: `1px solid ${UI.c.border}` };
  const td = { padding: "10px 12px", fontSize: 13, borderBottom: `1px solid ${UI.c.border}` };

  return (
    <div style={{ maxWidth: 860 }}>
      <Card title={`Users (${users.length})`}>
        {users.length === 0 ? (
          <EmptyState title="No users yet" hint="Users appear here after their first sign-in." />
        ) : (
          <table style={{ width: "100%", borderCollapse: "collapse" }}>
            <thead>
              <tr>
                <th style={th}>Email</th>
                <th style={th}>Mode</th>
                <th style={th}>Creds</th>
                <th style={th}>Autostart</th>
                <th style={th}>Admin</th>
                <th style={{ ...th, textAlign: "right" }}>Action</th>
              </tr>
            </thead>
            <tbody>
              {users.map(u => {
                const isSelf = u.id === data.current_user_id;
                const lastAdmin = u.is_admin && adminCount <= 1;
                return (
                  <tr key={u.id}>
                    <td style={td}>
                      <span style={{ color: UI.c.text }}>{u.email}</span>
                      {isSelf && <span style={{ color: UI.c.faint, fontSize: 11.5 }}> · you</span>}
                    </td>
                    <td style={td}>
                      {u.paper ? <Badge tone="green">PAPER</Badge> : <Badge tone="amber">LIVE</Badge>}
                    </td>
                    <td style={td}>{u.has_creds
                      ? <span style={{ color: UI.c.green }}>✓</span>
                      : <span style={{ color: UI.c.faint }}>—</span>}</td>
                    <td style={td}>{u.engine_autostart
                      ? <span style={{ color: UI.c.dim }}>on</span>
                      : <span style={{ color: UI.c.faint }}>off</span>}</td>
                    <td style={td}>{u.is_admin
                      ? <Badge tone="blue">ADMIN</Badge>
                      : <span style={{ color: UI.c.faint }}>—</span>}</td>
                    <td style={{ ...td, textAlign: "right" }}>
                      <PillButton
                        disabled={busyId === u.id || lastAdmin}
                        title={lastAdmin ? "Can't remove the last admin" : undefined}
                        onClick={() => setAdmin(u, !u.is_admin)}>
                        {u.is_admin ? "Revoke admin" : "Make admin"}
                      </PillButton>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
        {msg && <div style={{ marginTop: 12, color: msg.ok ? UI.c.green : UI.c.red, fontSize: 13 }}>{msg.text}</div>}
      </Card>

      <div style={{ color: UI.c.faint, fontSize: 11.5, marginTop: 12, lineHeight: 1.5 }}>
        Admin rights gate the Admin page only — they don't change what any account trades.
        The first admin is seeded with <code>./cmd/manage.sh set-admin --email &lt;you&gt;</code>.
      </div>
    </div>
  );
}
