// Bylt Capital CRM — the slide-in forms for deal work.

// Reads a money/number box. Returns { ok, value } — blank becomes 0.
function readNumber(raw, label) {
  const n = fmt.parseMoney(raw);
  if (n === "") return { ok: true, value: 0 };
  if (Number.isNaN(n) || n < 0) return { ok: false, message: `${label} needs to be a number.` };
  return { ok: true, value: n };
}
function readAll(values, spec) {
  const out = {};
  for (const [key, label] of spec) {
    const r = readNumber(values[key], label);
    if (!r.ok) return { error: r.message };
    out[key] = r.value;
  }
  return { out };
}
const show = (n) => (fmt.num(n) ? String(n) : "");

// Payback for a save. If the amount or factor was changed and the payback box
// was left alone, the old payback no longer fits, so it is worked out again.
function settlePayback(n, values, original) {
  const untouched = String(values.payback).trim() === show(original.payback);
  const termsChanged = n.amount !== fmt.num(original.amount) || n.factor !== fmt.num(original.factor);
  if ((!n.payback || (untouched && termsChanged)) && n.amount && n.factor) {
    n.payback = Math.round(n.amount * n.factor * 100) / 100;
  }
}
const same = (a, b) => JSON.stringify(a == null ? null : a) === JSON.stringify(b == null ? null : b);

