// Vanday — admin / super-admin dashboard.
//
// Loaded for users whose Clerk userId is in the VANDAY_ADMIN_USER_IDS env var
// on the server. Shows engagement metrics + a per-user table + the inbox of
// integrations beta users have asked for.

function AdminDashboard({ onClose }) {
  const [stats, setStats] = React.useState(null);
  const [requests, setRequests] = React.useState(null);
  const [error, setError] = React.useState(null);
  const [tab, setTab] = React.useState("overview"); // overview | workspaces | users | requests

  const authHeaders = async () => {
    try {
      const t = window.Clerk?.session ? await window.Clerk.session.getToken() : null;
      return t ? { Authorization: `Bearer ${t}` } : {};
    } catch { return {}; }
  };

  const load = React.useCallback(async () => {
    setError(null);
    try {
      const h = await authHeaders();
      const [s, r] = await Promise.all([
        fetch("/api/admin/stats", { headers: h }).then((x) => x.ok ? x.json() : Promise.reject(x.status)),
        fetch("/api/admin/feature-requests", { headers: h }).then((x) => x.ok ? x.json() : Promise.reject(x.status)),
      ]);
      setStats(s);
      setRequests(r.requests || []);
    } catch (err) {
      setError(typeof err === "number" ? `Server returned ${err}` : String(err));
    }
  }, []);

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

  const fmtDate = (ts) => ts ? new Date(ts).toLocaleString() : "—";
  const fmtAgo = (ts) => {
    if (!ts) return "—";
    const m = Math.floor((Date.now() - ts) / 60000);
    if (m < 1) return "just now";
    if (m < 60) return `${m}m ago`;
    const h = Math.floor(m / 60);
    if (h < 24) return `${h}h ago`;
    return `${Math.floor(h / 24)}d ago`;
  };

  return (
    <div style={{ padding: "32px 36px", maxWidth: 1100, margin: "0 auto", fontFamily: "inherit" }}>
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 22 }}>
        <div>
          <h1 style={{ fontSize: 24, fontWeight: 600, margin: 0 }}>Admin · Vanday</h1>
          <p style={{ color: "var(--text-muted)", fontSize: 13.5, margin: "4px 0 0" }}>
            Engagement, growth and the integration wishlist
          </p>
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <button className="btn" onClick={load}>Refresh</button>
          {onClose && <button className="btn" onClick={onClose}>Back to library</button>}
        </div>
      </div>

      {/* Tabs */}
      <div style={{ display: "flex", gap: 4, borderBottom: "1px solid var(--border)", marginBottom: 24 }}>
        {["overview", "workspaces", "users", "requests"].map((t) => (
          <button
            key={t}
            onClick={() => setTab(t)}
            style={{
              padding: "10px 16px", border: "none", background: "none",
              fontSize: 14, fontWeight: tab === t ? 600 : 400,
              color: tab === t ? "var(--text)" : "var(--text-muted)",
              borderBottom: tab === t ? "2px solid var(--brand)" : "2px solid transparent",
              cursor: "pointer",
            }}
          >
            {t === "overview" ? "Overview"
              : t === "workspaces" ? `Workspaces${stats?.orgs ? ` (${stats.orgs.length})` : ""}`
              : t === "users" ? "Users"
              : `Integration requests${requests ? ` (${requests.length})` : ""}`}
          </button>
        ))}
      </div>

      {error && (
        <div style={{ padding: 16, background: "oklch(0.95 0.05 24)", color: "oklch(0.4 0.18 24)", borderRadius: 8, marginBottom: 20 }}>
          {error}
        </div>
      )}

      {!stats && !error && <div style={{ color: "var(--text-muted)" }}>Loading…</div>}

      {/* Overview tab */}
      {tab === "overview" && stats && (
        <>
          <div style={{ fontSize: 11, fontWeight: 600, textTransform: "uppercase", letterSpacing: 0.4, color: "var(--text-faint)", marginBottom: 8 }}>
            Workspaces (tenants)
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))", gap: 12, marginBottom: 22 }}>
            <Stat label="Total workspaces"     value={stats.totals.totalOrgs ?? 0} />
            <Stat label="New in last 7 days"   value={stats.totals.newOrgs7d ?? 0} />
            <Stat label="Active in last 7 days" value={stats.totals.activeOrgs7d ?? 0} />
            <Stat label="MRR (placeholder)"    value={`$${(stats.totals.mrr ?? 0).toFixed(0)}`} />
          </div>
          <div style={{ fontSize: 11, fontWeight: 600, textTransform: "uppercase", letterSpacing: 0.4, color: "var(--text-faint)", marginBottom: 8 }}>
            Users + activity
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))", gap: 12 }}>
            <Stat label="Total signups"        value={stats.totals.totalUsers} />
            <Stat label="New in last 7 days"   value={stats.totals.newUsers7d} />
            <Stat label="Active in last 24h"   value={stats.totals.dau} />
            <Stat label="Active in last 7 days" value={stats.totals.wau} />
            <Stat label="Total uploads"        value={stats.totals.totalUploads} />
            <Stat label="Integration requests" value={stats.totals.totalFeatureRequests} />
          </div>
        </>
      )}

      {/* Workspaces tab — the main per-tenant view */}
      {tab === "workspaces" && stats && (
        <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10, overflow: "hidden" }}>
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13.5, minWidth: 1320 }}>
              <thead>
                <tr style={{ background: "var(--surface-sunken)", textAlign: "left" }}>
                  <th style={{ ...th(), ...stickyHeadCol() }}>Workspace</th>
                  <th style={th()}>Plan</th>
                  <th style={th()}>Members</th>
                  <th style={th()}>Uploads</th>
                  <th style={th()}>Storage</th>
                  <th style={th()}>Downloads</th>
                  <th style={th()}>Comments</th>
                  <th style={th()}>Searches</th>
                  <th style={th()}>Logins</th>
                  <th style={th()}>Published</th>
                  <th style={th()}>Limits (uploads / seats / storage)</th>
                  <th style={th()}>Last active</th>
                  <th style={th()}>Upload-Post profile</th>
                  <th style={th()}></th>
                </tr>
              </thead>
              <tbody>
                {stats.orgs?.length === 0 ? (
                  <tr><td style={td()} colSpan={14}>No workspaces yet.</td></tr>
                ) : (stats.orgs || []).map((o) => (
                  <AdminWorkspaceRow
                    key={o.id}
                    o={o}
                    viewerId={stats.viewerId}
                    authHeaders={authHeaders}
                    reload={load}
                    fmtDate={fmtDate}
                    fmtAgo={fmtAgo}
                  />
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {/* Users tab */}
      {tab === "users" && stats && (
        <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10, overflow: "hidden" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13.5 }}>
            <thead>
              <tr style={{ background: "var(--surface-sunken)", textAlign: "left" }}>
                <th style={th()}>Email</th>
                <th style={th()}>Uploads</th>
                <th style={th()}>Logins</th>
                <th style={th()}>Last seen</th>
                <th style={th()}>Signed up</th>
              </tr>
            </thead>
            <tbody>
              {stats.users.length === 0 ? (
                <tr><td style={td()} colSpan={5}>No users yet.</td></tr>
              ) : stats.users.map((u) => (
                <tr key={u.id} style={{ borderTop: "1px solid var(--border)" }}>
                  <td style={td()}>{u.email || u.id.slice(0, 20) + "…"}</td>
                  <td style={td()}>{u.uploads}</td>
                  <td style={td()}>{u.login_count}</td>
                  <td style={td()} title={fmtDate(u.last_seen_at)}>{fmtAgo(u.last_seen_at)}</td>
                  <td style={td()} title={fmtDate(u.created_at)}>{fmtAgo(u.created_at)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {/* Requests tab */}
      {tab === "requests" && (
        <div style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10, overflow: "hidden" }}>
          {requests && requests.length === 0 ? (
            <div style={{ padding: 24, color: "var(--text-muted)" }}>No feature requests yet.</div>
          ) : (
            <div style={{ display: "flex", flexDirection: "column" }}>
              {(requests || []).map((r) => (
                <div key={r.id} style={{ padding: "16px 20px", borderBottom: "1px solid var(--border)" }}>
                  <div style={{ fontSize: 12, color: "var(--text-faint)", marginBottom: 4 }}>
                    {r.kind} · {fmtAgo(r.created_at)} · {r.user_id ? r.user_id.slice(0, 18) + "…" : "anonymous"}
                  </div>
                  <div style={{ fontSize: 14, color: "var(--text)", whiteSpace: "pre-wrap" }}>{r.body}</div>
                </div>
              ))}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// Default beta limits — shown as placeholders when no per-account override
// is set. Keep in sync with BETA_MAX_UPLOADS / BETA_MAX_SEATS on the server.
const DEFAULT_MAX_UPLOADS = 100;
const DEFAULT_MAX_SEATS = 3;
const DEFAULT_MAX_STORAGE_GB = 50;
const BYTES_PER_GB = 1024 * 1024 * 1024;

// Human-friendly byte size: MB under ~0.1 GB, otherwise GB.
function fmtBytesGB(bytes) {
  const gb = (bytes || 0) / BYTES_PER_GB;
  if (gb < 0.1) return ((bytes || 0) / (1024 * 1024)).toFixed(1) + " MB";
  return gb.toFixed(2) + " GB";
}

// One workspace row. Owns its own state for the inline limit-override editor
// and the typed-confirmation delete modal so the parent table stays simple.
function AdminWorkspaceRow({ o, viewerId, authHeaders, reload, fmtDate, fmtAgo }) {
  // "Yours" = your personal workspace (id === your user id) or any workspace
  // you created. These are protected: no delete button, marked with a badge.
  const isMine = !!viewerId && (o.id === viewerId || o.created_by === viewerId);
  const [editing, setEditing] = React.useState(false);
  const [uploads, setUploads] = React.useState(
    o.max_uploads_override != null ? String(o.max_uploads_override) : "");
  const [seats, setSeats] = React.useState(
    o.max_seats_override != null ? String(o.max_seats_override) : "");
  const [storageGB, setStorageGB] = React.useState(
    o.max_storage_bytes_override != null ? String(o.max_storage_bytes_override / BYTES_PER_GB) : "");
  const [busy, setBusy] = React.useState(false);
  const [rowError, setRowError] = React.useState(null);
  const [confirming, setConfirming] = React.useState(false);

  // Empty string -> null (clear override); otherwise a non-negative integer.
  const parseLimit = (s) => {
    const t = String(s).trim();
    if (t === "") return null;
    const n = Math.floor(Number(t));
    if (!Number.isFinite(n) || n < 0) throw new Error("Limits must be 0 or a positive whole number.");
    return n;
  };
  // Storage is entered in GB (fractions allowed) and stored in bytes.
  const parseStorageBytes = (s) => {
    const t = String(s).trim();
    if (t === "") return null;
    const gb = Number(t);
    if (!Number.isFinite(gb) || gb < 0) throw new Error("Storage must be 0 or a positive number of GB.");
    return Math.round(gb * BYTES_PER_GB);
  };

  const saveLimits = async () => {
    setRowError(null);
    let body;
    try {
      body = { maxUploads: parseLimit(uploads), maxSeats: parseLimit(seats), maxStorageBytes: parseStorageBytes(storageGB) };
    } catch (e) { setRowError(e.message); return; }
    setBusy(true);
    try {
      const h = await authHeaders();
      const r = await fetch(`/api/admin/orgs/${encodeURIComponent(o.id)}/limits`, {
        method: "POST",
        headers: { ...h, "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });
      if (!r.ok) throw new Error(`Server returned ${r.status}`);
      setEditing(false);
      await reload();
    } catch (e) {
      setRowError(String(e.message || e));
    } finally { setBusy(false); }
  };

  const overrideLabel = (val, dflt) =>
    val != null
      ? <strong style={{ color: "var(--text)" }}>{val}</strong>
      : <span style={{ color: "var(--text-faint)" }}>{dflt} (default)</span>;

  return (
    <>
      <tr style={{ borderTop: "1px solid var(--border)" }}>
        <td style={{ ...td(), ...stickyBodyCol(isMine) }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
            <span style={{ fontWeight: 500 }}>{o.name}</span>
            {isMine && (
              <span style={{
                display: "inline-block", padding: "1px 7px", borderRadius: 999,
                fontSize: 10.5, fontWeight: 700, letterSpacing: 0.4, textTransform: "uppercase",
                background: "oklch(0.93 0.07 155)", color: "oklch(0.32 0.13 155)",
              }}>Your account</span>
            )}
          </div>
          <div style={{ fontSize: 11, color: "var(--text-faint)", fontFamily: "ui-monospace, SFMono-Regular, monospace" }}>
            {o.id.slice(0, 22)}{o.id.length > 22 ? "…" : ""}
          </div>
        </td>
        <td style={td()}><PlanPill plan={o.plan} /></td>
        <td style={td()}>{o.member_count}</td>
        <td style={td()}>{o.upload_count}</td>
        <td style={td()}>{fmtBytesGB(o.storage_bytes)}</td>
        <td style={td()}>{o.download_count ?? 0}</td>
        <td style={td()}>{o.comment_count ?? 0}</td>
        <td style={td()}>{o.search_count ?? 0}</td>
        <td style={td()}>{o.total_logins ?? 0}</td>
        <td style={td()}>{o.assets_with_publications}</td>
        <td style={td()}>
          {editing ? (
            <div style={{ display: "flex", flexDirection: "column", gap: 6, minWidth: 200 }}>
              <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
                <input
                  type="number" min="0" value={uploads}
                  onChange={(e) => setUploads(e.target.value)}
                  placeholder={String(DEFAULT_MAX_UPLOADS)}
                  style={limitInput()} disabled={busy} title="Max uploads"
                />
                <span style={{ color: "var(--text-faint)" }}>/</span>
                <input
                  type="number" min="0" value={seats}
                  onChange={(e) => setSeats(e.target.value)}
                  placeholder={String(DEFAULT_MAX_SEATS)}
                  style={limitInput()} disabled={busy} title="Max seats"
                />
                <span style={{ color: "var(--text-faint)" }}>/</span>
                <input
                  type="number" min="0" step="0.1" value={storageGB}
                  onChange={(e) => setStorageGB(e.target.value)}
                  placeholder={String(DEFAULT_MAX_STORAGE_GB)}
                  style={limitInput()} disabled={busy} title="Max storage (GB)"
                />
                <span style={{ color: "var(--text-faint)", fontSize: 12 }}>GB</span>
              </div>
              <div style={{ display: "flex", gap: 6 }}>
                <button className="btn btn-primary" style={{ padding: "3px 10px", fontSize: 12 }} onClick={saveLimits} disabled={busy}>
                  {busy ? "Saving…" : "Save"}
                </button>
                <button className="btn" style={{ padding: "3px 10px", fontSize: 12 }} onClick={() => {
                  setEditing(false); setRowError(null);
                  setUploads(o.max_uploads_override != null ? String(o.max_uploads_override) : "");
                  setSeats(o.max_seats_override != null ? String(o.max_seats_override) : "");
                  setStorageGB(o.max_storage_bytes_override != null ? String(o.max_storage_bytes_override / BYTES_PER_GB) : "");
                }} disabled={busy}>Cancel</button>
              </div>
              <div style={{ fontSize: 11, color: "var(--text-faint)" }}>Uploads / seats / storage (GB). Leave blank to use the default.</div>
              {rowError && <div style={{ fontSize: 11, color: "oklch(0.5 0.2 24)" }}>{rowError}</div>}
            </div>
          ) : (
            <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
              <span>
                {overrideLabel(o.max_uploads_override, DEFAULT_MAX_UPLOADS)}
                {" / "}{overrideLabel(o.max_seats_override, DEFAULT_MAX_SEATS)}
                {" / "}{overrideLabel(
                  o.max_storage_bytes_override != null ? `${o.max_storage_bytes_override / BYTES_PER_GB} GB` : null,
                  `${DEFAULT_MAX_STORAGE_GB} GB`,
                )}
              </span>
              <button className="btn" style={{ padding: "2px 8px", fontSize: 11 }} onClick={() => setEditing(true)}>Edit</button>
            </div>
          )}
        </td>
        <td style={td()} title={fmtDate(o.last_active_at)}>{fmtAgo(o.last_active_at)}</td>
        <td style={td()} title={o.upload_post_username || ""}>
          <UploadPostBadge username={o.upload_post_username} />
        </td>
        <td style={td()}>
          {isMine ? (
            <span style={{ fontSize: 12, color: "var(--text-faint)" }} title="You cannot delete your own account from here.">—</span>
          ) : (
            <button
              className="btn"
              style={{ padding: "3px 10px", fontSize: 12, color: "oklch(0.5 0.2 24)", borderColor: "oklch(0.8 0.1 24)" }}
              onClick={() => setConfirming(true)}
            >Delete</button>
          )}
        </td>
      </tr>
      {confirming && (
        <tr>
          <td colSpan={14} style={{ padding: 0 }}>
            <AdminDeleteAccount
              o={o}
              authHeaders={authHeaders}
              onClose={() => setConfirming(false)}
              onDeleted={async () => { setConfirming(false); await reload(); }}
            />
          </td>
        </tr>
      )}
    </>
  );
}

// Typed-confirmation delete panel. Deletes the workspace owner's entire
// account: all data, files, the (non-shared) Upload-Post profile, and the
// Clerk login. Irreversible — requires typing DELETE to arm the button.
function AdminDeleteAccount({ o, authHeaders, onClose, onDeleted }) {
  const [typed, setTyped] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const armed = typed.trim().toUpperCase() === "DELETE";

  const doDelete = async () => {
    if (!armed) return;
    setBusy(true); setErr(null);
    try {
      const h = await authHeaders();
      const r = await fetch(`/api/admin/accounts/${encodeURIComponent(o.id)}`, {
        method: "DELETE", headers: h,
      });
      if (!r.ok) {
        let msg = `Server returned ${r.status}`;
        try { const j = await r.json(); if (j.message || j.error) msg = j.message || j.error; } catch {}
        throw new Error(msg);
      }
      await onDeleted();
    } catch (e) {
      setErr(String(e.message || e));
      setBusy(false);
    }
  };

  return (
    <div style={{
      margin: "0 16px 14px", padding: "16px 18px",
      background: "oklch(0.97 0.03 24)", border: "1px solid oklch(0.85 0.09 24)",
      borderRadius: 10,
    }}>
      <div style={{ fontWeight: 600, color: "oklch(0.4 0.18 24)", marginBottom: 6 }}>
        Permanently delete “{o.name}”?
      </div>
      <div style={{ fontSize: 13, color: "var(--text-muted)", marginBottom: 12, lineHeight: 1.5 }}>
        This removes the owner’s account and <strong>cannot be undone</strong>: all assets and files,
        comments, shares, memberships, the Upload-Post profile
        {o.upload_post_username && o.upload_post_username !== "vandayai"
          ? <> (<code>{o.upload_post_username}</code>)</>
          : <> (shared profile is left untouched)</>}, and the Clerk login.
      </div>
      <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
        <input
          value={typed}
          onChange={(e) => setTyped(e.target.value)}
          placeholder="Type DELETE to confirm"
          style={{ padding: "6px 10px", borderRadius: 8, border: "1px solid var(--border)", fontSize: 13, width: 200 }}
          disabled={busy} autoFocus
        />
        <button
          className="btn"
          style={{
            padding: "6px 14px", fontSize: 13, fontWeight: 600,
            background: armed ? "oklch(0.55 0.2 24)" : "var(--surface-sunken)",
            color: armed ? "white" : "var(--text-faint)",
            borderColor: "transparent", cursor: armed ? "pointer" : "not-allowed",
          }}
          onClick={doDelete}
          disabled={!armed || busy}
        >{busy ? "Deleting…" : "Delete account"}</button>
        <button className="btn" style={{ padding: "6px 14px", fontSize: 13 }} onClick={onClose} disabled={busy}>Cancel</button>
      </div>
      {err && <div style={{ marginTop: 10, fontSize: 12.5, color: "oklch(0.45 0.2 24)" }}>{err}</div>}
    </div>
  );
}

function limitInput() {
  return { width: 64, padding: "4px 8px", borderRadius: 6, border: "1px solid var(--border)", fontSize: 13 };
}

function PlanPill({ plan }) {
  const known = {
    free_beta: { label: "Free beta", bg: "oklch(0.95 0.04 280)", fg: "oklch(0.32 0.13 280)" },
    pro:       { label: "Pro",       bg: "oklch(0.93 0.07 155)", fg: "oklch(0.32 0.13 155)" },
    team:      { label: "Team",      bg: "oklch(0.94 0.07 32)",  fg: "oklch(0.42 0.16 32)" },
    system:    { label: "System",    bg: "var(--surface-sunken)", fg: "var(--text-muted)" },
  };
  const p = known[plan] || { label: plan || "—", bg: "var(--surface-sunken)", fg: "var(--text-muted)" };
  return (
    <span style={{
      display: "inline-block",
      padding: "2px 8px", borderRadius: 999,
      fontSize: 11, fontWeight: 600, letterSpacing: 0.3,
      background: p.bg, color: p.fg,
    }}>{p.label}</span>
  );
}

function UploadPostBadge({ username }) {
  if (!username) {
    return <span style={{ fontSize: 12, color: "var(--text-faint)" }}>none</span>;
  }
  // Shared profile means this workspace is using your master `vandayai`
  // account. Show that explicitly so it's obvious which orgs are isolated.
  const isShared = username === "vandayai";
  return (
    <span style={{
      fontFamily: "ui-monospace, SFMono-Regular, monospace",
      fontSize: 11.5,
      color: isShared ? "oklch(0.42 0.16 32)" : "var(--text-muted)",
    }}>
      {username}{isShared ? " (shared)" : ""}
    </span>
  );
}

function Stat({ label, value }) {
  return (
    <div style={{
      background: "var(--surface)", border: "1px solid var(--border)",
      borderRadius: 10, padding: "16px 18px",
    }}>
      <div style={{ fontSize: 12, color: "var(--text-faint)", textTransform: "uppercase", letterSpacing: 0.4 }}>{label}</div>
      <div style={{ fontSize: 28, fontWeight: 600, marginTop: 6 }}>{value}</div>
    </div>
  );
}

function th() { return { padding: "10px 16px", fontWeight: 600, fontSize: 12, color: "var(--text-muted)", textTransform: "uppercase", letterSpacing: 0.4 }; }
function td() { return { padding: "12px 16px" }; }

// Freeze the first ("Workspace") column so it stays visible while the wide
// metrics table scrolls horizontally. Sticky cells need their own opaque
// background or the scrolling columns show through; the box-shadow draws a
// crisp divider plus a soft edge so it reads as a pinned column.
function stickyBodyCol(isMine) {
  return {
    position: "sticky", left: 0, zIndex: 1,
    // Tint your own accounts so they're recognisable at a glance.
    background: isMine ? "oklch(0.97 0.025 155)" : "var(--surface)",
    boxShadow: "1px 0 0 var(--border), 4px 0 8px rgba(0,0,0,0.04)",
  };
}
function stickyHeadCol() {
  return {
    position: "sticky", left: 0, zIndex: 2,
    background: "var(--surface-sunken)",
    boxShadow: "1px 0 0 var(--border), 4px 0 8px rgba(0,0,0,0.04)",
  };
}

window.AdminDashboard = AdminDashboard;
