// Bylt Capital CRM — deals: list rail, deal file with five tabs, action rail.
// (Offer links live in offers.jsx.)

const TAG_ICON = { PAY: "alert", NOTE: "note", OPS: "note", CALL: "phone", EMAIL: "mail", TEXT: "note", SMS: "note", SUB: "offer", GROK: "spark", DOC: "file", MILE: "flag", APP: "file", DEAL: "flag", OFFER: "link" };
const TAG_LABEL = { PAY: "Payment", OPS: "Note", NOTE: "Note", CALL: "Call", EMAIL: "Email", TEXT: "Text", SMS: "Text", SUB: "Submission", GROK: "Grok", DOC: "Document", MILE: "Milestone", APP: "Application", DEAL: "Deal", OFFER: "Offer link" };

function bestOffer(subs) {
  return subs.filter(s => (s.status === "offer" || s.status === "approved" || s.status === "counter") && fmt.num(s.amount) > 0)
    .sort((a, b) => fmt.num(b.amount) - fmt.num(a.amount))[0] || null;
}
function findClient(deal, clients) {
  if (!deal) return null;
  return clients.find(c => deal.clientId && c.id === deal.clientId)
      || clients.find(c => fmt.nameKey(c.biz) && fmt.nameKey(c.biz) === fmt.nameKey(deal.biz)) || null;
}

// ── Left rail ───────────────────────────────────────────────────────────────
function DealRail({ deals, selectedId, onSelect, onNew, canWrite, loading, balances, onImport, onExport }) {
  const [q, setQ] = useState("");
  const [filter, setFilter] = useState("all");
  const [open, setOpen] = useState({});            // business groups opened by hand
  const count = (id) => deals.filter(d => (d.status || "new") === id).length;
  const filters = [{ id: "all", label: "All", n: deals.length }]
    .concat(["new", "submitted", "review", "funded", "declined"].map(id => ({ id, label: statusLabel(DEAL_STATUSES, id), n: count(id) })));

  const needle = q.trim().toLowerCase();
  const visible = deals.filter(d => (filter === "all" || (d.status || "new") === filter)
    && (!needle || [d.biz, d.contact, d.id, d.phone, d.email].some(x => String(x || "").toLowerCase().includes(needle))));
  // One row per business: deals on the same client record (or, with no
  // record, the same name) sit under one row that opens to show them.
  const groups = [];
  const at = new Map();
  // A deal with no client record joins the row of a same-named deal that has one.
  const nameToClient = new Map();
  for (const d of deals) if (d.clientId && fmt.nameKey(d.biz) && !nameToClient.has(fmt.nameKey(d.biz))) nameToClient.set(fmt.nameKey(d.biz), d.clientId);
  for (const d of visible) {
    const cid = d.clientId || nameToClient.get(fmt.nameKey(d.biz)) || null;
    const key = cid ? "c:" + cid : "n:" + (fmt.nameKey(d.biz) || d.id);
    if (!at.has(key)) { at.set(key, groups.length); groups.push({ key, clientId: cid, biz: d.biz, deals: [] }); }
    groups[at.get(key)].deals.push(d);
  }
  const isOpen = (g) => open[g.key] !== undefined ? open[g.key] : g.deals.some(d => d.id === selectedId);
  const dealRow = (d, sub) => (
    <button key={d.id} className={`deal-row${sub ? " sub" : ""}`} aria-current={d.id === selectedId} onClick={() => onSelect(d.id)}>
      {sub ? null : <Avatar name={d.biz} />}
      <span className="main">
        <span className="name" style={{ display: "block" }}>{sub ? (d.status === "funded" && d.funder ? d.funder : d.contact || d.id) : d.biz}</span>
        <span className="sub" style={{ display: "block" }}>{sub ? `${d.id}${d.fundedAt ? " · " + fmt.date(d.fundedAt) : ""}` : d.contact || "No contact on file"}</span>
        <span className="meta">
          <Pill status={d.status || "new"} label={statusLabel(DEAL_STATUSES, d.status || "new")} />
          {fmt.num(d.amount) ? <span className="amt tnum">{fmt.moneyShort(d.amount)}</span> : null}
          {d.offerSeen ? <SeenChip at={d.offerSeen.at} via={d.offerSeen.via} views={d.offerSeen.views} /> : null}
        </span>
      </span>
    </button>
  );
  const groupRow = (g) => {
    const b = g.clientId && balances ? balances[g.clientId] : null;
    const opened = isOpen(g);
    const counts = {};
    for (const d of g.deals) counts[d.status || "new"] = (counts[d.status || "new"] || 0) + 1;
    return (
      <div key={g.key} className={`deal-group${opened ? " open" : ""}`}>
        <button className="deal-row group" aria-expanded={opened} aria-current={!opened && g.deals.some(d => d.id === selectedId)} onClick={() => setOpen(o => ({ ...o, [g.key]: !opened }))}>
          <Avatar name={g.biz} />
          <span className="main">
            <span className="name" style={{ display: "block" }}>{g.biz}</span>
            <span className="sub" style={{ display: "block" }}>{g.deals.length} deals · {Object.entries(counts).map(([k, n]) => `${n} ${statusLabel(DEAL_STATUSES, k).toLowerCase()}`).join(", ")}</span>
            {b && b.open ? <span className="meta"><span className="amt tnum">{fmt.moneyShort(b.remaining)} bal · {b.pct}% paid</span>{b.renewal ? <Pill status="submitted" label="Renewal" /> : null}</span> : null}
          </span>
          <span className="chev" aria-hidden="true"><Icon name="chev" size={15} /></span>
        </button>
        {opened ? g.deals.map(d => dealRow(d, true)) : null}
      </div>
    );
  };

  return (
    <aside className="rail">
      <div className="rail-head">
        <div className="rail-title">
          <div>
            <div className="label">Pipeline</div>
            <h2>Deals</h2>
          </div>
          <span className="rail-acts">
            {onImport ? <button className="icon-btn" onClick={onImport} aria-label="Import deals" title="Import"><Icon name="upload" size={16} /></button> : null}
            {onExport ? <button className="icon-btn" onClick={onExport} aria-label="Export deals" title="Export"><Icon name="download" size={16} /></button> : null}
            {canWrite ? <button className="btn btn-primary btn-sm" onClick={onNew}><Icon name="plus" size={14} />New</button> : null}
          </span>
        </div>
        <div className="search">
          <Icon name="search" size={15} />
          <input type="search" value={q} onChange={e => setQ(e.target.value)} placeholder="Search business, owner, ID…" aria-label="Search deals" />
        </div>
        <div className="filters" role="group" aria-label="Filter by status">
          {filters.map(f => (
            <button key={f.id} className="filter" aria-pressed={filter === f.id} onClick={() => setFilter(f.id)}>
              {f.label}<span className="n tnum">{f.n}</span>
            </button>
          ))}
        </div>
      </div>
      <div className="rail-list scroll">
        {loading ? <div className="empty"><p>Loading deals…</p></div>
          : !deals.length ? (
            <Empty title="No deals yet" action={canWrite ? <button className="btn btn-primary" onClick={onNew}><Icon name="plus" size={14} />New deal</button> : null}>
              Create the first deal to start tracking lender submissions and documents.
            </Empty>
          ) : !visible.length ? <div className="empty"><p>No deals match that search or filter.</p></div>
          : groups.map(g => (g.deals.length === 1 ? dealRow(g.deals[0], false) : groupRow(g)))}
      </div>
    </aside>
  );
}