// ── New / edit deal ─────────────────────────────────────────────────────────
// `seed` prefills a new deal (from a client's file); `extra` goes with it when it is created (its clientId).
function DealSheet({ deal, team, lenders, subs, user, onClose, onSaved, seed, extra }) {
  const editing = !!deal;
  const d = deal || seed || {};
  const isAdmin = !!canOf(user).manage, wide = !!canOf(user).wide;
  const [v, set] = useForm({
    biz: d.biz || "", contact: d.contact || "", phone: d.phone || "", email: d.email || "",
    amount: show(d.amount), factor: show(d.factor), term: show(d.term), termUnit: d.termUnit || "days", daily: show(d.daily),
    payback: show(d.payback), paidPct: show(d.paidPct),
    status: d.status || "new", source: d.source || "", repId: d.repId || (!editing && user && !wide ? user.id : ""),
    brokered: !!(d.broker && d.broker.isBrokered), bankNotes: d.bankNotes || "", funder: d.funder || "",
    fundedOn: d.status === "funded" ? fmt.localDay(d.fundedAt) : "",
  });
  const save = useSave(onSaved);
  // Others also working this deal (a split). They see it too. Admins decide who.
  const [coReps, setCoReps] = useState(Array.isArray(d.coRepIds) ? d.coRepIds : []);
  // Set when the server says this business is already in the system: { message, dealId? }
  const [dup, setDup] = useState(null);
  const dupRef = useRef(null);
  useEffect(() => { if (dup && dupRef.current) dupRef.current.scrollIntoView({ block: "start", behavior: "smooth" }); }, [dup]);
  const caught = (err) => {
    if (err.status === 409 && err.data && err.data.duplicate) { setDup({ message: err.message, dealId: err.data.dealId || null }); throw Object.assign(new Error("duplicate"), { quiet: true }); }
    throw err;
  };

  // Marking a deal funded: suggest the lender whose approval is on file.
  const setStatus = (x) => {
    set("status", x);
    if (x === "funded" && !v.funder) {
      const approved = (subs || []).filter(s => s.status === "approved").sort((a, b) => fmt.num(b.amount) - fmt.num(a.amount))[0];
      if (approved) set("funder", approved.lender);
    }
  };
  const funderOptions = [{ value: "", label: "Not recorded" }, { value: "Bylt Capital", label: "Bylt Capital (we funded it)" }]
    .concat((lenders || []).map(l => ({ value: l.name, label: l.name })));
  if (v.funder && !funderOptions.some(o => o.value === v.funder)) funderOptions.push({ value: v.funder, label: v.funder });

  const statusOptions = DEAL_STATUSES.map(s => ({ value: s.id, label: s.label }));
  if (!DEAL_STATUSES.some(s => s.id === v.status)) statusOptions.push({ value: v.status, label: fmt.title(v.status) });
  // Only an Admin can leave a deal with nobody on it (it then shows for Admins only).
  // People who can no longer sign in aren't offered, but stay shown where they already are.
  const repOptions = (wide || !v.repId ? [{ value: "", label: wide ? "Unassigned (Admins only)" : "Unassigned" }] : []).concat(team.filter(t => t.active !== false || t.id === v.repId).map(t => ({ value: t.id, label: t.active === false ? `${t.name} (no longer signs in)` : t.name })));
  if (v.repId && !team.some(t => t.id === v.repId)) repOptions.push({ value: v.repId, label: "Someone outside your team" });
  const coChoices = team.filter(t => t.id !== v.repId && (t.active !== false || coReps.includes(t.id)));

  const submit = (anyway) => {
    if (!v.biz.trim()) return save.setError("Enter the business name.");
    const nums = readAll(v, [["amount", "Amount"], ["factor", "Factor"], ["term", "Term"], ["daily", "Payment"], ["payback", "Payback"], ["paidPct", "Percent repaid"]]);
    if (nums.error) return save.setError(nums.error);
    const n = nums.out;
    if (n.paidPct > 100) return save.setError("Percent repaid can't be more than 100.");
    settlePayback(n, v, d);
    const body = {
      biz: v.biz.trim(), contact: v.contact.trim(), phone: v.phone.trim(), email: v.email.trim(),
      ...n, termUnit: v.termUnit, status: v.status, source: v.source.trim() || "Manual", repId: v.repId || null,
      broker: { ...(d.broker || {}), isBrokered: v.brokered }, bankNotes: v.bankNotes, funder: v.funder,
    };
    // Left blank, the server dates the funding at the moment the deal is marked funded.
    if (v.status === "funded" && (v.fundedOn || editing)) body.fundedAt = v.fundedOn;
    if (isAdmin) body.coRepIds = coReps.filter(id => id !== body.repId);
    if (!editing) {
      if (anyway === true) body.allowDuplicate = true;
      if (extra && typeof extra === "object") Object.assign(body, extra);
      setDup(null);
      return save.run(() => API.createDeal(body).catch(caught));
    }
    // Send only the fields that were changed here, so an edit never puts back
    // an older value over something a colleague or Grok changed meanwhile.
    const before = { ...d, status: d.status || "new", repId: d.repId || null, coRepIds: Array.isArray(d.coRepIds) ? d.coRepIds : [], broker: { ...(d.broker || {}), isBrokered: !!(d.broker && d.broker.isBrokered) } };
    for (const k of ["amount", "factor", "term", "daily", "payback", "paidPct"]) before[k] = fmt.num(d[k]);
    for (const k of ["biz", "contact", "phone", "email", "bankNotes", "funder"]) before[k] = d[k] || "";
    before.source = d.source || "Manual";
    before.termUnit = d.termUnit || "days";
    before.fundedAt = d.status === "funded" ? fmt.localDay(d.fundedAt) : "";
    const changes = Object.fromEntries(Object.entries(body).filter(([k, val]) => !same(val, before[k])));
    if (!Object.keys(changes).length) return onClose();
    // Renaming a deal into a business someone else is working gets the same stop as creating one.
    if (anyway === true) changes.allowDuplicate = true;
    setDup(null);
    save.run(() => API.updateDeal(d.id, changes).catch(caught));
  };

  return (
    <Sheet eyebrow={editing ? `Deal ${d.id}` : "Deals"} title={editing ? "Edit deal" : "New deal"}
           onClose={onClose} onSubmit={() => submit()} submitLabel={editing ? "Save deal" : "Create deal"} busy={save.busy} error={save.error}>
      {dup ? (
        <div className="form-section" ref={dupRef}>
          <div className="banner" role="alert">
            <b>{dup.message}</b>
            <div style={{ marginTop: 6 }}>
              {dup.dealId ? <a href={`#/deals/${encodeURIComponent(dup.dealId)}`} onClick={onClose}>Open that deal</a> : "You can't see the other file, so check with an Admin first."}
              {" "}If this really is a separate deal, you can still {editing ? "save it" : "create it"}{isAdmin ? "." : "; Admins are told."}
            </div>
            <button type="button" className="btn btn-sm" style={{ marginTop: 10 }} disabled={save.busy} onClick={() => submit(true)}>{editing ? "Save anyway" : "Create anyway"}</button>
          </div>
        </div>
      ) : null}
      <div className="form-section">
        <span className="label">Business</span>
        <div className="form-grid">
          <Field label="Business name" full><TextInput value={v.biz} onChange={x => set("biz", x)} placeholder="Legal or trading name" /></Field>
          <Field label="Owner / contact"><TextInput value={v.contact} onChange={x => set("contact", x)} /></Field>
          <Field label="Phone"><TextInput value={v.phone} onChange={x => set("phone", x)} type="tel" inputMode="tel" /></Field>
          <Field label="Email" full><TextInput value={v.email} onChange={x => set("email", x)} type="email" /></Field>
        </div>
      </div>
      <div className="form-section">
        <span className="label">Terms</span>
        <div className="form-grid">
          <Field label="Amount"><TextInput value={v.amount} onChange={x => set("amount", x)} inputMode="decimal" placeholder="$" /></Field>
          <Field label="Factor"><TextInput value={v.factor} onChange={x => set("factor", x)} inputMode="decimal" placeholder="1.28" /></Field>
          <Field label="Term"><TermInput value={v.term} unit={v.termUnit} onChange={x => set("term", x)} onUnit={x => set("termUnit", x)} /></Field>
          <Field label="Daily payment"><TextInput value={v.daily} onChange={x => set("daily", x)} inputMode="decimal" placeholder="$" /></Field>
          <Field label="Payback" hint="Leave blank to use amount × factor."><TextInput value={v.payback} onChange={x => set("payback", x)} inputMode="decimal" placeholder="$" /></Field>
          <Field label="Percent repaid"><TextInput value={v.paidPct} onChange={x => set("paidPct", x)} inputMode="numeric" placeholder="0–100" /></Field>
        </div>
      </div>
      <div className="form-section">
        <span className="label">Pipeline</span>
        <div className="form-grid">
          <Field label="Status"><Select value={v.status} onChange={setStatus} options={statusOptions} /></Field>
          <Field label="Assigned rep" hint={wide && !v.repId ? "With nobody assigned, only Admins and Assistants see this deal." : null}><Select value={v.repId} onChange={x => set("repId", x)} options={repOptions} /></Field>
          {v.status === "funded" ? (
            <Field label="Funded by" full hint="Pick Bylt Capital when you funded it yourself. That turns on bounced-payment tracking for this deal.">
              <Select value={v.funder} onChange={x => set("funder", x)} options={funderOptions} />
            </Field>
          ) : null}
          {v.status === "funded" ? (
            <Field label="Funded on" hint={editing && d.status === "funded" ? "Decides which month's total this deal counts in." : "Leave blank if it funded today."}>
              <TextInput value={v.fundedOn} onChange={x => set("fundedOn", x)} type="date" />
            </Field>
          ) : null}
          {isAdmin && coChoices.length ? (
            <div className="field full">
              <span className="label">Also on this deal</span>
              <div className="check-row" role="group" aria-label="Also on this deal" style={{ marginTop: 6 }}>
                {coChoices.map(t => (
                  <label key={t.id}><input type="checkbox" checked={coReps.includes(t.id)} onChange={e => setCoReps(list => (e.target.checked ? list.concat([t.id]) : list.filter(x => x !== t.id)))} /> {t.name}</label>
                ))}
              </div>
              <div className="hint">For a split. They see this deal too, along with their own team leader. Anyone given a share of the commission is added here automatically.</div>
            </div>
          ) : null}
          <Field label="Source" full><TextInput value={v.source} onChange={x => set("source", x)} placeholder="Referral, web, partner name…" /></Field>
          <label className="check full">
            <input type="checkbox" checked={v.brokered} onChange={e => set("brokered", e.target.checked)} />
            Brokered out to other lenders
          </label>
        </div>
      </div>
      <div className="form-section">
        <Field label="Bank notes"><textarea className="textarea" value={v.bankNotes} onChange={e => set("bankNotes", e.target.value)} placeholder="Average deposits, NSFs, positions…" /></Field>
      </div>
    </Sheet>
  );
}

