/* Documents — the Documents tab of Search (attachments A4, 0147).
   Every document in Ledger: the Search box's text plus filters for the kind of record
   it hangs off, document type and document date; click a title to open it in Drive.
   Lacey's "Search / Browse Hub" ask (2026-10-06).

   It lives INSIDE Search (operator 2026-10-12): Search is the one place to find
   anything. It was briefly its own Content Ops page; reviewing the AI's proposals for
   backfilled documents is the Metadata desk's Documents tab, like every other proposal.

   attachment_browse() filters, counts and pages in Postgres with no relevance cap, and
   runs as the caller, so restricted (freelancer) documents only appear for Content Ops.
   Assigns window.LedgerDocumentsBrowse. */
(function () {
  const DS = window.LawCrimeDesignSystem_e18d68;
  const { Select, Button } = DS;
  const A = () => window.LedgerAPI.att;
  // Every icon sits in a span React owns, keyed on its name (the lucide/React crash).
  const Ic = ({ n }) => <span className="ic-wrap" key={n}><i data-lucide={n} /></span>;
  const icons = () => setTimeout(() => window.lucide && window.lucide.createIcons(), 30);
  const PAGE = 50;

  const RECORDS = [
    { value: "", label: "Any record" },
    { value: "matter", label: "Matters" },
    { value: "asset_request", label: "Asset requests" },
    { value: "asset_cost_event", label: "Request costs" },
    { value: "agency", label: "Agencies" },
    { value: "freelancer", label: "Freelancers" },
    { value: "booking", label: "Bookings" },
    { value: "courthouse", label: "Courthouses" },
  ];
  const RECORD_LABEL = { matter: "Matter", asset_request: "Asset request", asset_cost_event: "Request cost", agency: "Agency", freelancer: "Freelancer", booking: "Booking", courthouse: "Courthouse" };
  const RECORD_ICON = { matter: "folder-open", asset_request: "clipboard-list", asset_cost_event: "receipt", agency: "landmark", freelancer: "contact", booking: "calendar-check", courthouse: "building" };

  function fmtBytes(n) {
    if (!n && n !== 0) return "";
    if (n < 1024 * 1024) return `${Math.max(1, Math.round(n / 1024))} KB`;
    if (n < 1024 ** 3) return `${(n / 1024 / 1024).toFixed(n < 10 * 1024 * 1024 ? 1 : 0)} MB`;
    return `${(n / 1024 ** 3).toFixed(2)} GB`;
  }
  const fmtDate = (d) => (d ? window.LedgerTime.fmtDate(d) : "");

  /** The records a document is linked to. Anything with a matter behind it opens the matter. */
  function Links({ links, onOpenMatter }) {
    if (!links || !links.length) return <span className="fl-sub">Not linked</span>;
    return (
      <div className="doc-links">
        {links.map((l) => {
          const open = l.matter_id && onOpenMatter ? () => onOpenMatter(l.matter_id) : null;
          const label = l.label || RECORD_LABEL[l.entity_type];
          return open
            ? <button type="button" key={l.entity_type + l.entity_id} className="doc-link doc-link--go" title={`${RECORD_LABEL[l.entity_type]}: open the matter`} onClick={open}>
                <Ic n={RECORD_ICON[l.entity_type]} />{label}</button>
            : <span key={l.entity_type + l.entity_id} className="doc-link" title={RECORD_LABEL[l.entity_type]}>
                <Ic n={RECORD_ICON[l.entity_type]} />{label}</span>;
        })}
      </div>
    );
  }

  /** q comes from the Search box. */
  function DocumentsBrowse({ q = "", onOpenMatter }) {
    const [term, setTerm] = React.useState(q);            // q, debounced
    const [entityType, setEntityType] = React.useState("");
    const [docType, setDocType] = React.useState("");
    const [dateFrom, setDateFrom] = React.useState("");
    const [dateTo, setDateTo] = React.useState("");
    const [sort, setSort] = React.useState("date");
    const [page, setPage] = React.useState(0);
    const [res, setRes] = React.useState(null);           // {rows, total}
    const [types, setTypes] = React.useState([]);
    const [busy, setBusy] = React.useState(false);
    const [err, setErr] = React.useState(null);

    React.useEffect(() => { A().browseTypes().then(setTypes).catch(() => {}); }, []);
    React.useEffect(() => { const t = setTimeout(() => setTerm(q), 250); return () => clearTimeout(t); }, [q]);
    // Any change to the question restarts at the first page.
    React.useEffect(() => { setPage(0); }, [term, entityType, docType, dateFrom, dateTo, sort]);

    const load = React.useCallback(async () => {
      setBusy(true); setErr(null);
      try {
        const r = await A().browse({ q: term, entityType, docType, dateFrom, dateTo, sort, page, pageSize: PAGE });
        setRes(r);
      } catch (e) { setErr(e.message || String(e)); setRes({ rows: [], total: 0 }); }
      finally { setBusy(false); }
    }, [term, entityType, docType, dateFrom, dateTo, sort, page]);
    React.useEffect(() => { load(); }, [load]);
    React.useEffect(() => { icons(); });

    // Grouped by record type, because "Other" is in every list and means a different thing in each.
    const typeOpts = [{ value: "", label: "Any document type" }].concat(
      types.filter((t) => !entityType || t.doc_entity_type === entityType)
        .map((t) => ({ value: `${t.doc_entity_type}:${t.doc_type_key}`,
                       label: `${entityType ? "" : RECORD_LABEL[t.doc_entity_type] + " · "}${t.label} (${Number(t.n).toLocaleString()})` })));
    React.useEffect(() => { if (docType && entityType && !docType.startsWith(entityType + ":")) setDocType(""); }, [entityType]);

    const rows = (res && res.rows) || [];
    const total = (res && res.total) || 0;
    const filtered = !!(entityType || docType || dateFrom || dateTo);
    const clear = () => { setEntityType(""); setDocType(""); setDateFrom(""); setDateTo(""); };

    return (
      <div className="doc-browse">
        <div className="fl-filters doc-filters">
          <Select value={entityType} onChange={(e) => setEntityType(e.target.value)} options={RECORDS} />
          <Select value={docType} onChange={(e) => setDocType(e.target.value)} options={typeOpts} />
          <label className="doc-date">From <input className="lc-input" type="date" value={dateFrom} onChange={(e) => setDateFrom(e.target.value)} /></label>
          <label className="doc-date">To <input className="lc-input" type="date" value={dateTo} onChange={(e) => setDateTo(e.target.value)} /></label>
        </div>
        <div className="fl-toggles">
          <span className="fl-count">{res ? `${total.toLocaleString()} document${total === 1 ? "" : "s"}` : ""}
            {term.trim() ? <> matching “{term.trim()}”</> : null}{busy && res ? " · loading…" : ""}</span>
          {filtered && <button type="button" className="link-btn" onClick={clear}>Clear filters</button>}
          <span style={{ flex: 1 }} />
          <span className="fl-viewsw">
            <button type="button" className={"tagopt" + (sort === "date" ? " tagopt--on" : "")} onClick={() => setSort("date")}>Document date</button>
            <button type="button" className={"tagopt" + (sort === "added" ? " tagopt--on" : "")} onClick={() => setSort("added")}>Recently added</button>
          </span>
        </div>

        {err && <div className="login__err" style={{ marginBottom: 12 }}>{err}</div>}

        <DS.Card><DS.Card.Body style={{ padding: 0 }}>
          <div className="opsq-table-wrap">
            <table className="opsq-table doc-table">
              <thead><tr><th>Type</th><th>Document</th><th>Linked to</th><th>Date</th><th className="doc-num">Size</th></tr></thead>
              <tbody>
                {res === null ? <tr><td colSpan={5} className="fl-sub">Loading…</td></tr>
                  : rows.length === 0 ? (
                    <tr><td colSpan={5}><div className="ledger-empty"><Ic n="file-search" /><b>No documents</b>
                      <span>Nothing matches. Remove a filter or change the search.</span></div></td></tr>
                  ) : rows.map((r) => (
                    <tr key={r.id} className="doc-row">
                      <td>
                        <span className="att-type">{r.doc_type_label || r.doc_type_key}</span>
                        {r.sensitivity === "restricted" && <div className="doc-restr" title="Restricted drive: Content Ops only"><Ic n="lock" /> Restricted</div>}
                      </td>
                      <td className="doc-main">
                        <a href={r.drive_url} target="_blank" rel="noopener noreferrer" className="att-title">{r.title || r.file_name} <Ic n="external-link" /></a>
                        {r.title && r.title !== r.file_name && <div className="att-sub">{r.file_name}</div>}
                        {(r.case_number || r.court) && <div className="att-sub">{[r.case_number, r.court].filter(Boolean).join(" · ")}</div>}
                      </td>
                      <td><Links links={r.links} onOpenMatter={onOpenMatter} /></td>
                      <td className="doc-when">
                        {r.document_date ? fmtDate(r.document_date) : <span className="fl-sub">No date</span>}
                        <div className="fl-sub" title={r.uploaded_by_name ? `Added by ${r.uploaded_by_name}` : "Added"}>Added {fmtDate(r.uploaded_at)}</div>
                      </td>
                      <td className="doc-num fl-sub">{fmtBytes(r.size_bytes)}</td>
                    </tr>
                  ))}
              </tbody>
            </table>
          </div>
          {total > PAGE && (
            <div className="pager pager--incard">
              <span className="pager__count">{page * PAGE + 1}–{Math.min((page + 1) * PAGE, total)} of {total.toLocaleString()}</span>
              <span className="pager__nav">
                <Button variant="ghost" icon="chevron-left" disabled={page === 0 || busy} onClick={() => setPage((p) => Math.max(0, p - 1))}>Previous</Button>
                <Button variant="ghost" disabled={(page + 1) * PAGE >= total || busy} onClick={() => setPage((p) => p + 1)}>Next</Button>
              </span>
            </div>
          )}
        </DS.Card.Body></DS.Card>
      </div>
    );
  }

  window.LedgerDocumentsBrowse = DocumentsBrowse;
})();
