// Audit Log — Vault-wide write history, admin only.
// One row per write through the vault-auth-proxy Worker (audit_log table).
// Bulk imports appear as one logical row (the commit_* RPC); get_/list_/stage_
// RPCs and reads are never logged. RLS restricts SELECT to is_admin accounts.
(function () {
  const { useState, useEffect, useMemo, useCallback } = React;
  const BLUE = "#196EA7", INK = "#1A2733", INK2 = "#5A6B7B", MUTE = "#93A1B0", LINE = "#E4E9F0";
  const PAGE_SIZE = 50;

  // Category map: table / rpc name -> nav section. Anything unlisted lands in "Other".
  const CATEGORIES = [
    { key: "actions", label: "Action Dashboard", names: [
      "user_actions", "pipeline_actions", "project_actions", "new_clients",
      "crs", "cr_reminder_state", "cr_calendar_feed", "calendar_feeds",
      "cadence_actions_done", "mark_cadence_done", "unmark_cadence_done",
    ]},
    { key: "research", label: "Research Dashboard", names: [
      "research_goals", "research_plans", "rpm_cards", "rpm_card_notes",
      "create_research_goal", "progression_cards",
    ]},
    { key: "activity", label: "Activity Dashboard", names: [
      "closed_deals", "harvey_offers", "upsert_offer", "delete_offer",
      "pipeline_picks", "upsert_pipeline_pick", "clear_my_pipeline_picks",
    ]},
    { key: "tools", label: "Project Health & Tools", names: [
      "white_space_projects", "projects", "project_links", "client_project_map",
      "project_universe", "project_lists",
    ]},
    { key: "admin", label: "Administrative", names: [
      "people", "authorized_users", "goals_config", "data_uploads",
      "commit_table_load", "commit_table_append", "commit_table_window_replace",
      "replace_table_data", "undo_last_upload", "backfill_cr_target",
    ]},
  ];
  const NAME_TO_CATEGORY = {};
  CATEGORIES.forEach(c => c.names.forEach(n => { NAME_TO_CATEGORY[n] = c.label; }));

  const ACTION_LABEL = { POST: "Insert", PATCH: "Update", DELETE: "Delete" };
  function actionLabel(row) {
    if (row.kind === "rpc") return "RPC";
    return ACTION_LABEL[row.method] || row.method;
  }
  const ACTION_TINT = {
    Insert: { bg: "#E9F5EE", fg: "#1F7A46" },
    Update: { bg: "#EEF4FB", fg: BLUE },
    Delete: { bg: "#FBEEEE", fg: "#B0413E" },
    RPC:    { bg: "#F3EFFA", fg: "#6B4FA0" },
  };

  function fmtTs(ts) {
    if (!ts) return "";
    const d = new Date(ts);
    return d.toLocaleDateString("en-US", { month: "short", day: "numeric" }) + " " +
           d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
  }
  function isoStart(d) { return d ? d + "T00:00:00" : null; }
  function isoEnd(d)   { return d ? d + "T23:59:59" : null; }

  function AuditLogScreen() {
    const [rows, setRows]       = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError]     = useState(null);
    const [page, setPage]       = useState(0);
    const [hasMore, setHasMore] = useState(false);
    const [expanded, setExpanded] = useState(null);

    // Filters
    const [fUser, setFUser]   = useState("");
    const [fCat, setFCat]     = useState("");
    const [fAct, setFAct]     = useState("");
    const [fFrom, setFFrom]   = useState("");
    const [fTo, setFTo]       = useState("");

    const userOptions = useMemo(() => {
      const emails = new Set((window.VAULT_ACCOUNTS || []).map(a => a.email));
      rows.forEach(r => emails.add(r.user_email));
      return Array.from(emails).sort();
    }, [rows]);

    const load = useCallback(async (pageN) => {
      setLoading(true); setError(null);
      try {
        const cat = CATEGORIES.find(c => c.key === fCat);
        const method = fAct === "RPC" ? null : ({ Insert: "POST", Update: "PATCH", Delete: "DELETE" }[fAct] || null);
        const kind   = fAct === "RPC" ? "rpc" : null;
        const data = await window.VaultAPI.getAuditLog({
          user: fUser || null,
          kind,
          names: cat ? cat.names : null,
          method,
          from: isoStart(fFrom),
          to: isoEnd(fTo),
          limit: PAGE_SIZE + 1,
          offset: pageN * PAGE_SIZE,
        });
        setHasMore(data.length > PAGE_SIZE);
        setRows(data.slice(0, PAGE_SIZE));
      } catch (e) {
        setError(e.message || String(e));
        setRows([]);
      }
      setLoading(false);
    }, [fUser, fCat, fAct, fFrom, fTo]);

    useEffect(() => { setPage(0); load(0); }, [load]);
    useEffect(() => { load(page); }, [page]); // eslint-disable-line

    const sel = { height: 32, padding: "0 8px", borderRadius: 8, border: "1px solid " + LINE, background: "#fff", color: INK, fontSize: 12.5 };
    const th  = { textAlign: "left", fontSize: 10.5, textTransform: "uppercase", letterSpacing: "0.05em", color: MUTE, fontWeight: 600, padding: "8px 10px", borderBottom: "1px solid " + LINE, whiteSpace: "nowrap" };
    const td  = { padding: "9px 10px", borderBottom: "1px solid #F0F3F7", fontSize: 12.5, color: INK, verticalAlign: "top" };

    return (
      <div style={{ maxWidth: 1360, margin: "0 auto" }}>
        {/* Filter bar */}
        <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap", marginBottom: 14 }}>
          <select value={fUser} onChange={e => setFUser(e.target.value)} style={sel}>
            <option value="">All users</option>
            {userOptions.map(u => <option key={u} value={u}>{u}</option>)}
          </select>
          <select value={fCat} onChange={e => setFCat(e.target.value)} style={sel}>
            <option value="">All categories</option>
            {CATEGORIES.map(c => <option key={c.key} value={c.key}>{c.label}</option>)}
          </select>
          <select value={fAct} onChange={e => setFAct(e.target.value)} style={sel}>
            <option value="">All actions</option>
            <option>Insert</option><option>Update</option><option>Delete</option><option>RPC</option>
          </select>
          <input type="date" value={fFrom} onChange={e => setFFrom(e.target.value)} style={sel} />
          <span style={{ color: MUTE, fontSize: 12 }}>to</span>
          <input type="date" value={fTo} onChange={e => setFTo(e.target.value)} style={sel} />
          {(fUser || fCat || fAct || fFrom || fTo) && (
            <button onClick={() => { setFUser(""); setFCat(""); setFAct(""); setFFrom(""); setFTo(""); }}
              style={{ ...sel, cursor: "pointer", color: INK2 }}>Clear</button>
          )}
          <div style={{ flex: 1 }} />
          <button onClick={() => load(page)} style={{ ...sel, cursor: "pointer", color: INK2 }}>Refresh</button>
        </div>

        {/* Explainer */}
        <div style={{ display: "flex", gap: 10, alignItems: "flex-start", padding: "10px 14px", background: "#F2F7FB", border: "1px solid #DCE8F2", borderRadius: 10, marginBottom: 14, fontSize: 12, color: INK2, lineHeight: 1.5 }}>
          <span>Every write in Vault is logged here automatically — edits, deletes, uploads, and write RPCs, stamped with the signed-in user. Bulk imports appear as one row with a row count. Reads are never logged. Entries older than 180 days are pruned automatically.</span>
        </div>

        {error && <div style={{ color: "#B0413E", padding: 16, background: "#FBEEEE", borderRadius: 10, marginBottom: 12, fontSize: 13 }}>{error}</div>}

        {loading ? (
          <div style={{ color: MUTE, padding: 40, textAlign: "center" }}>Loading…</div>
        ) : rows.length === 0 ? (
          <div style={{ color: MUTE, padding: 40, textAlign: "center" }}>No audit entries match these filters.</div>
        ) : (
          <div className="tbl-wrap" style={{ background: "#fff", border: "1px solid " + LINE, borderRadius: 12, overflow: "hidden" }}>
            <table style={{ width: "100%", borderCollapse: "collapse" }}>
              <thead><tr>
                <th style={th}>When</th>
                <th style={th}>User</th>
                <th style={th}>Action</th>
                <th style={th}>Target</th>
                <th style={th}>Category</th>
                <th style={{ ...th, textAlign: "right" }}>Rows</th>
                <th style={{ ...th, textAlign: "right" }}>Status</th>
                <th style={th}>Detail</th>
              </tr></thead>
              <tbody>
                {rows.map(r => {
                  const act = actionLabel(r);
                  const tint = ACTION_TINT[act] || ACTION_TINT.RPC;
                  const open = expanded === r.id;
                  const ok = r.status >= 200 && r.status < 300;
                  return (
                    <tr key={r.id} style={{ cursor: (r.summary || r.query) ? "pointer" : "default" }}
                        onClick={() => setExpanded(open ? null : r.id)}>
                      <td style={{ ...td, whiteSpace: "nowrap", color: INK2 }}>{fmtTs(r.ts)}</td>
                      <td style={{ ...td, whiteSpace: "nowrap" }}>{r.user_email}</td>
                      <td style={td}>
                        <span style={{ display: "inline-block", padding: "2px 8px", borderRadius: 999, fontSize: 11, fontWeight: 600, background: tint.bg, color: tint.fg }}>{act}</span>
                      </td>
                      <td style={{ ...td, fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 12 }}>{r.name}</td>
                      <td style={{ ...td, color: INK2 }}>{NAME_TO_CATEGORY[r.name] || "Other"}</td>
                      <td style={{ ...td, textAlign: "right", color: INK2 }}>{r.row_count ?? "—"}</td>
                      <td style={{ ...td, textAlign: "right", color: ok ? "#1F7A46" : "#B0413E", fontWeight: ok ? 400 : 600 }}>{r.status ?? "—"}</td>
                      <td style={{ ...td, color: MUTE, maxWidth: 380 }}>
                        {open ? (
                          <div style={{ whiteSpace: "pre-wrap", wordBreak: "break-all", fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11, color: INK2 }}>
                            {r.query ? "filters: " + r.query + "\n" : ""}{r.summary || ""}
                          </div>
                        ) : (
                          <span style={{ display: "block", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{r.summary || r.query || ""}</span>
                        )}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}

        {/* Pagination */}
        <div style={{ display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 12 }}>
          <button disabled={page === 0} onClick={() => setPage(p => Math.max(0, p - 1))}
            style={{ height: 32, padding: "0 12px", borderRadius: 8, border: "1px solid " + LINE, background: "#fff", color: page === 0 ? MUTE : INK2, cursor: page === 0 ? "default" : "pointer", fontSize: 12.5 }}>‹ Newer</button>
          <span style={{ alignSelf: "center", color: MUTE, fontSize: 12 }}>Page {page + 1}</span>
          <button disabled={!hasMore} onClick={() => setPage(p => p + 1)}
            style={{ height: 32, padding: "0 12px", borderRadius: 8, border: "1px solid " + LINE, background: "#fff", color: !hasMore ? MUTE : INK2, cursor: !hasMore ? "default" : "pointer", fontSize: 12.5 }}>Older ›</button>
        </div>
      </div>
    );
  }

  window.AuditLogScreen = AuditLogScreen;
})();