// ── Add / edit lender submission ────────────────────────────────────────────
function SubmissionSheet({ deal, submission, lenders, onClose, onSaved }) {
  const editing = !!submission;
  const s = submission || {};
  const [v, set] = useForm({
    lender: s.lender || "", status: s.status || "offer",
    amount: show(s.amount), factor: show(s.factor), term: show(s.term), termUnit: s.termUnit || "days", freq: s.freq || "Daily",
    payment: show(s.payment), payback: show(s.payback), upsell: show(s.upsell),
    stips: (s.stips || []).join("\n"), notes: s.notes || "", expiresAt: s.expiresAt || "",
  });
  const save = useSave(onSaved);
  const declined = v.status === "declined";

  const submit = () => {
    if (!v.lender.trim()) return save.setError("Enter the lender's name.");
    const nums = readAll(v, [["amount", "Amount"], ["factor", "Factor"], ["term", "Term"], ["payment", "Payment"], ["payback", "Payback"], ["upsell", "Upsell"]]);
    if (nums.error) return save.setError(nums.error);
    const n = nums.out;
    settlePayback(n, v, s);
    const body = {
      lender: v.lender.trim(), status: v.status, ...n, termUnit: v.termUnit, freq: v.freq,
      stips: v.stips.split("\n").map(x => x.trim()).filter(Boolean), notes: v.notes,
      expiresAt: declined ? "" : v.expiresAt,
    };
    save.run(() => (editing ? API.updateSubmission(deal.id, s.id, body) : API.addSubmission(deal.id, body)));
  };

  return (
    <Sheet eyebrow={deal.biz} title={editing ? "Edit submission" : "Add submission"}
           onClose={onClose} onSubmit={submit} submitLabel={editing ? "Save submission" : "Add submission"} busy={save.busy} error={save.error}>
      <div className="form-section">
        <span className="label">Lender response</span>
        <div className="form-grid">
          <Field label="Lender" full hint="A new name is added to your lender list.">
            <input className="input" list="ef-lenders" value={v.lender} onChange={e => set("lender", e.target.value)} placeholder="Start typing…" autoComplete="off" />
            <datalist id="ef-lenders">{lenders.map(l => <option key={l.id} value={l.name} />)}</datalist>
          </Field>
          <div className="field full">
            <span className="label">Status</span>
            {s.status === "funded"
              ? <div className="hint" style={{ marginTop: 6 }}><Pill status="funded" label="Funded" /> Set by Mark funded. To undo it, change the funded deal's status.</div>
              : <Segmented value={v.status} onChange={x => set("status", x)} options={SUB_STATUSES.filter(o => o.id !== "funded")} label="Status" />}
          </div>
        </div>
      </div>
      {declined ? null : (
        <div className="form-section">
          <span className="label">Offer terms</span>
          <div className="form-grid">
            <Field label="Amount"><TextInput value={v.amount} onChange={x => set("amount", x)} inputMode="decimal" placeholder="$" /></Field>
            <Field label="Factor"><TextInput value={v.factor} onChange={x => set("factor", x)} inputMode="decimal" placeholder="1.28" /></Field>
            <Field label="Term"><TermInput value={v.term} unit={v.termUnit} onChange={x => set("term", x)} onUnit={x => set("termUnit", x)} /></Field>
            <Field label="Payment frequency">
              <Select value={v.freq} onChange={x => set("freq", x)} options={["Daily", "Weekly", "Bi-Weekly", "Monthly"].map(x => ({ value: x, label: x }))} />
            </Field>
            <Field label="Payment"><TextInput value={v.payment} onChange={x => set("payment", x)} inputMode="decimal" placeholder="$" /></Field>
            <Field label="Payback" hint="Leave blank to use amount × factor."><TextInput value={v.payback} onChange={x => set("payback", x)} inputMode="decimal" placeholder="$" /></Field>
            <Field label="Upsell (points)"><TextInput value={v.upsell} onChange={x => set("upsell", x)} inputMode="decimal" /></Field>
            <Field label="Good until" hint="Home warns you the day before it runs out."><TextInput value={v.expiresAt} onChange={x => set("expiresAt", x)} type="date" /></Field>
          </div>
        </div>
      )}
      <div className="form-section">
        <div className="form-grid">
          {declined ? null : (
            <Field label="Stipulations" full hint="One per line.">
              <textarea className="textarea" value={v.stips} onChange={e => set("stips", e.target.value)} placeholder={"3 months bank statements\nVoided check"} />
            </Field>
          )}
          <Field label={declined ? "Decline reason / notes" : "Notes"} full>
            <textarea className="textarea" value={v.notes} onChange={e => set("notes", e.target.value)} />
          </Field>
        </div>
      </div>
    </Sheet>
  );
}