// ── Tabs ────────────────────────────────────────────────────────────────────
function OverviewTab({ deal, subs, activity, team, go, payments, canWrite, onLogBounce, onRemoveBounce, onMadeGood, commission, offerLinks, statementSummary }) {
  const best = bestOffer(subs);
  const rep = team.find(t => t.id === deal.repId);
  const pct = Math.max(0, Math.min(100, fmt.num(deal.paidPct)));
  const funded = deal.status === "funded";
  const stat = (label, value) => <div className="stat"><div className="label">{label}</div><div className="v tnum">{value}</div></div>;
  return (
    <>
      <div className="card stats">
        {stat("Amount", fmt.num(deal.amount) ? fmt.money(deal.amount) : "—")}
        {stat("Factor", fmt.num(deal.factor) ? fmt.num(deal.factor).toFixed(2) : "—")}
        {stat("Term", fmt.num(deal.term) ? fmt.term(deal.term, deal.termUnit) : "—")}
        {stat("Daily payment", fmt.num(deal.daily) ? fmt.money(deal.daily) : "—")}
        {stat("Payback", fmt.num(deal.payback) ? fmt.money(deal.payback) : "—")}
      </div>

      {statementSummary}

      {funded || pct > 0 ? (
        <div className="card">
          <div className="card-body">
            <div className="section-bar" style={{ marginBottom: 10 }}>
              <span className="label">Repayment</span>
              <b className="tnum">{pct}% repaid</b>
            </div>
            <div className="progress" role="progressbar" aria-valuenow={pct} aria-valuemin="0" aria-valuemax="100"><i style={{ width: pct + "%" }} /></div>
            {fmt.num(deal.payback) ? (
              <div className="terms" style={{ marginTop: 10 }}>
                <span>Collected <b className="tnum">{fmt.money(Math.round(fmt.num(deal.payback) * pct) / 100)}</b></span>
                <span>Remaining <b className="tnum">{fmt.money(Math.round(fmt.num(deal.payback) * (100 - pct)) / 100)}</b></span>
              </div>
            ) : null}
          </div>
        </div>
      ) : null}

      {offerLinks}

      <div className="grid-2">
        <div className="card">
          <div className="card-head"><span className="label">Key facts</span></div>
          <dl>
            <div className="kv"><dt>Status</dt><dd><Pill status={deal.status || "new"} label={statusLabel(DEAL_STATUSES, deal.status || "new")} /></dd></div>
            <div className="kv"><dt>Assigned rep</dt><dd>{rep ? rep.name : deal.repId ? <span className="muted">Someone outside your team</span> : <span className="muted">Unassigned · Admins only</span>}</dd></div>
            {(deal.coRepIds || []).length ? <div className="kv"><dt>Also on it</dt><dd>{(deal.coRepIds || []).map(id => (team.find(t => t.id === id) || {}).name).filter(Boolean).join(", ") || <span className="muted">Others outside your team</span>}</dd></div> : null}
            <div className="kv"><dt>Source</dt><dd>{deal.source || "—"}</dd></div>
            <div className="kv"><dt>Brokered</dt><dd>{deal.broker && deal.broker.isBrokered ? "Yes" : "No"}</dd></div>
            {funded ? <div className="kv"><dt>Funded by</dt><dd>{deal.funder || <span className="muted">Not recorded</span>}{deal.fundedAt ? <span className="muted"> · {fmt.date(deal.fundedAt)}</span> : null}</dd></div> : null}
            <div className="kv"><dt>Opened</dt><dd>{fmt.date(deal.createdAt) || deal.date || "—"}</dd></div>
            <div className="kv"><dt>Last updated</dt><dd>{fmt.when(deal.updatedAt) || "—"}</dd></div>
          </dl>
        </div>
        <div className="card">
          <div className="card-head">
            <span className="label">Lender submissions</span>
            <button className="link-btn" onClick={() => go("submissions")}>View all</button>
          </div>
          {best ? (
            <div className="card-body">
              <div className="label">Best offer</div>
              <div className="serif tnum" style={{ fontSize: 28, fontWeight: 500, lineHeight: 1.15, marginTop: 2 }}>{fmt.money(best.amount)}</div>
              <div className="terms">
                <span><b>{best.lender}</b></span>
                {fmt.num(best.factor) ? <span>Factor <b>{best.factor}</b></span> : null}
                {fmt.num(best.term) ? <span><b>{fmt.term(best.term, best.termUnit)}</b></span> : null}
              </div>
              <div className="muted" style={{ fontSize: 12.5, marginTop: 10 }}>
                {subs.length} {subs.length === 1 ? "lender" : "lenders"} · {subs.filter(s => s.status === "declined").length} declined
              </div>
            </div>
          ) : (
            <div className="card-body dim" style={{ fontSize: 13.5 }}>
              {subs.length ? `${subs.length} ${subs.length === 1 ? "lender has" : "lenders have"} responded, none with an offer yet.` : "No lender has responded yet."}
            </div>
          )}
        </div>
      </div>

      {commission}

      {funded && fmt.inHouse(deal.funder) ? (
        <div className="card card-flush">
          <div className="card-head">
            <span className="label">Bounced payments</span>
            {canWrite ? <button className="btn btn-sm" onClick={onLogBounce}><Icon name="alert" size={14} />Log bounced payment</button> : null}
          </div>
          {payments.length ? payments.map(p => (
            <div className="row" key={p.id}>
              <span className={`hicon ${p.status === "bounced" ? "t-bad" : "t-good"}`}><Icon name={p.status === "bounced" ? "alert" : "check"} size={15} /></span>
              <div className="grow">
                <div className="title">{fmt.money(p.amount)} on {fmt.day(p.date)}{p.status === "bounced" ? <Pill status="declined" label="Open" /> : <Pill status="funded" label="Made good" />}</div>
                <div className="line">{[p.reason, p.note].filter(Boolean).join(" · ") || "No reason recorded"}</div>
                <div className="when">{p.createdBy ? `Logged by ${p.createdBy}` : "Logged"} {fmt.when(p.createdAt).replace(/^T/, "t").replace(/^Y/, "y")}</div>
              </div>
              {canWrite ? (
                <div className="row-actions">
                  {p.status === "bounced" ? <button className="btn btn-sm" onClick={() => onMadeGood(p)}>Mark made good</button> : null}
                  <button className="icon-btn" onClick={() => onRemoveBounce(p)} aria-label={`Remove the ${fmt.money(p.amount)} bounce on ${fmt.day(p.date)}`}><Icon name="trash" size={15} /></button>
                </div>
              ) : null}
            </div>
          )) : <div className="card-body dim" style={{ fontSize: 13.5 }}>No bounced payments recorded. One you log stays on Home until it is marked made good.</div>}
        </div>
      ) : null}

      {deal.bankNotes ? (
        <div className="card">
          <div className="card-head"><span className="label">Bank notes</span></div>
          <div className="card-body notes">{deal.bankNotes}</div>
        </div>
      ) : null}

      <div className="card card-flush">
        <div className="card-head">
          <span className="label">Recent activity</span>
          <button className="link-btn" onClick={() => go("activity")}>View all</button>
        </div>
        {activity.length ? activity.slice(0, 4).map((a, i) => <ActivityRow key={i} a={a} />)
          : <div className="card-body dim" style={{ fontSize: 13.5 }}>Nothing logged on this deal yet.</div>}
      </div>
    </>
  );
}

