/* =============================================================
   CoreIQ Office — Legacy archive retrieval (LIVE · legacy archive)

   Read-only back-office views over the Z (APSS) 7-year retention archive
   (z_archive.*, non-synced). Lets staff / an auditor pull up a historical
   receipt, a supplier tax invoice, an account statement, or a stock movement
   trail. Every figure is queried live from Aurora via /archive/*.
   ============================================================= */
const { useState: aUseState, useEffect: aUseEffect, useCallback: aUseCallback } = React;

const aMoney = (c) => "$" + (Number(c || 0) / 100).toLocaleString("en-AU", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const aNum = (n) => Number(n || 0).toLocaleString("en-AU");
const aDate = (s) => (s ? String(s).slice(0, 10) : "—");
const aDateTime = (s) => (s ? String(s).replace("T", " ").slice(0, 16) : "—");
const aHuman = (s) => String(s || "").replace(/_/g, " ");

// Generic list fetch hook: re-runs when `key` changes, exposes data/loading/err.
function useArchive(fetcher, key) {
  const [data, setData] = aUseState(null);
  const [loading, setLoading] = aUseState(true);
  const [err, setErr] = aUseState(null);
  aUseEffect(() => {
    let alive = true;
    setLoading(true); setErr(null);
    Promise.resolve(fetcher())
      .then((d) => { if (alive) { setData(d); setLoading(false); } })
      .catch((e) => { if (alive) { setErr(String((e && e.message) || e)); setLoading(false); } });
    return () => { alive = false; };
  }, [key]);
  return { data, loading, err };
}

function AHeader({ eyebrow, title, actions, back }) {
  return (
    <header className="off-screen-header">
      <div className="off-screen-header-meta">
        <span className="off-screen-eyebrow">{back ? <>{back} · </> : null}{eyebrow}</span>
        <h2 className="off-screen-title">{title}</h2>
      </div>
      {actions ? <div className="off-screen-actions">{actions}</div> : null}
    </header>
  );
}
function ABackBtn({ onClick }) {
  return <button className="btn btn--ghost btn--sm" style={{padding:0, height:"auto", fontSize:"var(--fs-12)"}} onClick={onClick}>‹ Back</button>;
}
function AErr({ err }) {
  return <div className="off-card" style={{borderColor:"var(--void-border)", background:"var(--void-bg)", color:"var(--void-text)", padding:"12px 16px", flexDirection:"row", alignItems:"center", gap:10}}><window.OIcon name="alert"/> <span>{err}</span></div>;
}
function AEmpty({ children }) {
  return <div style={{padding:"16px 4px", fontSize:"var(--fs-13)", color:"var(--text-subtle)"}}>{children}</div>;
}
function APager({ total, limit, offset, onPage }) {
  if (!total) return null;
  const from = offset + 1, to = Math.min(offset + limit, total);
  return (
    <div style={{display:"flex", alignItems:"center", justifyContent:"space-between", padding:"12px 2px", fontSize:"var(--fs-12)", color:"var(--text-subtle)"}}>
      <span>Showing {aNum(from)}–{aNum(to)} of {aNum(total)}</span>
      <div style={{display:"flex", gap:8}}>
        <button className="btn btn--secondary btn--sm" disabled={offset <= 0} onClick={() => onPage(Math.max(0, offset - limit))}>‹ Prev</button>
        <button className="btn btn--secondary btn--sm" disabled={to >= total} onClick={() => onPage(offset + limit)}>Next ›</button>
      </div>
    </div>
  );
}
function ASearch({ value, onChange, placeholder, extra }) {
  return (
    <div className="off-card" style={{flexDirection:"row", alignItems:"center", gap:10, padding:"10px 12px", marginBottom:14}}>
      <window.OIcon name="search" style={{color:"var(--text-subtle)"}}/>
      <input className="input" value={value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} style={{flex:1, height:34, border:"none", background:"transparent", padding:0}}/>
      {extra}
    </div>
  );
}

// Clickable column header → server-side sort. `num` right-aligns + defaults desc.
function SortHead({ label, col, sort, onSort, num, def }) {
  const active = sort.col === col;
  return (
    <div className="off-grid-headcell" onClick={() => onSort(col, def || (num ? "desc" : "asc"))} title="Sort"
      style={Object.assign({ cursor: "pointer", userSelect: "none" }, num ? { justifyContent: "flex-end" } : {})}>
      {label}{active ? (sort.dir === "asc" ? " ↑" : " ↓") : ""}
    </div>
  );
}
const nextSort = (sort, col, def) => (sort.col === col ? { col, dir: sort.dir === "asc" ? "desc" : "asc" } : { col, dir: def || "asc" });

// -----------------------------------------------------------------
// 1) SALES HISTORY — receipts → lines + tenders + EFTPOS detail
// -----------------------------------------------------------------
function ArchiveSales() {
  const [q, setQ] = aUseState("");
  const [from, setFrom] = aUseState("");
  const [to, setTo] = aUseState("");
  const [offset, setOffset] = aUseState(0);
  const [applied, setApplied] = aUseState({ q: "", from: "", to: "", offset: 0 });
  const [sel, setSel] = aUseState(null);
  const [sort, setSort] = aUseState({ col: "date", dir: "desc" });
  const onSort = (c, d) => { setOffset(0); setSort((s) => nextSort(s, c, d)); };

  aUseEffect(() => { setApplied({ q, from, to, offset }); }, [offset]);
  const apply = () => { setOffset(0); setApplied({ q, from, to, offset: 0 }); };
  const key = JSON.stringify(applied) + "|" + sort.col + sort.dir;
  const { data, loading, err } = useArchive(
    () => window.OfficeAPI.archiveSales({ limit: 50, offset: applied.offset, sort: sort.col, dir: sort.dir, ...(applied.q ? { q: applied.q } : {}), ...(applied.from ? { from: applied.from } : {}), ...(applied.to ? { to: applied.to } : {}) }),
    key,
  );

  if (sel) return <ArchiveSaleDetail id={sel} onBack={() => setSel(null)}/>;

  return (
    <div className="off-screen">
      <AHeader eyebrow="live from Aurora" title="Sales history"/>
      <div className="off-screen-body">
        <ASearch value={q} onChange={setQ} placeholder="Receipt number or customer name…"
          extra={<>
            <input className="input" type="date" value={from} onChange={(e) => setFrom(e.target.value)} style={{height:34, width:150}} title="From"/>
            <span style={{color:"var(--text-subtle)"}}>→</span>
            <input className="input" type="date" value={to} onChange={(e) => setTo(e.target.value)} style={{height:34, width:150}} title="To"/>
            <button className="btn btn--primary btn--sm" onClick={apply}>Search</button>
          </>}/>
        {err && <AErr err={"Couldn't load sales: " + err}/>}
        <div className="off-card">
          <div className="off-card-header">
            <h3 className="off-card-title">Receipts</h3>
            <div className="off-card-meta">{loading ? "loading…" : aNum(data?.total) + " matching · newest first"}</div>
          </div>
          {!loading && data && data.items.length === 0 && <AEmpty>No receipts match.</AEmpty>}
          {data && data.items.length > 0 && (
            <div className="off-grid" style={{gridTemplateColumns:"150px 120px minmax(160px,1.3fr) 100px 110px"}}>
              <SortHead label="Date" col="date" sort={sort} onSort={onSort}/>
              <SortHead label="Receipt #" col="number" sort={sort} onSort={onSort}/>
              <SortHead label="Customer" col="customer" sort={sort} onSort={onSort}/>
              <SortHead label="Status" col="status" sort={sort} onSort={onSort}/>
              <SortHead label="Total" col="total" sort={sort} onSort={onSort} num/>
              {data.items.map((r) => (
                <div key={r.id} className="off-grid-row" style={{cursor:"pointer"}} onClick={() => setSel(r.id)}>
                  <div className="off-grid-cell off-cell-mono" style={{fontSize:"var(--fs-12)"}}>{aDateTime(r.date)}</div>
                  <div className="off-grid-cell off-cell-mono off-cell-strong">{r.number}</div>
                  <div className="off-grid-cell off-muted" style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{r.customerName || "—"}</div>
                  <div className="off-grid-cell">{r.status === "voided" ? <span style={{color:"var(--void)", fontWeight:600}}>voided</span> : r.status}</div>
                  <div className="off-grid-cell off-cell-num off-cell-strong">{aMoney(r.totalCents)}</div>
                </div>
              ))}
            </div>
          )}
          {data && <APager total={data.total} limit={data.limit} offset={data.offset} onPage={setOffset}/>}
        </div>
      </div>
    </div>
  );
}

function ArchiveSaleDetail({ id, onBack }) {
  const { data, loading, err } = useArchive(() => window.OfficeAPI.archiveSale(id), id);
  const [showCard, setShowCard] = aUseState(false);
  if (loading) return <div className="off-screen"><AHeader back={<ABackBtn onClick={onBack}/>} eyebrow="loading…" title="Receipt"/></div>;
  if (err || !data) return <div className="off-screen"><AHeader back={<ABackBtn onClick={onBack}/>} eyebrow="error" title="Receipt"/><div className="off-screen-body"><AErr err={err || "not found"}/></div></div>;
  const t = data.transaction;
  return (
    <div className="off-screen">
      <AHeader back={<ABackBtn onClick={onBack}/>} eyebrow={`${aDateTime(t.date)}${t.customerName ? " · " + t.customerName : ""}`} title={"Receipt #" + t.number}/>
      <div className="off-screen-body">
        <div className="off-kpi-grid">
          <KpiCard label="Total" value={aMoney(t.totalCents)} delta={{ text: t.status === "voided" ? "VOIDED" : "completed" }}/>
          <KpiCard label="GST" value={aMoney(t.taxCents)} delta={{ text: "incl. in total" }}/>
          <KpiCard label="Lines" value={aNum(data.lines.length)} delta={{ text: "items sold" }}/>
          <KpiCard label="Tenders" value={aNum(data.tenders.length)} delta={{ text: data.cards.length ? data.cards.length + " card auth" : "—" }}/>
        </div>
        <div className="off-card" style={{marginTop:16}}>
          <div className="off-card-header"><h3 className="off-card-title">Lines</h3></div>
          <div className="off-grid" style={{gridTemplateColumns:"minmax(180px,1.6fr) 70px 110px 110px 120px"}}>
            <div className="off-grid-headcell">Item</div>
            <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>Qty</div>
            <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>Unit</div>
            <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>PBS subsidy</div>
            <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>Line total</div>
            {data.lines.map((l) => (
              <div key={l.id} className="off-grid-row">
                <div className="off-grid-cell off-cell-strong" style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{l.name || l.sku || "—"}{l.status === "C" ? <span style={{color:"var(--void)", marginLeft:6, fontSize:"var(--fs-11)"}}>cancelled</span> : null}</div>
                <div className="off-grid-cell off-cell-num" style={{color: l.quantity < 0 ? "var(--void)" : "inherit"}}>{l.quantity}</div>
                <div className="off-grid-cell off-cell-num off-muted">{aMoney(l.unitPriceCents)}</div>
                <div className="off-grid-cell off-cell-num off-muted">{l.govtContributionCents ? aMoney(l.govtContributionCents) : "—"}</div>
                <div className="off-grid-cell off-cell-num off-cell-strong">{aMoney(l.lineTotalCents)}</div>
              </div>
            ))}
          </div>
        </div>
        <div className="dash-grid" style={{marginTop:16}}>
          <div className="off-card">
            <div className="off-card-header"><h3 className="off-card-title">Tenders</h3></div>
            {data.tenders.length === 0 && <AEmpty>No tender lines.</AEmpty>}
            {data.tenders.map((t2) => (
              <div key={t2.id} className="alert-row" style={{cursor:"default"}}>
                <div style={{flex:1, fontSize:"var(--fs-13)", textTransform:"capitalize"}}>{aHuman(t2.type)}{t2.accountId ? <span style={{color:"var(--text-subtle)", fontSize:"var(--fs-11)", marginLeft:6}}>· on account</span> : null}</div>
                <div style={{fontWeight:600, fontVariantNumeric:"tabular-nums", color: t2.amountCents < 0 ? "var(--void)" : "inherit"}}>{aMoney(t2.amountCents)}</div>
              </div>
            ))}
          </div>
          <div className="off-card">
            <div className="off-card-header"><h3 className="off-card-title">Card / EFTPOS</h3>{data.cards.length ? <button className="btn btn--ghost btn--sm" onClick={() => setShowCard((v) => !v)}>{showCard ? "Hide" : "Show"} receipt</button> : null}</div>
            {data.cards.length === 0 && <AEmpty>No card-present auth on this sale.</AEmpty>}
            {data.cards.map((c) => (
              <div key={c.id} style={{marginBottom:8}}>
                <div className="alert-row" style={{cursor:"default"}}>
                  <div style={{flex:1, fontSize:"var(--fs-12)", color:"var(--text-subtle)"}}>Sale ref</div>
                  <div style={{fontFamily:"var(--font-mono)", fontSize:"var(--fs-12)"}}>{c.saleReference}</div>
                </div>
                {showCard && c.merchantReceipt && (
                  <pre style={{whiteSpace:"pre-wrap", fontFamily:"var(--font-mono)", fontSize:"var(--fs-11)", background:"var(--bg-subtle)", padding:"10px 12px", borderRadius:8, margin:"6px 0 0", maxHeight:260, overflow:"auto", color:"var(--text)"}}>{c.merchantReceipt}</pre>
                )}
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// -----------------------------------------------------------------
// 2) PURCHASING — wholesaler tax invoices + purchase orders
// -----------------------------------------------------------------
function ArchivePurchasing() {
  const [tab, setTab] = aUseState("invoices");
  const [q, setQ] = aUseState("");
  const [applied, setApplied] = aUseState("");
  const [offset, setOffset] = aUseState(0);
  const [sel, setSel] = aUseState(null);
  const [sort, setSort] = aUseState({ col: "date", dir: "desc" });
  const onSort = (c, d) => { setOffset(0); setSort((s) => nextSort(s, c, d)); };
  aUseEffect(() => { setOffset(0); setSel(null); setSort({ col: "date", dir: "desc" }); }, [tab]);
  const key = tab + "|" + applied + "|" + offset + "|" + sort.col + sort.dir;
  const { data, loading, err } = useArchive(
    () => (tab === "invoices"
      ? window.OfficeAPI.archiveInvoices({ limit: 50, offset, sort: sort.col, dir: sort.dir, ...(applied ? { q: applied } : {}) })
      : window.OfficeAPI.archivePurchaseOrders({ limit: 50, offset, sort: sort.col, dir: sort.dir, ...(applied ? { q: applied } : {}) })),
    key,
  );
  if (sel) return <ArchiveInvoiceDetail id={sel} onBack={() => setSel(null)}/>;
  const supName = (it) => it.supplierName || (it.notes ? String(it.notes).split(" / ")[0] : null) || "—";

  return (
    <div className="off-screen">
      <AHeader eyebrow="live from Aurora" title="Wholesaler invoices & orders"/>
      <div className="off-screen-body">
        <div className="tabset" style={{marginBottom:14}}>
          <button className="tabset-item" aria-selected={tab === "invoices"} onClick={() => setTab("invoices")}>Tax invoices</button>
          <button className="tabset-item" aria-selected={tab === "orders"} onClick={() => setTab("orders")}>Purchase orders</button>
        </div>
        <ASearch value={q} onChange={setQ} placeholder={tab === "invoices" ? "Invoice number or supplier…" : "Order number or invoice ref…"}
          extra={<button className="btn btn--primary btn--sm" onClick={() => { setOffset(0); setApplied(q); }}>Search</button>}/>
        {err && <AErr err={"Couldn't load: " + err}/>}
        <div className="off-card">
          <div className="off-card-header">
            <h3 className="off-card-title">{tab === "invoices" ? "Supplier tax invoices" : "Purchase orders"}</h3>
            <div className="off-card-meta">{loading ? "loading…" : aNum(data?.total) + " total · newest first"}</div>
          </div>
          {!loading && data && data.items.length === 0 && <AEmpty>Nothing matches.</AEmpty>}
          {tab === "invoices" && data && data.items.length > 0 && (
            <div className="off-grid" style={{gridTemplateColumns:"120px 140px minmax(150px,1.2fr) 100px 90px 110px"}}>
              <SortHead label="Date" col="date" sort={sort} onSort={onSort}/>
              <SortHead label="Invoice #" col="number" sort={sort} onSort={onSort}/>
              <SortHead label="Supplier" col="supplier" sort={sort} onSort={onSort}/>
              <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>Ex-GST</div>
              <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>GST</div>
              <SortHead label="Total" col="total" sort={sort} onSort={onSort} num/>
              {data.items.map((r) => (
                <div key={r.id} className="off-grid-row" style={{cursor:"pointer"}} onClick={() => setSel(r.id)}>
                  <div className="off-grid-cell off-cell-mono" style={{fontSize:"var(--fs-12)"}}>{aDate(r.date)}</div>
                  <div className="off-grid-cell off-cell-mono off-cell-strong">{r.number || "—"}</div>
                  <div className="off-grid-cell off-muted" style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{supName(r)}</div>
                  <div className="off-grid-cell off-cell-num">{aMoney(r.subtotalCents)}</div>
                  <div className="off-grid-cell off-cell-num off-muted">{aMoney(r.gstCents)}</div>
                  <div className="off-grid-cell off-cell-num off-cell-strong">{aMoney(r.totalCents)}</div>
                </div>
              ))}
            </div>
          )}
          {tab === "orders" && data && data.items.length > 0 && (
            <div className="off-grid" style={{gridTemplateColumns:"120px 130px minmax(150px,1.3fr) 110px 120px"}}>
              <SortHead label="Date" col="date" sort={sort} onSort={onSort}/>
              <SortHead label="Order #" col="number" sort={sort} onSort={onSort}/>
              <SortHead label="Supplier" col="supplier" sort={sort} onSort={onSort}/>
              <div className="off-grid-headcell">Source</div>
              <SortHead label="Status" col="status" sort={sort} onSort={onSort}/>
              {data.items.map((r) => (
                <div key={r.id} className="off-grid-row">
                  <div className="off-grid-cell off-cell-mono" style={{fontSize:"var(--fs-12)"}}>{aDate(r.date)}</div>
                  <div className="off-grid-cell off-cell-mono off-cell-strong">{r.number}</div>
                  <div className="off-grid-cell off-muted" style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{r.supplierName || "—"}</div>
                  <div className="off-grid-cell">{r.sourceType === "pharmx" ? <span style={{color:"var(--brand)"}}>PharmX</span> : aHuman(r.sourceType)}</div>
                  <div className="off-grid-cell off-muted">{aHuman(r.status)}</div>
                </div>
              ))}
            </div>
          )}
          {data && <APager total={data.total} limit={data.limit} offset={data.offset} onPage={setOffset}/>}
        </div>
      </div>
    </div>
  );
}

function ArchiveInvoiceDetail({ id, onBack }) {
  const { data, loading, err } = useArchive(() => window.OfficeAPI.archiveInvoice(id), id);
  if (loading) return <div className="off-screen"><AHeader back={<ABackBtn onClick={onBack}/>} eyebrow="loading…" title="Invoice"/></div>;
  if (err || !data) return <div className="off-screen"><AHeader back={<ABackBtn onClick={onBack}/>} eyebrow="error" title="Invoice"/><div className="off-screen-body"><AErr err={err || "not found"}/></div></div>;
  const i = data.invoice;
  const sup = i.supplierName || (i.notes ? String(i.notes).split(" / ")[0] : "—");
  return (
    <div className="off-screen">
      <AHeader back={<ABackBtn onClick={onBack}/>} eyebrow={`${aDate(i.date)} · ${sup}`} title={"Invoice #" + (i.number || "—")}/>
      <div className="off-screen-body">
        <div className="off-kpi-grid">
          <KpiCard label="Ex-GST" value={aMoney(i.subtotalCents)} delta={{ text: "net of tax" }}/>
          <KpiCard label="GST" value={aMoney(i.gstCents)} delta={{ text: "10%" }}/>
          <KpiCard label="Total inc-GST" value={aMoney(i.totalCents)} delta={{ dir: "up", text: "tax invoice" }}/>
          <KpiCard label="Lines" value={aNum(data.lines.length)} delta={{ text: i.status || "received" }}/>
        </div>
        <div className="off-card" style={{marginTop:16}}>
          <div className="off-card-header"><h3 className="off-card-title">Invoice lines</h3><div className="off-card-meta">{i.notes}</div></div>
          <div className="off-grid" style={{gridTemplateColumns:"minmax(180px,1.6fr) 110px 70px 110px 110px"}}>
            <div className="off-grid-headcell">Description</div>
            <div className="off-grid-headcell">Supplier code</div>
            <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>Qty</div>
            <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>Unit cost</div>
            <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>Line ex-GST</div>
            {data.lines.map((l) => (
              <div key={l.id} className="off-grid-row">
                <div className="off-grid-cell off-cell-strong" style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{l.name || l.sku || "—"}</div>
                <div className="off-grid-cell off-cell-mono off-muted">{l.supplierCode || "—"}</div>
                <div className="off-grid-cell off-cell-num">{l.quantity}</div>
                <div className="off-grid-cell off-cell-num off-muted">{aMoney(l.unitCostCents)}</div>
                <div className="off-grid-cell off-cell-num off-cell-strong">{aMoney(l.lineTotalCents)}</div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// -----------------------------------------------------------------
// 3) ACCOUNT STATEMENTS — A/R ledger per debtor
// -----------------------------------------------------------------
const AR_TYPE = { I: "Charge", P: "Payment", C: "Credit", A: "Adjustment", S: "Statement", D: "Discount", Z: "Migrated" };
function ArchiveAccounts() {
  const [q, setQ] = aUseState("");
  const [applied, setApplied] = aUseState("");
  const [offset, setOffset] = aUseState(0);
  const [sel, setSel] = aUseState(null);
  const [sort, setSort] = aUseState({ col: "entries", dir: "desc" });
  const onSort = (c, d) => { setOffset(0); setSort((s) => nextSort(s, c, d)); };
  const key = applied + "|" + offset + "|" + sort.col + sort.dir;
  const { data, loading, err } = useArchive(() => window.OfficeAPI.archiveAccounts({ limit: 50, offset, sort: sort.col, dir: sort.dir, ...(applied ? { q: applied } : {}) }), key);
  if (sel) return <ArchiveStatement id={sel} name={sel._name} onBack={() => setSel(null)}/>;
  return (
    <div className="off-screen">
      <AHeader eyebrow="live from Aurora" title="Account statements"/>
      <div className="off-screen-body">
        <ASearch value={q} onChange={setQ} placeholder="Account number or customer name…"
          extra={<button className="btn btn--primary btn--sm" onClick={() => { setOffset(0); setApplied(q); }}>Search</button>}/>
        {err && <AErr err={"Couldn't load accounts: " + err}/>}
        <div className="off-card">
          <div className="off-card-header">
            <h3 className="off-card-title">Debtor accounts</h3>
            <div className="off-card-meta">{loading ? "loading…" : aNum(data?.total) + " accounts · most active first"}</div>
          </div>
          {!loading && data && data.items.length === 0 && <AEmpty>No accounts match.</AEmpty>}
          {data && data.items.length > 0 && (
            <div className="off-grid" style={{gridTemplateColumns:"100px minmax(160px,1.4fr) 110px 110px 110px"}}>
              <SortHead label="Account #" col="account" sort={sort} onSort={onSort}/>
              <SortHead label="Customer" col="customer" sort={sort} onSort={onSort}/>
              <SortHead label="Balance" col="balance" sort={sort} onSort={onSort} num/>
              <SortHead label="Ledger rows" col="entries" sort={sort} onSort={onSort} num/>
              <SortHead label="Last activity" col="activity" sort={sort} onSort={onSort}/>
              {data.items.map((r) => (
                <div key={r.id} className="off-grid-row" style={{cursor:"pointer"}} onClick={() => { const o = new String(r.id); o._name = r.customerName; setSel(o); }}>
                  <div className="off-grid-cell off-cell-mono off-cell-strong">{r.accountNumber || "—"}</div>
                  <div className="off-grid-cell" style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{r.customerName || "—"}</div>
                  <div className="off-grid-cell off-cell-num off-cell-strong" style={{color: r.balanceCents > 0 ? "var(--void-text)" : "inherit"}}>{aMoney(r.balanceCents)}</div>
                  <div className="off-grid-cell off-cell-num off-muted">{aNum(r.entries)}</div>
                  <div className="off-grid-cell off-cell-mono off-muted" style={{fontSize:"var(--fs-12)"}}>{aDate(r.lastActivity)}</div>
                </div>
              ))}
            </div>
          )}
          {data && <APager total={data.total} limit={data.limit} offset={data.offset} onPage={setOffset}/>}
        </div>
      </div>
    </div>
  );
}

function ArchiveStatement({ id, name, onBack }) {
  const [from, setFrom] = aUseState("");
  const [to, setTo] = aUseState("");
  const [applied, setApplied] = aUseState({ from: "", to: "" });
  const key = String(id) + "|" + JSON.stringify(applied);
  const { data, loading, err } = useArchive(
    () => window.OfficeAPI.archiveAccountLedger(String(id), { ...(applied.from ? { from: applied.from } : {}), ...(applied.to ? { to: applied.to } : {}) }),
    key,
  );
  if (loading) return <div className="off-screen"><AHeader back={<ABackBtn onClick={onBack}/>} eyebrow="loading…" title={String(name || "Account")}/></div>;
  if (err || !data) return <div className="off-screen"><AHeader back={<ABackBtn onClick={onBack}/>} eyebrow="error" title="Account"/><div className="off-screen-body"><AErr err={err || "not found"}/></div></div>;
  const a = data.account;
  return (
    <div className="off-screen">
      <AHeader back={<ABackBtn onClick={onBack}/>} eyebrow={`account ${a.accountNumber || ""}`} title={a.customerName || "Account"}/>
      <div className="off-screen-body">
        <div className="off-kpi-grid">
          <KpiCard label="Current balance" value={aMoney(a.balanceCents)} delta={{ text: a.balanceCents > 0 ? "owing" : "clear" }}/>
          <KpiCard label="30 days" value={aMoney(a.aged.m30)} delta={{ text: "aged" }}/>
          <KpiCard label="60 days" value={aMoney(a.aged.m60)} delta={{ text: "aged" }}/>
          <KpiCard label="90+ days" value={aMoney(a.aged.m90)} delta={{ text: "aged" }}/>
        </div>
        <div className="off-card" style={{marginTop:16}}>
          <div className="off-card-header">
            <h3 className="off-card-title">Statement · ledger</h3>
            <div style={{display:"flex", gap:8, alignItems:"center"}}>
              <input className="input" type="date" value={from} onChange={(e) => setFrom(e.target.value)} style={{height:30, width:140}}/>
              <span style={{color:"var(--text-subtle)"}}>→</span>
              <input className="input" type="date" value={to} onChange={(e) => setTo(e.target.value)} style={{height:30, width:140}}/>
              <button className="btn btn--secondary btn--sm" onClick={() => setApplied({ from, to })}>Apply</button>
            </div>
          </div>
          {data.entries.length === 0 && <AEmpty>No ledger entries in this window.</AEmpty>}
          {data.entries.length > 0 && (
            <div className="off-grid" style={{gridTemplateColumns:"110px 100px minmax(180px,1.6fr) 110px 120px"}}>
              <div className="off-grid-headcell">Date</div>
              <div className="off-grid-headcell">Type</div>
              <div className="off-grid-headcell">Narration</div>
              <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>Amount</div>
              <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>Balance</div>
              {data.entries.map((e) => (
                <div key={e.id} className="off-grid-row" style={{opacity: e.hideOnStatement ? 0.5 : 1}}>
                  <div className="off-grid-cell off-cell-mono" style={{fontSize:"var(--fs-12)"}}>{aDate(e.date)}</div>
                  <div className="off-grid-cell">{AR_TYPE[e.type] || e.type}</div>
                  <div className="off-grid-cell off-muted" style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap"}}>{e.narration || "—"}</div>
                  <div className="off-grid-cell off-cell-num off-cell-strong" style={{color: e.amountCents < 0 ? "var(--paid-text)" : "inherit"}}>{aMoney(e.amountCents)}</div>
                  <div className="off-grid-cell off-cell-num off-cell-mono" style={{fontSize:"var(--fs-12)"}}>{aMoney(e.runningBalanceCents)}</div>
                </div>
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// -----------------------------------------------------------------
// 4) STOCK MOVEMENT HISTORY — full legacy trail incl. S8 controlled-drug
// -----------------------------------------------------------------
const MOVE_TYPES = ["", "sale", "dispense", "receive_invoice", "adjustment", "refund", "transfer", "order"];
function ArchiveStock() {
  const { setScreenState, setScreen } = window.useOffice();
  const [q, setQ] = aUseState("");
  const [type, setType] = aUseState("");
  const [applied, setApplied] = aUseState({ q: "", type: "" });
  const [offset, setOffset] = aUseState(0);
  const [sort, setSort] = aUseState({ col: "date", dir: "desc" });
  const onSort = (c, d) => { setOffset(0); setSort((s) => nextSort(s, c, d)); };
  const key = JSON.stringify(applied) + "|" + offset + "|" + sort.col + sort.dir;
  const { data, loading, err } = useArchive(
    () => window.OfficeAPI.archiveStockMovements({ limit: 50, offset, sort: sort.col, dir: sort.dir, ...(applied.q ? { q: applied.q } : {}), ...(applied.type ? { type: applied.type } : {}) }),
    key,
  );
  const openProduct = (pid) => { setScreenState({ activeProductId: pid, productFrom: "stockHistory" }); setScreen("productDetail"); };
  return (
    <div className="off-screen">
      <AHeader eyebrow="live from Aurora" title="Stock movement history"/>
      <div className="off-screen-body">
        <ASearch value={q} onChange={setQ} placeholder="Product name or barcode…"
          extra={<>
            <select className="input" value={type} onChange={(e) => setType(e.target.value)} style={{height:34, width:160}}>
              {MOVE_TYPES.map((t) => <option key={t} value={t}>{t === "" ? "All types" : aHuman(t)}</option>)}
            </select>
            <button className="btn btn--primary btn--sm" onClick={() => { setOffset(0); setApplied({ q, type }); }}>Search</button>
          </>}/>
        {err && <AErr err={"Couldn't load movements: " + err}/>}
        <div className="off-card">
          <div className="off-card-header">
            <h3 className="off-card-title">Movements</h3>
            <div className="off-card-meta">{loading ? "loading…" : aNum(data?.total) + " in trail · newest first"}</div>
          </div>
          {!loading && data && data.items.length === 0 && <AEmpty>No movements match.</AEmpty>}
          {data && data.items.length > 0 && (
            <div className="off-grid" style={{gridTemplateColumns:"140px minmax(180px,1.5fr) 140px 70px 110px"}}>
              <SortHead label="Date" col="date" sort={sort} onSort={onSort}/>
              <SortHead label="Product" col="product" sort={sort} onSort={onSort}/>
              <SortHead label="Type" col="type" sort={sort} onSort={onSort}/>
              <SortHead label="Qty" col="quantity" sort={sort} onSort={onSort} num/>
              <div className="off-grid-headcell" style={{justifyContent:"flex-end"}}>On hand</div>
              {data.items.map((m) => {
                const up = m.quantityDelta >= 0;
                return (
                  <div key={m.id} className="off-grid-row">
                    <div className="off-grid-cell off-cell-mono" style={{fontSize:"var(--fs-12)"}}>{aDateTime(m.occurredAt)}</div>
                    <div className="off-grid-cell off-cell-strong" style={{overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap", cursor: m.productId ? "pointer" : "default"}} onClick={m.productId ? () => openProduct(m.productId) : undefined}>
                      {m.productName || m.sku || "—"}{m.schedule === "S8" ? <span style={{color:"var(--void)", fontWeight:700, marginLeft:6, fontSize:"var(--fs-11)"}}>S8</span> : null}
                    </div>
                    <div className="off-grid-cell off-muted">{aHuman(m.movementType)}</div>
                    <div className="off-grid-cell off-cell-num off-cell-strong" style={{color: up ? "var(--paid-text)" : "var(--void)"}}>{up ? "+" : ""}{m.quantityDelta}</div>
                    <div className="off-grid-cell off-cell-num off-cell-mono" style={{fontSize:"var(--fs-12)"}}>{m.quantityBefore}→{m.quantityAfter}</div>
                  </div>
                );
              })}
            </div>
          )}
          {data && <APager total={data.total} limit={data.limit} offset={data.offset} onPage={setOffset}/>}
        </div>
      </div>
    </div>
  );
}

// -----------------------------------------------------------------
// Register
// -----------------------------------------------------------------
window.OFFICE_SCREENS = Object.assign(window.OFFICE_SCREENS || {}, {
  salesHistory: ArchiveSales,
  invoices: ArchivePurchasing,
  accounts: ArchiveAccounts,
  stockHistory: ArchiveStock,
});