// ── Mark a lender response funded ───────────────────────────────────────────
// Funds the deal on this lender's terms, links the response to a funding
// already entered by hand, or (deal already funded by someone else) opens a
// separate funded deal for the same business.
function FundSheet({ deal, submission, subs, onClose, onSaved }) {
  const s = submission;
  const key = (x) => String(x || "").trim().toLowerCase().replace(/[^a-z0-9]+/g, " ");
  const linked = (subs || []).some(x => x.status === "funded" && x.fundedDealId === deal.id);
  const initial = deal.status !== "funded" ? "fund" : (key(deal.funder) === key(s.lender) && !linked ? "link" : "new");
  const [mode, setMode] = useState(initial);
  const [day, setDay] = useState(fmt.localDay(new Date().toISOString()));
  const save = useSave(onSaved);
  const submit = () => {
    const body = mode === "new" ? { asNewDeal: true, fundedAt: day } : mode === "fund" ? { fundedAt: day } : {};
    save.run(() => API.fundSubmission(deal.id, s.id, body).catch(err => {
      if (err.status === 409 && err.data && err.data.needsNewDeal) { setMode("new"); throw Object.assign(new Error(err.message), { quiet: false }); }
      throw err;
    }));
  };
  const payback = fmt.num(s.payback) || (fmt.num(s.amount) && fmt.num(s.factor) ? Math.round(fmt.num(s.amount) * fmt.num(s.factor) * 100) / 100 : 0);
  return (
    <Sheet eyebrow={deal.biz} title={`Mark ${s.lender} funded`} onClose={onClose} onSubmit={submit}
           submitLabel={mode === "new" ? "Create funded deal" : mode === "link" ? "Mark funded" : "Mark deal funded"} busyLabel="Saving…" busy={save.busy} error={save.error}>
      <div className="form-section">
        {mode === "new" ? (
          <div className="banner info">This deal is already funded{deal.funder ? <> by <b>{deal.funder}</b></> : null}. {s.lender}'s funding becomes a <b>separate funded deal</b> for {deal.biz}, with the same rep, split and client record, and its own commission.</div>
        ) : mode === "link" ? (
          <div className="banner info">This deal is already marked funded by {deal.funder}. The response is linked to that funding; the deal's terms stay as entered.</div>
        ) : (
          <div className="banner info">The deal becomes <b>Funded</b> on these terms, with {s.lender} as the funder. Its commission record is started.</div>
        )}
      </div>
      <div className="form-section">
        <span className="label">Terms</span>
        <dl className="kv-list">
          <div className="kv"><dt>Amount</dt><dd className="tnum">{fmt.money(s.amount)}</dd></div>
          {fmt.num(s.factor) ? <div className="kv"><dt>Factor</dt><dd className="tnum">{s.factor}</dd></div> : null}
          {fmt.num(s.term) ? <div className="kv"><dt>Term</dt><dd className="tnum">{fmt.term(s.term, s.termUnit)}</dd></div> : null}
          {fmt.num(s.payment) ? <div className="kv"><dt>Payment</dt><dd className="tnum">{fmt.money(s.payment)} {String(s.freq || "Daily").toLowerCase()}</dd></div> : null}
          {payback ? <div className="kv"><dt>Payback</dt><dd className="tnum">{fmt.money(payback)}</dd></div> : null}
        </dl>
        <div className="hint lh" style={{ marginTop: 8 }}>Wrong figures? Cancel, edit the response, then mark it funded.</div>
      </div>
      {mode !== "link" ? (
        <div className="form-section">
          <div className="form-grid">
            <Field label="Funded on" hint="Decides which month's total it counts in."><TextInput value={day} onChange={setDay} type="date" /></Field>
          </div>
        </div>
      ) : null}
    </Sheet>
  );
}