const FUNDABLE = ["offer", "approved", "counter"];
function SubmissionRow({ s, dealId, canWrite, onEdit, onDelete, onFund }) {
  const [open, setOpen] = useState(false);
  const hasMore = (s.stips && s.stips.length) || s.notes || s.sourceRaw;
  return (
    <div className="row sub-row">
      <Avatar name={s.lender} square />
      <div className="grow">
        <div className="title">{s.lender}<Pill status={s.status} label={statusLabel(SUB_STATUSES, s.status)} /></div>
        {s.status !== "declined" ? (
          <div className="terms tnum">
            {fmt.num(s.factor) ? <span>Factor <b>{s.factor}</b></span> : null}
            {fmt.num(s.term) ? <span><b>{fmt.term(s.term, s.termUnit)}</b></span> : null}
            {fmt.num(s.payment) ? <span><b>{fmt.money(s.payment)}</b> {String(s.freq || "Daily").toLowerCase()}</span> : null}
            {fmt.num(s.payback) ? <span>Payback <b>{fmt.money(s.payback)}</b></span> : null}
            {fmt.num(s.upsell) ? <span>Upsell <b>{s.upsell}</b> pts</span> : null}
          </div>
        ) : null}
        <div className="when">
          {s.createdBy ? `Logged by ${s.createdBy} · ` : ""}{fmt.when(s.createdAt) || s.ts}
          {s.sourceType ? ` · from ${s.sourceType}` : ""}
          {s.expiresAt && s.status !== "declined" ? ` · good until ${fmt.day(s.expiresAt)}` : ""}
          {hasMore ? <> · <button className="link-btn" onClick={() => setOpen(!open)} aria-expanded={open}>{open ? "Hide details" : "Details"}</button></> : null}
          {s.status === "funded" && s.fundedDealId && s.fundedDealId !== dealId ? <> · <a href={`#/deals/${encodeURIComponent(s.fundedDealId)}`}>Funded as deal {s.fundedDealId}</a></> : null}
        </div>
        {canWrite && FUNDABLE.includes(s.status) && fmt.num(s.amount) > 0 ? (
          <button className="btn btn-sm btn-primary fund-btn" onClick={onFund}><Icon name="check" size={14} />Mark funded</button>
        ) : null}
        {open ? (
          <div className="detail">
            {s.stips && s.stips.length ? <><b>Stipulations</b><div className="chips">{s.stips.map((x, i) => <span className="chip" key={i}>{x}</span>)}</div></> : null}
            {s.notes ? <div style={{ marginTop: s.stips && s.stips.length ? 10 : 0 }}><b>Notes</b><div className="notes">{s.notes}</div></div> : null}
            {s.sourceRaw ? <div style={{ marginTop: 10 }}><b>Original {s.sourceType || "message"}</b><pre>{s.sourceRaw}</pre></div> : null}
          </div>
        ) : null}
      </div>
      <div className="right">
        {fmt.num(s.amount) ? <div className="big tnum">{fmt.money(s.amount)}</div> : <div className="muted">—</div>}
      </div>
      {canWrite ? (
        <div className="row-actions">
          <button className="icon-btn" onClick={onEdit} aria-label={`Edit ${s.lender} submission`}><Icon name="edit" size={15} /></button>
          <button className="icon-btn" onClick={onDelete} aria-label={`Delete ${s.lender} submission`}><Icon name="trash" size={15} /></button>
        </div>
      ) : null}
    </div>
  );
}

function SubmissionsTab({ subs, dealId, canWrite, onAdd, onEdit, onDelete, onFund }) {
  const offers = subs.filter(s => s.status !== "declined" && s.status !== "pending").length;
  return (
    <>
      <div className="section-bar">
        <span className="label">{subs.length} {subs.length === 1 ? "lender" : "lenders"}{subs.length ? ` · ${offers} with terms` : ""}</span>
        {canWrite ? <button className="btn btn-primary btn-sm" onClick={onAdd}><Icon name="plus" size={14} />Add submission</button> : null}
      </div>
      <div className="card card-flush">
        {subs.length ? subs.map(s => <SubmissionRow key={s.id} s={s} dealId={dealId} canWrite={canWrite} onEdit={() => onEdit(s)} onDelete={() => onDelete(s)} onFund={() => onFund(s)} />)
          : <Empty title="No lender responses yet">{canWrite ? "Add each offer or decline as it comes in. The best offer shows on the overview." : "Offers and declines appear here as they come in."}</Empty>}
      </div>
    </>
  );
}

function ActivityRow({ a }) {
  const tag = String(a.tag || "NOTE").toUpperCase();
  return (
    <div className="row">
      <span className="act-icon"><Icon name={TAG_ICON[tag] || "note"} size={15} /></span>
      <div className="grow">
        <div className="line" style={{ color: "var(--ink)", marginTop: 0 }}>{a.text}</div>
        <div className="when">
          <span className={`tag t-${tag.toLowerCase()}`}>{TAG_LABEL[tag] || fmt.title(tag.toLowerCase())}</span>{"  "}{fmt.when(a.ts)}
        </div>
      </div>
    </div>
  );
}
function ActivityTab({ activity, canWrite, onAdd }) {
  return (
    <>
      <div className="section-bar">
        <span className="label">{activity.length} {activity.length === 1 ? "event" : "events"}</span>
        {canWrite ? <button className="btn btn-primary btn-sm" onClick={onAdd}><Icon name="plus" size={14} />Log activity</button> : null}
      </div>
      <div className="card card-flush">
        {activity.length ? activity.map((a, i) => <ActivityRow key={i} a={a} />)
          : <Empty title="Nothing logged yet">Calls, notes, lender responses and uploads are listed here, newest first.</Empty>}
      </div>
    </>
  );
}

