// AdminAuditLog (Stage 11 · RBAC)
//
// Read-only viewer over admin_audit_log (migration 55) joined to admin_users
// for the actor identity. Filterable by admin, action type, date range, and a
// free-text search across target/details. Self-contained IIFE exposing
// window.AdminAuditLog; loaded before page-admin.jsx.

(function () {
  const { useState, useEffect, useMemo } = React;

  const ACTION_LABEL = {
    "admin.invited": "Invited admin user",
    "admin.promoted": "Promoted existing user",
    "admin.removed": "Removed admin",
    "admin.deactivated": "Deactivated admin",
    "admin.reactivated": "Reactivated admin",
    "admin.role_changed": "Changed admin role",
    "admin.invite_resent": "Resent invite",
    "company_access.granted": "Granted company access",
    "company_access.updated": "Updated company permissions",
    "company_access.revoked": "Revoked company access",
  };
  const labelFor = (a) => ACTION_LABEL[a] || (a || "").replace(/[._]/g, " ").replace(/\b\w/g, (m) => m.toUpperCase());

  function fmtTs(iso) {
    if (!iso) return "—";
    const d = new Date(iso);
    return d.toLocaleString(undefined, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
  }
  function detailText(r) {
    const d = r.details || {};
    if (r.action === "admin.invited" || r.action === "admin.promoted" || r.action === "admin.role_changed") {
      if (d.to) return `Role: ${d.from || "?"} → ${d.to}`;
      if (d.role) return `Role: ${d.role}`;
    }
    if ((r.action || "").startsWith("company_access")) {
      const ks = d.perms ? Object.keys(d.perms).filter((k) => d.perms[k]).map((k) => k.replace("can_", "").replace(/_/g, " ")) : [];
      return ks.length ? ks.join(", ") : "—";
    }
    const keys = Object.keys(d);
    return keys.length ? keys.map((k) => `${k}: ${typeof d[k] === "object" ? JSON.stringify(d[k]) : d[k]}`).join(" · ").slice(0, 120) : "—";
  }

  function AdminAuditLog() {
    const [rows, setRows] = useState(null);
    const [actors, setActors] = useState({});
    const [err, setErr] = useState(null);
    const [fAdmin, setFAdmin] = useState("all");
    const [fAction, setFAction] = useState("all");
    const [fRange, setFRange] = useState("30");
    const [search, setSearch] = useState("");

    useEffect(() => { load(); }, []);
    async function load() {
      const db = window.supabaseClient;
      if (!db) { setRows([]); return; }
      try {
        const [{ data: logs, error: e1 }, { data: admins }] = await Promise.all([
          db.from("admin_audit_log").select("id, admin_user_id, action, target_type, target_id, target_name, details, created_at").order("created_at", { ascending: false }).limit(1000),
          db.from("admin_users").select("id, email, full_name"),
        ]);
        if (e1) { setErr(e1.message); setRows([]); return; }
        const m = {};
        (admins || []).forEach((a) => { m[a.id] = a.full_name || a.email; });
        setActors(m);
        setRows(logs || []);
      } catch (e) { setErr(String(e.message || e)); setRows([]); }
    }

    const actionTypes = useMemo(() => Array.from(new Set((rows || []).map((r) => r.action))).sort(), [rows]);
    const adminList = useMemo(() => {
      const ids = Array.from(new Set((rows || []).map((r) => r.admin_user_id).filter(Boolean)));
      return ids.map((id) => ({ id, name: actors[id] || "Unknown" }));
    }, [rows, actors]);

    const filtered = useMemo(() => {
      if (!rows) return [];
      const now = Date.now();
      const cutoff = fRange === "all" ? 0 : now - Number(fRange) * 86400000;
      const q = search.trim().toLowerCase();
      return rows.filter((r) => {
        if (fAdmin !== "all" && r.admin_user_id !== fAdmin) return false;
        if (fAction !== "all" && r.action !== fAction) return false;
        if (cutoff && new Date(r.created_at).getTime() < cutoff) return false;
        if (q) {
          const hay = `${labelFor(r.action)} ${r.target_name || ""} ${detailText(r)} ${actors[r.admin_user_id] || ""}`.toLowerCase();
          if (!hay.includes(q)) return false;
        }
        return true;
      });
    }, [rows, fAdmin, fAction, fRange, search, actors]);

    return (
      <div className="pc-adm-section">
        <div className="pc-adm-section-header">
          <h2 className="pc-adm-section-title">Audit Log</h2>
          <div style={{ fontSize: 12, color: "var(--text-3)" }}>{filtered.length} of {(rows || []).length} entries</div>
        </div>

        {err && <div style={{ background: "rgba(220,38,38,0.08)", border: "1px solid rgba(220,38,38,0.25)", borderRadius: 8, padding: "10px 14px", fontSize: 12.5, color: "#b91c1c", marginBottom: 16 }}>Could not load audit log ({err}).</div>}

        <div className="pc-adm-filters" style={{ flexWrap: "wrap" }}>
          <input className="pc-adm-search" placeholder="Search action, target, details…" value={search} onChange={(e) => setSearch(e.target.value)} />
          <select className="pc-adm-input" style={{ minWidth: 150 }} value={fAdmin} onChange={(e) => setFAdmin(e.target.value)}>
            <option value="all">All admins</option>
            {adminList.map((a) => <option key={a.id} value={a.id}>{a.name}</option>)}
          </select>
          <select className="pc-adm-input" style={{ minWidth: 170 }} value={fAction} onChange={(e) => setFAction(e.target.value)}>
            <option value="all">All actions</option>
            {actionTypes.map((a) => <option key={a} value={a}>{labelFor(a)}</option>)}
          </select>
          <select className="pc-adm-input" style={{ minWidth: 130 }} value={fRange} onChange={(e) => setFRange(e.target.value)}>
            <option value="7">Last 7 days</option>
            <option value="30">Last 30 days</option>
            <option value="90">Last 90 days</option>
            <option value="all">All time</option>
          </select>
        </div>

        <div className="pc-adm-table-wrap">
          <table className="pc-adm-table">
            <thead><tr><th>Timestamp</th><th>Admin</th><th>Action</th><th>Target</th><th>Details</th></tr></thead>
            <tbody>
              {!rows && <tr><td colSpan={5} style={{ textAlign: "center", padding: 28, color: "var(--text-3)" }}>Loading audit log…</td></tr>}
              {rows && filtered.length === 0 && <tr><td colSpan={5} style={{ textAlign: "center", padding: 28, color: "var(--text-3)" }}>No matching audit entries.</td></tr>}
              {filtered.map((r) => (
                <tr key={r.id}>
                  <td style={{ paddingLeft: 14, fontSize: 12, color: "var(--text-2)", whiteSpace: "nowrap" }}>{fmtTs(r.created_at)}</td>
                  <td style={{ fontSize: 12.5, fontWeight: 600 }}>{actors[r.admin_user_id] || "System"}</td>
                  <td style={{ fontSize: 12.5 }}>{labelFor(r.action)}</td>
                  <td style={{ fontSize: 12.5, color: "var(--text-2)" }}>{r.target_name || (r.target_type ? r.target_type : "—")}</td>
                  <td style={{ fontSize: 11.5, color: "var(--text-3)" }}>{detailText(r)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    );
  }

  window.AdminAuditLog = AdminAuditLog;
})();