// ── Log activity ────────────────────────────────────────────────────────────
const ACTIVITY_KINDS = [
  { id: "NOTE", label: "Note" }, { id: "CALL", label: "Call" }, { id: "EMAIL", label: "Email" }, { id: "TEXT", label: "Text" },
];
function ActivitySheet({ deal, onClose, onSaved }) {
  const [kind, setKind] = useState("NOTE");
  const [text, setText] = useState("");
  const save = useSave(onSaved);
  const submit = () => {
    if (!text.trim()) return save.setError("Write what happened.");
    save.run(() => API.addActivity(deal.id, { text: text.trim(), tag: kind }));
  };
  return (
    <Sheet eyebrow={deal.biz} title="Log activity" onClose={onClose} onSubmit={submit} submitLabel="Log activity" busy={save.busy} error={save.error}>
      <div className="form-section">
        <div className="field" style={{ marginBottom: 16 }}>
          <span className="label">Type</span>
          <Segmented value={kind} onChange={setKind} options={ACTIVITY_KINDS} label="Type" />
        </div>
        <Field label="What happened">
          <textarea className="textarea" style={{ minHeight: 160 }} value={text} onChange={e => setText(e.target.value)} placeholder="Spoke with the owner about…" />
        </Field>
      </div>
    </Sheet>
  );
}