const SLOTS = [
  { key: "dlFront", role: "dl-front", label: "Driver license, front" },
  { key: "dlBack", role: "dl-back", label: "Driver license, back" },
  { key: "check", role: "voided-check", label: "Voided check" },
];
function extOf(name) { const m = String(name || "").match(/\.([A-Za-z0-9]{1,5})$/); return m ? m[1].toUpperCase() : "FILE"; }
function DocumentsTab({ deal, canWrite, onUpload, onDelete, statements, toast }) {
  const all = Array.isArray(deal.docs) ? deal.docs : [];
  // Once the statements section has loaded it lists the statement files itself, with what was read from each.
  const split = !!(statements && statements.data);
  const docs = split ? all.filter(f => !isStatementFile(f)) : all;
  const slots = deal.documents || {};
  return (
    <>
      <div className="section-bar">
        <span className="label">Identity and banking</span>
        {canWrite ? <button className="btn btn-primary btn-sm" onClick={() => onUpload()}><Icon name="upload" size={14} />Upload document</button> : null}
      </div>
      <div className="slots">
        {SLOTS.map(sl => {
          const f = slots[sl.key];
          return (
            <div className={`slot${f ? " filled" : ""}`} key={sl.key}>
              <div className="label">{sl.label}</div>
              {f ? (
                <>
                  <div className="name" title={f.name}>{f.name}</div>
                  <div className="muted" style={{ fontSize: 12 }}>{f.size} · {fmt.date(f.uploaded)}</div>
                  <div className="acts">
                    <a className="btn btn-sm" href={API.documentUrl(f.objectKey)} target="_blank" rel="noopener">Open</a>
                    {canWrite ? <button className="btn btn-sm btn-danger" onClick={() => onDelete(f)}>Remove</button> : null}
                  </div>
                </>
              ) : (
                <>
                  <div className="muted" style={{ fontSize: 13, marginTop: 6 }}>Not on file</div>
                  {canWrite ? <div className="acts"><button className="btn btn-sm" onClick={() => onUpload(sl.role)}>Upload</button></div> : null}
                </>
              )}
            </div>
          );
        })}
      </div>
      <StatementsCard deal={deal} statements={statements} canWrite={canWrite} toast={toast} onDelete={onDelete} />
      <div className="section-bar"><span className="label">{split ? "Other documents" : "All documents"}</span></div>
      <div className="card card-flush">
        {docs.length ? docs.map(f => (
          <div className="row" key={f.objectKey}>
            <span className="doc-icon">{extOf(f.name)}</span>
            <div className="grow">
              <div className="title" style={{ fontWeight: 600 }}>{f.name}</div>
              <div className="when" style={{ marginTop: 2 }}>{f.kind || "Document"} · {f.size} · {fmt.date(f.uploaded)}{f.uploadedBy ? ` · uploaded by ${f.uploadedBy}` : ""}</div>
            </div>
            <div className="row-actions">
              <a className="btn btn-sm" href={API.documentUrl(f.objectKey)} target="_blank" rel="noopener">Open</a>
              {canWrite ? <button className="icon-btn" onClick={() => onDelete(f)} aria-label={`Delete ${f.name}`}><Icon name="trash" size={15} /></button> : null}
            </div>
          </div>
        )) : <Empty title={split && all.length ? "No other files" : "No files yet"}>{split && all.length ? "Tax returns, financials, contracts and anything else for this deal." : "Bank statements, tax returns, financials, contracts and anything else for this deal."}</Empty>}
      </div>
    </>
  );
}

// Private details (the same card as on a lead and a client), then the website application when there is one.
function ApplicationCard({ deal, client, canReveal, onEnter }) {
  const app = deal.application;
  return (
    <>
      <PrivateDetailsCard kind="deal" id={deal.id} summary={piiSummary.deal(deal, client)} canReveal={canReveal} onEnter={onEnter} />
      {app && app.source !== "typed" ? (
        <div className="card">
          <div className="card-head"><span className="label">{app.source === "import" ? "Imported application" : "Website application"}</span></div>
          <ApplicationDetails app={app} hidePrivate canReveal={canReveal} />
        </div>
      ) : null}
    </>
  );
}

// Which client file this deal belongs to, and the ones it might: matches the server found (similar name, same
// EIN, phone or email), a client that only shares the name (shown, but not linked), and a "may be the same
// business" question left when the deal funded (deal.clientMatch).
const whyText = (why) => (why || []).join(", ");
function ClientMatches({ deal, client, canWrite, onLink, onPick, onDismissMatch }) {
  const [found, setFound] = useState(null);
  useEffect(() => { let live = true; setFound(null); API.clientMatches(deal.id).then(r => live && setFound(r.candidates || []), () => live && setFound([])); return () => { live = false; }; }, [deal.id, deal.clientId]);
  const [busy, setBusy] = useState("");
  const link = async (c) => { setBusy(c.id); try { await onLink(c); } finally { setBusy(""); } };
  const linked = !!(client && deal.clientId === client.id);
  const asked = deal.clientMatch && Array.isArray(deal.clientMatch.candidates) ? deal.clientMatch.candidates.filter(c => c.id !== deal.clientId) : [];
  const others = (found || []).filter(c => c.id !== deal.clientId && !(client && !linked && c.id === client.id) && !asked.some(a => a.id === c.id));
  if (!canWrite) return null;
  return (
    <>
      {client && !linked ? (
        <div className="banner info">
          <div><b>Not linked yet.</b> {client.biz} ({client.id}) has the same business name, so it shows here, but this deal isn't on its file: its statements and advance don't count there.</div>
          <div style={{ marginTop: 8, display: "flex", gap: 8, flexWrap: "wrap" }}>
            <button className="btn btn-sm btn-primary" disabled={!!busy} onClick={() => link(client)}>{busy === client.id ? "Linking…" : `Link this deal to ${client.biz}`}</button>
            <button className="btn btn-sm" onClick={onPick}>A different client…</button>
          </div>
        </div>
      ) : null}
      {asked.length ? (
        <div className="banner info">
          <div><b>This may be the same business as {asked.length === 1 ? "another client" : "other clients"}.</b> When the deal funded, the CRM gave it a client file of its own because no client matched for sure. If it belongs to one of these, move it there: its advance moves too, and the extra file is removed.</div>
          <div style={{ marginTop: 8, display: "grid", gap: 6 }}>
            {asked.map(c => (
              <div key={c.id} style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
                <span><b>{c.biz}</b> <span className="muted">· {c.id} · {whyText(c.why)}</span></span>
                <button className="btn btn-sm btn-primary" disabled={!!busy} onClick={() => link(c)}>{busy === c.id ? "Moving…" : "Move deal here"}</button>
              </div>
            ))}
          </div>
          <div style={{ marginTop: 8 }}><button className="btn btn-sm" onClick={onDismissMatch}>Not the same business</button></div>
        </div>
      ) : null}
      {!client && others.length ? (
        <div className="card">
          <div className="card-head"><span className="label">Might be an existing client</span></div>
          {others.map(c => (
            <div className="row" key={c.id}>
              <div className="grow"><div className="title">{c.biz}</div><div className="when">{[c.id, c.owner, whyText(c.why)].filter(Boolean).join(" · ")}</div></div>
              <div className="right"><button className="btn btn-sm btn-primary" disabled={!!busy} onClick={() => link(c)}>{busy === c.id ? "Linking…" : "Link this deal"}</button></div>
            </div>
          ))}
        </div>
      ) : null}
    </>
  );
}