// ── Upload document ─────────────────────────────────────────────────────────
const DOC_ROLES = [
  { value: "statement", label: "Bank statement" },
  { value: "contract", label: "Contract" },
  { value: "dl-front", label: "Driver license, front" },
  { value: "dl-back", label: "Driver license, back" },
  { value: "voided-check", label: "Voided check" },
  { value: "tax-return", label: "Tax return" },
  { value: "profit-loss", label: "Profit and loss" },
  { value: "balance-sheet", label: "Balance sheet" },
  { value: "cc-processing", label: "CC processing statement" },
  { value: "personal-tax-return", label: "Personal tax return" },
  { value: "debt-schedule", label: "Debt schedule" },
  { value: "pfs", label: "Personal financial statement (SBA 413)" },
  { value: "sba-1919", label: "SBA Form 1919" },
  { value: "entity-docs", label: "Formation documents" },
  { value: "resume", label: "Owner resume" },
  { value: "lease", label: "Lease" },
  { value: "business-plan", label: "Business plan" },
  { value: "ar-aging", label: "AR aging report" },
  { value: "invoices", label: "Invoices" },
  { value: "customer-list", label: "Customer list" },
  { value: "other", label: "Other" },
];
const MAX_UPLOAD = 25 * 1024 * 1024;
function UploadSheet({ deal, role, onClose, onSaved }) {
  const [kind, setKind] = useState(role || "statement");
  const [files, setFiles] = useState([]);
  const [over, setOver] = useState(false);
  const input = useRef(null);
  const save = useSave(onSaved);
  const single = ["dl-front", "dl-back", "voided-check"].includes(kind);

  const pick = (list) => {
    const arr = Array.from(list || []);
    const big = arr.find(f => f.size > MAX_UPLOAD);
    if (big) return save.setError(`${big.name} is over 25 MB.`);
    save.setError("");
    setFiles(single ? arr.slice(0, 1) : arr);
  };
  const submit = () => {
    if (!files.length) return save.setError("Choose a file to upload.");
    save.run(async () => { for (const f of (single ? files.slice(0, 1) : files)) await API.uploadDocument(deal.id, f, kind); });
  };

  return (
    <Sheet eyebrow={deal.biz} title="Upload document" onClose={onClose} onSubmit={submit}
           submitLabel={files.length > 1 ? `Upload ${files.length} files` : "Upload"} busy={save.busy} error={save.error}>
      <div className="form-section">
        <Field label="Document type">
          <Select value={kind} onChange={(x) => { setKind(x); setFiles(f => f.slice(0, 1)); }} options={DOC_ROLES} />
        </Field>
      </div>
      <div className="form-section">
        <div className={`drop${over ? " over" : ""}`}
             onDragOver={e => { e.preventDefault(); setOver(true); }} onDragLeave={() => setOver(false)}
             onDrop={e => { e.preventDefault(); setOver(false); pick(e.dataTransfer.files); }}>
          {files.length
            ? files.map(f => <div key={f.name + f.size}><b>{f.name}</b> <span className="muted">· {(f.size / 1024 / 1024).toFixed(1)} MB</span></div>)
            : <div><b>Drop {single ? "a file" : "files"} here</b><br />PDF or image, up to 25 MB each</div>}
          <div style={{ marginTop: 12 }}>
            <button type="button" className="btn btn-sm" onClick={() => input.current.click()}>{files.length ? "Choose different" : "Choose file"}</button>
          </div>
          <input ref={input} type="file" hidden multiple={!single} onChange={e => pick(e.target.files)} />
        </div>
        {single && deal.documents && deal.documents[{ "dl-front": "dlFront", "dl-back": "dlBack", "voided-check": "check" }[kind]]
          ? <p className="hint" style={{ marginTop: 10, fontSize: 12.5, color: "var(--ink-mute)" }}>This replaces the file already in that slot.</p> : null}
      </div>
    </Sheet>
  );
}

// ── Client record ───────────────────────────────────────────────────────────
function ClientSheet({ client, seed, onClose, onSaved, onDelete }) {
  const editing = !!client;
  const c = client || seed || {};
  const [v, set] = useForm({
    biz: c.biz || "", owner: c.owner || "", phone: c.phone || "", email: c.email || "",
    dob: c.dob || "", ein: c.ein || "", address: c.address || "",
  });
  const save = useSave(onSaved);
  const submit = () => {
    if (!v.biz.trim()) return save.setError("Enter the business name.");
    const dob = v.dob.trim().match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
    if (v.dob.trim() && !(dob && +dob[1] >= 1 && +dob[1] <= 12 && +dob[2] >= 1 && +dob[2] <= new Date(+dob[3], +dob[1], 0).getDate())) return save.setError("Date of birth should be a real date like 06/14/1978.");
    const body = Object.fromEntries(Object.entries(v).map(([k, x]) => [k, String(x).trim()]));
    save.run(() => (editing ? API.updateClient(client.id, body) : API.createClient(body)));
  };
  return (
    <Sheet eyebrow="Clients" title={editing ? "Edit client" : "New client"} onClose={onClose} onSubmit={submit}
           submitLabel={editing ? "Save client" : "Create client"} busy={save.busy} error={save.error}
           danger={editing && onDelete ? <button type="button" className="btn btn-danger" style={{ marginRight: "auto" }} onClick={onDelete}>Delete</button> : null}>
      <div className="form-section">
        <span className="label">Business</span>
        <div className="form-grid">
          <Field label="Business name" full><TextInput value={v.biz} onChange={x => set("biz", x)} /></Field>
          <Field label="EIN"><TextInput value={v.ein} onChange={x => set("ein", x)} placeholder="12-3456789" /></Field>
          <Field label="Address" full><TextInput value={v.address} onChange={x => set("address", x)} /></Field>
        </div>
      </div>
      <div className="form-section">
        <span className="label">Owner</span>
        <div className="form-grid">
          <Field label="Owner name" full><TextInput value={v.owner} onChange={x => set("owner", x)} /></Field>
          <Field label="Phone"><TextInput value={v.phone} onChange={x => set("phone", x)} type="tel" inputMode="tel" /></Field>
          <Field label="Email"><TextInput value={v.email} onChange={x => set("email", x)} type="email" /></Field>
          <Field label="Date of birth" hint="Used for renewal reminders."><TextInput value={v.dob} onChange={x => set("dob", x)} placeholder="MM/DD/YYYY" /></Field>
        </div>
      </div>
    </Sheet>
  );
}