// Pick the client file a deal belongs to: likely matches first, then a search over every client this person can see.
function LinkClientSheet({ deal, clients, current, canUnlink, onClose, onLink, onUnlink }) {
  const [q, setQ] = useState("");
  const [found, setFound] = useState([]);
  const [error, setError] = useState("");
  const [busy, setBusy] = useState("");
  useEffect(() => { API.clientMatches(deal.id).then(r => setFound(r.candidates || []), () => {}); }, [deal.id]);
  const needle = q.trim().toLowerCase();
  const hit = (c) => !needle || [c.biz, c.owner, c.phone, c.email, c.id, ...(c.aliases || [])].some(x => String(x || "").toLowerCase().includes(needle));
  const list = needle ? clients.filter(c => c.id !== current && hit(c)).slice(0, 30) : found.filter(c => c.id !== current).map(f => ({ ...(clients.find(c => c.id === f.id) || {}), ...f }));
  const go = async (fn, id) => { setBusy(id); setError(""); try { await fn(); } catch (e) { setError(e.message); setBusy(""); } };
  return (
    <Sheet eyebrow={deal.biz} title={current ? "Move to another client" : "Link to a client"} onClose={onClose} error={error}
           danger={current && canUnlink ? <button type="button" className="btn btn-quiet btn-danger" style={{ marginRight: "auto" }} disabled={!!busy} onClick={() => go(onUnlink, "-")}>Unlink</button> : null}>
      <div className="form-section">
        <Field label="Search clients" full><TextInput value={q} onChange={setQ} placeholder="Business, owner, phone, email or client id" /></Field>
        <div className="dim" style={{ fontSize: 12.5, margin: "8px 0" }}>{needle ? `${list.length ? list.length : "No"} matching ${list.length === 1 ? "client" : "clients"}` : found.length ? "Likely matches for this deal. Search to find any other client." : "No likely matches. Search by name, owner, phone or email."}</div>
        <div className="card card-flush">
          {list.map(c => (
            <div className="row" key={c.id}>
              <div className="grow"><div className="title">{c.biz}</div><div className="when">{[c.id, c.owner, c.phone, c.why ? whyText(c.why) : ""].filter(Boolean).join(" · ")}</div></div>
              <div className="right"><button type="button" className="btn btn-sm btn-primary" disabled={!!busy} onClick={() => go(() => onLink(c), c.id)}>{busy === c.id ? "Saving…" : current ? "Move here" : "Link"}</button></div>
            </div>
          ))}
        </div>
      </div>
    </Sheet>
  );
}

function ClientTab({ deal, client, deals, canWrite, canReveal, onCreate, onEdit, onEnter, onLink, onPick, onDismissMatch }) {
  const matches = <ClientMatches deal={deal} client={client} canWrite={canWrite} onLink={onLink} onPick={onPick} onDismissMatch={onDismissMatch} />;
  if (!client) {
    return (
      <>
      <ApplicationCard deal={deal} client={client} canReveal={canReveal} onEnter={onEnter} />
      {matches}
      <div className="card">
        <Empty title="No client file for this deal"
               action={canWrite ? <span style={{ display: "flex", gap: 8, flexWrap: "wrap", justifyContent: "center" }}><button className="btn" onClick={onPick}><Icon name="users" size={14} />Link to an existing client</button><button className="btn btn-primary" onClick={onCreate}><Icon name="plus" size={14} />Create client record</button></span> : null}>
          A client file keeps the owner's details, EIN, deals, advances and statements in one place, however many deals they do. A returning client's new deal belongs on their existing file.
        </Empty>
      </div>
      </>
    );
  }
  const theirs = deals.filter(d => (d.clientId && d.clientId === client.id) || fmt.nameKey(d.biz) === fmt.nameKey(client.biz));
  const fundedTotal = theirs.filter(d => d.status === "funded").reduce((t, d) => t + fmt.num(d.amount), 0);
  return (
    <>
      <ApplicationCard deal={deal} client={client} canReveal={canReveal} onEnter={onEnter} />
      {matches}
      <div className="section-bar">
        <span className="label">Client {client.id}</span>
        <span style={{ display: "flex", gap: 8 }}>
          <a className="btn btn-sm btn-primary" href={`#/clients/${encodeURIComponent(client.id)}`}><Icon name="users" size={14} />Open client file</a>
          {canWrite ? <button className="btn btn-sm" onClick={onEdit}><Icon name="edit" size={14} />Edit client</button> : null}
          {canWrite && deal.clientId === client.id ? <button className="btn btn-sm" onClick={onPick}>Change client</button> : null}
        </span>
      </div>
      <div className="grid-2">
        <div className="card">
          <div className="card-head"><span className="label">Owner</span></div>
          <dl>
            <div className="kv"><dt>Name</dt><dd>{client.owner || "—"}</dd></div>
            <div className="kv"><dt>Phone</dt><dd>{client.phone ? <a href={`tel:${client.phone}`}>{client.phone}</a> : "—"}</dd></div>
            <div className="kv"><dt>Email</dt><dd>{client.email ? <a href={`mailto:${client.email}`}>{client.email}</a> : "—"}</dd></div>
          </dl>
        </div>
        <div className="card">
          <div className="card-head"><span className="label">Business</span></div>
          <dl>
            <div className="kv"><dt>Name</dt><dd>{client.biz}</dd></div>
            <div className="kv"><dt>Address</dt><dd>{client.address || "—"}</dd></div>
            <div className="kv"><dt>Funded to date</dt><dd className="tnum">{fundedTotal ? fmt.money(fundedTotal) : "—"}</dd></div>
          </dl>
        </div>
      </div>
      <div className="card card-flush">
        <div className="card-head"><span className="label">Deals with this client</span></div>
        {theirs.map(d => (
          <div className="row" key={d.id}>
            <div className="grow">
              <div className="title">{d.id === deal.id ? "This deal" : <a href={`#/deals/${encodeURIComponent(d.id)}`}>{d.id}</a>}<Pill status={d.status || "new"} label={statusLabel(DEAL_STATUSES, d.status || "new")} /></div>
              <div className="when">{fmt.date(d.createdAt) || d.date}</div>
            </div>
            <div className="right"><div className="big tnum">{fmt.num(d.amount) ? fmt.money(d.amount) : "—"}</div></div>
          </div>
        ))}
      </div>
    </>
  );
}

// ── The deal file (center + right rail) ─────────────────────────────────────
function DealFile({ deal: listed, deals, clients, team, lenders, user, office, canWrite, canDelete, onBack, onChanged, onCreated, onDeleted, refreshClients, refreshLenders, toast, confirm }) {
  const [tab, setTab] = useState("overview");
  const [subs, setSubs] = useState([]);
  const [activity, setActivity] = useState([]);
  const [loadError, setLoadError] = useState("");
  const [sheet, setSheet] = useState(null);     // { kind, ...payload }
  const [detail, setDetail] = useState(null);   // the deal as the server has it right now, with its files
  const [payments, setPayments] = useState([]);
  const [offers, setOffers] = useState([]);
  const dealId = listed.id;
  const deal = detail && detail.id === dealId ? detail : listed;
  const portal = usePortal(dealId);          // the client portal: account, checklist, messages (portal.jsx)

  // Answers for a deal that is no longer the one on screen are dropped.
  const showing = useRef(dealId); showing.current = dealId;
  const loadSide = useCallback(async () => {
    try {
      const [s, a, p, o] = await Promise.all([API.submissions(dealId), API.activity(dealId), API.payments(dealId).catch(() => []), API.offers(dealId).catch(() => [])]);
      if (showing.current !== dealId) return;
      setSubs(s); setActivity(a); setPayments(p); setOffers(o); setLoadError("");
    } catch (err) { if (showing.current === dealId && err.status !== 401) setLoadError(err.message); }
  }, [dealId]);

  const refreshDeal = useCallback(async () => {
    try { const d = await API.deal(dealId); if (showing.current === dealId) setDetail(d); onChanged(d); } catch (e) { /* the list reload reports it */ }
  }, [dealId]);
  const saved = (d) => { if (d && d.id) { setDetail(d); onChanged(d); } };

  useEffect(() => { setTab("overview"); setSubs([]); setActivity([]); setPayments([]); setOffers([]); setSheet(null); setDetail(null); loadSide(); refreshDeal(); }, [dealId]);

  // Offers, notes and files can arrive from Grok or a colleague while this file
  // is open: pick them up when switching tabs or coming back to the window.
  const firstTab = useRef(true);
  useEffect(() => {
    if (firstTab.current) { firstTab.current = false; return; }
    loadSide(); refreshDeal(); portal.load();
  }, [tab]);
  useEffect(() => {
    const onShow = () => { if (document.visibilityState === "visible") { loadSide(); refreshDeal(); portal.load(); } };
    document.addEventListener("visibilitychange", onShow);
    return () => document.removeEventListener("visibilitychange", onShow);
  }, [dealId]);
  const client = findClient(deal, clients);
  const best = bestOffer(subs);
  const docCount = (Array.isArray(deal.docs) ? deal.docs.length : 0) + SLOTS.filter(s => deal.documents && deal.documents[s.key]).length;
  const statements = useStatements(dealId, Array.isArray(deal.docs) ? deal.docs.length : 0);
  const close = () => setSheet(null);

  const askDeleteSub = (s) => confirm({
    title: "Delete this submission?", body: `${s.lender}'s ${statusLabel(SUB_STATUSES, s.status).toLowerCase()} will be removed from this deal.`, confirmLabel: "Delete submission",
    onConfirm: async () => { await API.deleteSubmission(dealId, s.id); await loadSide(); toast("Submission deleted"); },
  });
  const askDeleteDoc = (f) => confirm({
    title: "Delete this file?", body: `${f.name} will be permanently removed.`, confirmLabel: "Delete file",
    onConfirm: async () => { await API.deleteDocument(f.objectKey); await refreshDeal(); toast("File deleted"); },
  });
  // Linking the deal to a client file (or moving it to another): its advance and statements count there from then on.
  const linkClient = async (c) => {
    try { saved(await API.updateDeal(dealId, { clientId: c.id })); await refreshClients(); toast(`Linked to ${c.biz}`); setSheet(null); }
    catch (err) { toast(err.message, true); throw err; }
  };
  const unlinkClient = async () => { saved(await API.updateDeal(dealId, { clientId: null })); await refreshClients(); toast("Unlinked from the client file"); setSheet(null); };
  const dismissClientMatch = async () => { try { saved(await API.updateDeal(dealId, { clientMatch: null })); toast("Kept on its own client file"); } catch (err) { toast(err.message, true); } };
  const askDeleteDeal = () => confirm({
    title: "Delete this deal?", body: `${deal.biz} and its submissions, activity and uploaded files will be permanently removed.`, confirmLabel: "Delete deal",
    onConfirm: async () => { await API.deleteDeal(dealId); onDeleted(dealId); toast("Deal deleted"); },
  });

  // Puts the terms the client accepted onto the deal itself.
  const applyTerms = async (o) => {
    const t = o.selection;
    try {
      saved(await API.updateDeal(dealId, { amount: t.amount, factor: t.factor, ...(t.termUnit === "weeks" && t.termCount ? { term: t.termCount, termUnit: "weeks" } : { term: t.term, termUnit: "days" }), payback: t.payback, daily: Math.round((t.payback / t.term) * 100) / 100 }));
      await loadSide(); toast("Deal updated with the accepted terms");
    } catch (err) { toast(err.message, true); }
  };

  const tabs = [
    { id: "overview", label: "Overview", short: "Overview" },
    { id: "submissions", label: "Submissions", short: "Lenders", n: subs.length },
    { id: "activity", label: "Activity", short: "Activity", n: activity.length },
    { id: "map", label: "Map", short: "Map" },
    { id: "documents", label: "Documents", short: "Docs", n: docCount },
    { id: "portal", label: "Portal", short: "Portal", n: portal.data && portal.data.checklist ? portal.data.checklist.filter(i => i.status === "received").length : 0 },
    canOf(user).clients !== false ? { id: "client", label: "Client", short: "Client" } : null,
  ].filter(Boolean);
  const actions = canWrite ? [
    { label: "Add submission", short: "Lender", icon: "offer", run: () => setSheet({ kind: "submission" }) },
    { label: "Offer link", short: "Offer link", icon: "link", run: () => setSheet({ kind: "offer" }) },
    { label: "Log activity", short: "Activity", icon: "note", run: () => setSheet({ kind: "activity" }) },
    { label: "Upload doc", short: "Upload", icon: "upload", run: () => setSheet({ kind: "upload" }) },
    { label: "Edit deal", short: "Edit", icon: "edit", run: () => setSheet({ kind: "deal" }) },
  ] : [];

  return (
    <>
      <section className="file">
        <div className="file-head">
          <button className="back" onClick={onBack}><Icon name="back" size={15} />All deals</button>
          <div className="file-top">
            <div style={{ minWidth: 0 }}>
              <div className="file-id">
                <span className="label">Deal · {deal.id}</span>
                <Pill status={deal.status || "new"} label={statusLabel(DEAL_STATUSES, deal.status || "new")} />
              </div>
              <div className="name-row"><h1 className="file-name">{deal.biz}</h1><RemitBadge share={remitShare(statements.data && statements.data.summary)} withPlatforms={remitShareAll(statements.data && statements.data.summary)} /><BankLabels reverse={bankLabelsOf(statements.data && statements.data.summary).reverse} debtSettlement={bankLabelsOf(statements.data && statements.data.summary).debtSettlement} highRisk={!!(statements.data && statements.data.callNotes && statements.data.callNotes.redFlagSummary && statements.data.callNotes.redFlagSummary.highRisk)} /></div>
              <div className="file-contact">
                {client ? <a href={`#/clients/${encodeURIComponent(client.id)}`} className="client-link"><Icon name="users" size={13} />Client file</a> : null}
                {deal.contact ? <span>{deal.contact}</span> : null}
                {deal.phone ? <a href={`tel:${deal.phone}`}>{deal.phone}</a> : null}
                {deal.email ? <a href={`mailto:${deal.email}`}>{deal.email}</a> : null}
                {!deal.contact && !deal.phone && !deal.email ? <span className="muted">No contact details on file</span> : null}
                {deal.geo && deal.geo.lat != null ? <ShowOnMap kind="deal" id={deal.id} /> : null}
              </div>
            </div>
            <div className="file-money">
              <div className="label">{deal.status === "funded" ? "Funded" : "Requested"}</div>
              <div className="amount tnum">{fmt.num(deal.amount) ? <><span className="cur">$</span>{fmt.num(deal.amount).toLocaleString("en-US")}</> : <span className="muted">—</span>}</div>
              <div className="facts tnum">
                {fmt.num(deal.factor) ? <span>Factor <b>{fmt.num(deal.factor).toFixed(2)}</b></span> : null}
                {fmt.num(deal.payback) ? <span>Payback <b>{fmt.moneyShort(deal.payback)}</b></span> : null}
                {deal.status === "funded" ? <span>Repaid <b>{fmt.num(deal.paidPct)}%</b></span> : null}
              </div>
            </div>
          </div>
          {actions.length ? (
            <div className="file-actions">
              {actions.map((a, i) => (
                <button key={a.label} className={`btn btn-sm${i === 0 ? " btn-primary" : ""}`} onClick={a.run} aria-label={a.label}>
                  <Icon name={a.icon} size={15} /><span className="lg">{a.label}</span><span className="sm" aria-hidden="true">{a.short}</span>
                </button>
              ))}
            </div>
          ) : null}
          <CallNotesStrip notes={statements.data && statements.data.callNotes} />
        </div>

        <div className="tabs" role="tablist">
          {tabs.map(t => (
            <button key={t.id} role="tab" className="tab" aria-label={t.n ? `${t.label} ${t.n}` : t.label} aria-selected={tab === t.id} onClick={() => setTab(t.id)}>
              <span className="lg">{t.label}</span><span className="sm" aria-hidden="true">{t.short}</span>{t.n ? <span className="n tnum">{t.n}</span> : null}
            </button>
          ))}
        </div>

        <div className="tab-body scroll" role="tabpanel">
          {loadError ? <div className="banner" role="alert">Couldn't load submissions and activity: {loadError} <button className="link-btn" onClick={loadSide}>Try again</button></div> : null}
          {tab === "overview" ? (
            <OverviewTab deal={deal} subs={subs} activity={activity} team={team} go={setTab} payments={payments} canWrite={canWrite}
              commission={<DealCommissionCard deal={deal} user={user} toast={toast} confirm={confirm} />}
              statementSummary={<StatementOverview statements={statements} onOpen={() => setTab("documents")} />}
              offerLinks={<OfferLinksCard deal={deal} offers={offers} canWrite={canWrite} isAdmin={!!canOf(user).manage} user={user} office={office} toast={toast} confirm={confirm}
                onNew={() => setSheet({ kind: "offer" })} onEdit={(o) => setSheet({ kind: "offer", offer: o })} onChanged={loadSide} onApply={applyTerms} />}
              onLogBounce={() => setSheet({ kind: "bounce" })}
              onRemoveBounce={(p) => confirm({
                title: "Remove this bounced payment?", body: `For one logged by mistake. The ${fmt.money(p.amount)} bounce on ${fmt.day(p.date)} will be taken off this deal and off Home.`, confirmLabel: "Remove",
                onConfirm: async () => { await API.deletePayment(dealId, p.id); await loadSide(); toast("Bounced payment removed"); },
              })}
              onMadeGood={async (p) => { try { await API.updatePayment(dealId, p.id, { status: "made_good" }); await loadSide(); toast("Marked made good"); } catch (e) { toast(e.message, true); } }} />
          ) : null}
          {tab === "submissions" ? <SubmissionsTab subs={subs} dealId={dealId} canWrite={canWrite} onAdd={() => setSheet({ kind: "submission" })} onEdit={s => setSheet({ kind: "submission", submission: s })} onDelete={askDeleteSub} onFund={s => setSheet({ kind: "fund", submission: s })} /> : null}
          {tab === "map" ? <FileMapTab kind="deal" id={deal.id} geo={deal.geo} gplace={deal.gplace} biz={deal.biz} /> : null}
          {tab === "activity" ? <ActivityTab activity={activity} canWrite={canWrite} onAdd={() => setSheet({ kind: "activity" })} /> : null}
          {tab === "documents" ? <DocumentsTab deal={deal} canWrite={canWrite} onUpload={role => setSheet({ kind: "upload", role })} onDelete={askDeleteDoc} statements={statements} toast={toast} /> : null}
          {tab === "portal" ? <PortalTab deal={deal} portal={portal} canWrite={canWrite} isAdmin={!!canOf(user).manage} confirm={confirm} toast={toast} onChanged={() => { loadSide(); refreshDeal(); }} /> : null}
          {tab === "client" ? <ClientTab deal={deal} client={client} deals={deals} canWrite={canWrite} canReveal={!!canOf(user).pii} onCreate={() => setSheet({ kind: "client" })} onEdit={() => setSheet({ kind: "client", client })} onEnter={() => setSheet({ kind: "pii" })}
            onLink={linkClient} onPick={() => setSheet({ kind: "linkClient" })} onDismissMatch={dismissClientMatch} /> : null}
          {tab === "overview" && canDelete ? (
            <div style={{ textAlign: "right" }}><button className="btn btn-sm btn-quiet btn-danger" onClick={askDeleteDeal}><Icon name="trash" size={14} />Delete deal</button></div>
          ) : null}
        </div>
      </section>

      <aside className="context scroll">
        {actions.length ? (
          <div>
            <span className="label">Actions</span>
            <div className="action-grid">
              {actions.map(a => <button key={a.label} className="action" onClick={a.run}><Icon name={a.icon} />{a.label}</button>)}
            </div>
          </div>
        ) : null}
        <CallNotesPanel notes={statements.data && statements.data.callNotes} />
        {best ? (
          <div>
            <span className="label">Best offer</span>
            <div className="offer-card">
              <b>{best.lender}</b>
              <div className="amt tnum">{fmt.money(best.amount)}</div>
              <div style={{ fontSize: 12.5 }} className="dim tnum">
                {[fmt.num(best.factor) ? `Factor ${best.factor}` : "", fmt.num(best.term) ? fmt.term(best.term, best.termUnit) : "", fmt.num(best.payment) ? `${fmt.money(best.payment)} ${String(best.freq || "daily").toLowerCase()}` : ""].filter(Boolean).join(" · ")}
              </div>
            </div>
          </div>
        ) : null}
        <div>
          <span className="label">Assigned rep</span>
          <div className="mini"><div className="mini-row" style={{ display: "flex", alignItems: "center", gap: 10 }}>
            {(() => { const rep = team.find(t => t.id === deal.repId); return rep
              ? <><Avatar name={rep.name} size="sm" /><div><b>{rep.name}</b><div className="when">{rep.role}</div></div></>
              : <span className="muted">{deal.repId ? "Someone outside your team" : "Unassigned · Admins only"}</span>; })()}
          </div></div>
        </div>
        <div>
          <span className="label">Client portal</span>
          <div className="mini"><div className="mini-row">
            {!portal.data ? <span className="muted">…</span> : portal.data.accounts.length
              ? <button className="link-btn" onClick={() => setTab("portal")}>{portal.data.accounts[0].email}{portal.data.checklist && portal.data.checklist.some(i => i.status === "received") ? ` · ${portal.data.checklist.filter(i => i.status === "received").length} to review` : ""}</button>
              : <><span className="muted">No account yet. </span>{canWrite ? <button className="link-btn" onClick={() => setTab("portal")}>Invite</button> : null}</>}
          </div></div>
        </div>
        <div>
          <span className="label">Recent activity</span>
          <div className="mini">
            {activity.length ? activity.slice(0, 5).map((a, i) => (
              <div className="mini-row" key={i}>{a.text}<div className="when">{fmt.when(a.ts)}</div></div>
            )) : <div className="mini-row muted">Nothing logged yet.</div>}
          </div>
        </div>
      </aside>

      {sheet && sheet.kind === "deal" ? <DealSheet deal={deal} team={team} lenders={lenders} subs={subs} user={user} onClose={close} onSaved={d => { close(); saved(d); loadSide(); toast("Deal saved"); }} /> : null}
      {sheet && sheet.kind === "submission" ? (
        <SubmissionSheet deal={deal} submission={sheet.submission} lenders={lenders} onClose={close}
          onSaved={() => { const was = sheet.submission; close(); loadSide(); refreshLenders(); setTab("submissions"); toast(was ? "Submission saved" : "Submission added"); }} />
      ) : null}
      {sheet && sheet.kind === "fund" ? (
        <FundSheet deal={deal} submission={sheet.submission} subs={subs} onClose={close}
          onSaved={async (r) => {
            close();
            if (r && r.newDeal && r.deal) { await loadSide(); onCreated(r.deal); toast(`New funded deal ${r.deal.id} created`); return; }
            if (r && r.deal) saved(r.deal);
            await loadSide(); toast("Marked funded");
          }} />
      ) : null}
      {sheet && sheet.kind === "offer" ? (
        <OfferSheet deal={deal} offer={sheet.offer} subs={subs} user={user} office={office} onClose={close}
          onSaved={async (o) => {
            const was = sheet.offer; close(); await loadSide(); setTab("overview");
            let copied = false;
            if (!was && o && o.url) { try { await navigator.clipboard.writeText(o.url); copied = true; } catch (e) { /* the Copy button is right there */ } }
            toast(was ? "Offer link saved" : copied ? "Offer link created and copied" : "Offer link created");
          }} />
      ) : null}
      {sheet && sheet.kind === "pii" ? <EnterPiiSheet kind="deal" id={deal.id} biz={deal.biz} has={{ ssn: !!(deal.application && deal.application.ssnLast4), ein: !!(deal.application && deal.application.ein), dob: !!(deal.application && deal.application.dob) }} onClose={close} onSaved={() => { close(); refreshDeal(); if (refreshClients) refreshClients(); toast("Saved encrypted"); }} /> : null}
      {sheet && sheet.kind === "bounce" ? <BouncedPaymentSheet deal={deal} onClose={close} onSaved={() => { close(); loadSide(); toast("Bounced payment logged"); }} /> : null}
      {sheet && sheet.kind === "activity" ? <ActivitySheet deal={deal} onClose={close} onSaved={() => { close(); loadSide(); setTab("activity"); toast("Activity logged"); }} /> : null}
      {sheet && sheet.kind === "upload" ? <UploadSheet deal={deal} role={sheet.role} onClose={close} onSaved={() => { close(); refreshDeal(); loadSide(); setTab("documents"); toast("Uploaded"); }} /> : null}
      {sheet && sheet.kind === "linkClient" ? (
        <LinkClientSheet deal={deal} clients={clients} current={deal.clientId || null} canUnlink={deal.status !== "funded"} onClose={close} onLink={linkClient} onUnlink={unlinkClient} />
      ) : null}
      {sheet && sheet.kind === "client" ? (
        <ClientSheet client={sheet.client} seed={{ biz: deal.biz, owner: deal.contact, phone: deal.phone, email: deal.email, ...(deal.application ? { dob: deal.application.dob || "", ein: deal.application.ein && deal.application.ein.length === 9 ? `${deal.application.ein.slice(0, 2)}-${deal.application.ein.slice(2)}` : "" } : {}) }} onClose={close}
          onSaved={async (c) => {
            const created = !sheet.client; close();
            if (created && c && c.id) { try { saved(await API.updateDeal(dealId, { clientId: c.id })); } catch (e) { /* link is optional */ } }
            await refreshClients(); toast(created ? "Client created" : "Client saved");
          }} />
      ) : null}
    </>
  );
}

// ── Deals view ──────────────────────────────────────────────────────────────
function DealsView({ deals, setDeals, loading, selectedId, select, clients, team, lenders, user, office, refreshClients, refreshLenders, toast, confirm, go }) {
  const [creating, setCreating] = useState(false);
  const [exporting, setExporting] = useState(false);
  const [balances, setBalances] = useState({});
  const canWrite = !!canOf(user).write;
  const isAdmin = !!canOf(user).manage;
  useEffect(() => { API.clientBalances().then(setBalances).catch(() => {}); }, [deals.length]);
  const deal = deals.find(d => d.id === selectedId) || null;
  const onChanged = (d) => { if (d && d.id) setDeals(prev => prev.map(x => (x.id === d.id ? (x.offerSeen && !d.offerSeen ? { ...d, offerSeen: x.offerSeen } : d) : x))); };   // offerSeen comes with the list only

  return (
    <main className="workspace" data-view={deal ? "file" : "list"}>
      <DealRail deals={deals} selectedId={selectedId} onSelect={select} onNew={() => setCreating(true)} canWrite={canWrite} loading={loading} balances={balances}
        onImport={isAdmin ? () => go("import") : null} onExport={isAdmin ? () => setExporting(true) : null} />
      {deal ? (
        <DealFile deal={deal} deals={deals} clients={clients} team={team} lenders={lenders} user={user} office={office} canWrite={canWrite} canDelete={canWrite}
          onBack={() => select(null)} onChanged={onChanged}
          onCreated={(d) => { setDeals(prev => [d, ...prev.filter(x => x.id !== d.id)]); select(d.id); }}
          onDeleted={(id) => { setDeals(prev => prev.filter(x => x.id !== id)); select(null); }}
          refreshClients={refreshClients} refreshLenders={refreshLenders} toast={toast} confirm={confirm} />
      ) : (
        <>
          <section className="file"><div className="tab-body" style={{ display: "grid", placeItems: "center", height: "100%" }}>
            {loading ? null : selectedId
              ? <Empty title="That deal isn't here">It may have been deleted. Pick another from the list.</Empty>
              : <Empty title={deals.length ? "Pick a deal" : "Your pipeline is empty"}>{deals.length ? "Choose a deal on the left to open its file." : "Deals you create show up in the list on the left."}</Empty>}
          </div></section>
          <aside className="context" />
        </>
      )}
      {exporting ? <ExportSheet what="deals" onClose={() => setExporting(false)} toast={toast} /> : null}
      {creating ? <DealSheet team={team} lenders={lenders} user={user} onClose={() => setCreating(false)} onSaved={d => {
        // (No object rest here: the in-browser Babel turns it into a top-level helper that clashes between files.)
        const maybe = d.clientSuggestions, deal = Object.assign({}, d); delete deal.clientSuggestions;
        setCreating(false); setDeals(prev => [deal, ...prev]); select(deal.id); toast("Deal created");
        // Not linked to a client for sure, but it looks like one: ask now, while it's fresh.
        const top = Array.isArray(maybe) && maybe[0];
        if (top) confirm({ plain: true, title: "Existing client?", confirmLabel: `Link to ${top.biz}`,
          body: `${deal.biz} looks like ${top.biz} (${top.id}${top.owner ? ", " + top.owner : ""}): ${top.why.join(", ")}. Link this deal to that client file?${maybe.length > 1 ? ` Other possible matches are on the deal's Client tab.` : ""}`,
          onConfirm: async () => { const linked = await API.updateDeal(deal.id, { clientId: top.id }); setDeals(prev => prev.map(x => (x.id === linked.id ? linked : x))); if (refreshClients) await refreshClients(); toast(`Linked to ${top.biz}`); } });
      }} /> : null}
    </main>
  );
}

Object.assign(window, { DealsView, findClient });