// ── Lead ────────────────────────────────────────────────────────────────────
function LeadSheet({ lead, team, user, onClose, onSaved }) {
  const editing = !!lead;
  const l = lead || {};
  const isAdmin = !!canOf(user).manage, wide = !!canOf(user).wide;
  const people = team || [];
  const ownerOptions = (wide || (editing && !l.repId) ? [{ value: "", label: wide ? "Unassigned (Admins only)" : "Unassigned" }] : []).concat(people.filter(t => t.active !== false || t.id === l.repId).map(t => ({ value: t.id, label: t.name })));
  if (l.repId && !people.some(t => t.id === l.repId)) ownerOptions.push({ value: l.repId, label: "Someone outside your team" });
  const [v, set] = useForm({
    repId: l.repId || (!editing && user && !wide ? user.id : ""),
    biz: l.biz || l.businessName || "", name: l.name || l.ownerName || "", phone: l.phone || "", email: l.email || "",
    amount: show(l.fundingAmount || l.amount), source: l.source || "", note: l.note || l.notes || "",
  });
  const save = useSave(onSaved);
  const submit = () => {
    if (!v.biz.trim() && !v.name.trim()) return save.setError("Enter a business name or a contact name.");
    const amt = readNumber(v.amount, "Amount wanted");
    if (!amt.ok) return save.setError(amt.message);
    const body = { biz: v.biz.trim(), name: v.name.trim(), phone: v.phone.trim(), email: v.email.trim(), fundingAmount: amt.value, source: v.source.trim() || "Manual", note: v.note };
    if (!editing || (v.repId || null) !== (l.repId || null)) body.repId = v.repId || null;
    save.run(() => (editing ? API.updateLead(l.id, body) : API.createLead(body)));
  };
  return (
    <Sheet eyebrow="Leads" title={editing ? "Edit lead" : "New lead"} onClose={onClose} onSubmit={submit}
           submitLabel={editing ? "Save lead" : "Create lead"} busy={save.busy} error={save.error}>
      <div className="form-section">
        <div className="form-grid">
          <Field label="Business name" full><TextInput value={v.biz} onChange={x => set("biz", x)} /></Field>
          <Field label="Contact name" full><TextInput value={v.name} onChange={x => set("name", x)} /></Field>
          <Field label="Phone"><TextInput value={v.phone} onChange={x => set("phone", x)} type="tel" inputMode="tel" /></Field>
          <Field label="Email"><TextInput value={v.email} onChange={x => set("email", x)} type="email" /></Field>
          <Field label="Amount wanted"><TextInput value={v.amount} onChange={x => set("amount", x)} inputMode="decimal" placeholder="$" /></Field>
          <Field label="Source"><TextInput value={v.source} onChange={x => set("source", x)} placeholder="Web, referral…" /></Field>
          {ownerOptions.length > 1 || wide ? (
            <Field label="Assigned to" full hint={wide ? "Whoever it is assigned to sees it, and so does their team leader. Unassigned leads show for Admins and Assistants only." : null}>
              <Select value={v.repId} onChange={x => set("repId", x)} options={ownerOptions} />
            </Field>
          ) : null}
          <Field label="Notes" full><textarea className="textarea" value={v.note} onChange={e => set("note", e.target.value)} /></Field>
        </div>
      </div>
    </Sheet>
  );
}

// ── Bounced payment (deals Bylt Capital funded itself) ───────────────────────
const BOUNCE_REASONS = ["NSF", "Account closed", "Stop payment", "Account frozen", "Other"];
function BouncedPaymentSheet({ deal, onClose, onSaved }) {
  const today = new Date(); const pad = (n) => String(n).padStart(2, "0");
  const [v, set] = useForm({ date: `${today.getFullYear()}-${pad(today.getMonth() + 1)}-${pad(today.getDate())}`, amount: show(deal.daily), reason: "NSF", note: "" });
  const save = useSave(onSaved);
  const submit = () => {
    if (!/^\d{4}-\d{2}-\d{2}$/.test(v.date)) return save.setError("Pick the date the payment bounced.");
    const amt = readNumber(v.amount, "Amount");
    if (!amt.ok) return save.setError(amt.message);
    save.run(() => API.addPayment(deal.id, { date: v.date, amount: amt.value, reason: v.reason, note: v.note }));
  };
  return (
    <Sheet eyebrow={deal.biz} title="Log bounced payment" onClose={onClose} onSubmit={submit} submitLabel="Log bounced payment" busy={save.busy} error={save.error}>
      <div className="form-section">
        <div className="form-grid">
          <Field label="Date it bounced"><TextInput value={v.date} onChange={x => set("date", x)} type="date" /></Field>
          <Field label="Amount"><TextInput value={v.amount} onChange={x => set("amount", x)} inputMode="decimal" placeholder="$" /></Field>
          <Field label="Reason" full><Select value={v.reason} onChange={x => set("reason", x)} options={BOUNCE_REASONS.map(x => ({ value: x, label: x }))} /></Field>
          <Field label="Notes" full><textarea className="textarea" value={v.note} onChange={e => set("note", e.target.value)} placeholder="What the merchant said, when they will make it good…" /></Field>
        </div>
      </div>
    </Sheet>
  );
}

Object.assign(window, { BouncedPaymentSheet, FundSheet, DealSheet, SubmissionSheet, ActivitySheet, UploadSheet, ClientSheet, LeadSheet, DOC_ROLES });
