// Installments — shared pool + purchase contracts
const INST_TODAY = new Date(2026, 6, 27);
const instTone = (s) => (s === "Completed" ? "green" : s === "Overdue" ? "red" : "blue");
const contractTotal = (c) => c.items.reduce((s, i) => s + i.qty * i.price, 0);

function PersonModal({ open, person, prefillName, onClose, onSave }) {
  const { useState, useEffect } = React;
  const [f, setF] = useState({ name: "", phone: "", email: "", note: "" });
  const [err, setErr] = useState("");
  useEffect(() => { if (open) { setF(person ? { ...person } : { name: prefillName || "", phone: "", email: "", note: "" }); setErr(""); } }, [open, person]);
  if (!open) return null;
  const save = () => {
    if (!f.name.trim()) { setErr(T("inst.errEnterName")); return; }
    onSave({ ...f, name: f.name.trim(), id: person ? person.id : "P-" + String(D.poolPeople.length + 1).padStart(2, "0") });
  };
  return (
    <Modal open={true} onClose={onClose} title={person ? T("common.editItem", { name: person.name }) : T("inst.addBuyer")} width={440} z={150}
      footer={<div className="btnrow"><Btn onClick={onClose}>{T("common.cancel")}</Btn><Btn variant="primary" icon="check" onClick={save}>{person ? T("common.saveChanges") : T("inst.addBuyer")}</Btn></div>}>
      <Field label={T("common.fullName")} error={err}><Input value={f.name} onChange={(e) => setF({ ...f, name: e.target.value })} autoFocus /></Field>
      <div className="formgrid">
        <Field label={T("common.phone")}><Input value={f.phone} onChange={(e) => setF({ ...f, phone: e.target.value })} /></Field>
        <Field label={T("common.email")}><Input type="email" value={f.email} onChange={(e) => setF({ ...f, email: e.target.value })} /></Field>
      </div>
      <Field label={T("common.noteOptional")}><Input value={f.note} onChange={(e) => setF({ ...f, note: e.target.value })} /></Field>
    </Modal>
  );
}

function PeopleTab({ people, contribs, contracts, onAdd, onEdit }) {
  const { useState } = React;
  const [openRow, setOpenRow] = useState(null);
  const owes = (name) => contracts.reduce((s, c) => { const sh = c.shares.find((x) => x.person === name); return s + (sh ? Math.round(contractTotal(c) * (1 + (c.interest || 0) / 100) * sh.pct / 100) : 0); }, 0);
  const inContracts = (name) => contracts.filter((c) => c.shares.some((x) => x.person === name)).length;
  return (
    <div>
      <div className="toolbar page-toolbar">
        <span className="dim" style={{ fontSize: 13 }}>{T("inst.buyersHint", { n: people.length })}</span>
        <Btn variant="primary" icon="plus" onClick={onAdd}>{T("inst.addBuyer")}</Btn>
      </div>
      <section className="card">
        <DataTable tableId="pool-people" rowKey={(r) => r.id} rows={people} onRow={(r) => setOpenRow(openRow === r.id ? null : r.id)} empty={T("inst.noBuyers")}
          expanded={(r) => {
            if (openRow !== r.id) return null;
            const mine = contracts.filter((c) => c.shares.some((x) => x.person === r.name));
            return (
              <div className="paytx">
                {mine.length === 0 ? <p className="dim" style={{ margin: "2px 0 10px", fontSize: 13 }}>{T("inst.noPurchasesYet")}</p> : mine.map((c) => {
                  const total = contractTotal(c);
                  const sh = c.shares.find((x) => x.person === r.name);
                  return (
                    <div className="ep-list" style={{ marginBottom: 10 }} key={c.id}>
                      <div className="ep-row" style={{ gridTemplateColumns: "1fr auto auto auto", gap: 14 }}>
                        <span><b>{c.id}</b>{c.note ? <span className="dim"> · {c.note}</span> : null}</span>
                        <span className="dim mono">{c.date}</span>
                        <span className="mono strong">{T("inst.owesAmount", { amount: money(Math.round(total * (1 + (c.interest || 0) / 100) * sh.pct / 100)) })}</span>
                      </div>
                      {c.items.map((i, idx) => (
                        <div className="ep-row" style={{ gridTemplateColumns: "1fr 70px 110px 110px" }} key={idx}>
                          <span className="dim">{i.name}</span>
                          <span className="ta-c mono">×{i.qty}</span>
                          <span className="ta-r mono">{money(i.price)}</span>
                          <span className="ta-r mono">{money(i.qty * i.price)}</span>
                        </div>
                      ))}
                      <div className="ep-row" style={{ gridTemplateColumns: "1fr auto" }}>
                        <span className="dim">{T("inst.contractTotal")}</span>
                        <span className="mono strong">{money(total)}</span>
                      </div>
                    </div>
                  );
                })}
                <div className="btnrow">
                  <Btn small icon="cog" onClick={(e) => { e.stopPropagation(); onEdit(r); }}>{T("inst.editProfile")}</Btn>
                </div>
              </div>
            );
          }}
          cols={[
          { k: "name", label: T("inst.buyer"), render: (r) => <span className="cellwho"><Avatar name={r.name} size={28} /><span className="who2"><b>{r.name}</b><small className="dim">{r.note || r.id}</small></span></span> },
          { k: "phone", label: T("common.phone"), w: "140px", render: (r) => r.phone ? <span className="mono dim">{r.phone}</span> : <span className="dim">—</span> },
          { k: "email", label: T("common.email"), w: "180px", render: (r) => r.email ? <span className="dim">{r.email}</span> : <span className="dim">—</span> },
          { k: "contracts", label: T("inst.contracts"), align: "right", w: "90px", render: (r) => <span className="mono">{inContracts(r.name) || "—"}</span> },
          { k: "owes", label: T("inst.owes"), align: "right", w: "110px", render: (r) => owes(r.name) ? <span className="mono">{money(owes(r.name))}</span> : <span className="dim">—</span> }
        ]} />
      </section>
    </div>
  );
}

// Per-buyer payment plan derived from a contract share; collections apply in order
function shareInterest(c, financed, pct) {
  const t = c.interestType || "flat";
  if (t === "fee") return Math.round((c.fee || 0) * pct / 100);
  const r = (c.interest || 0) / 100;
  if (t === "declining") return Math.round(financed * (r / 12) * ((c.months || 6) + 1) / 2);
  return Math.round(financed * r);
}
function sharePlan(c, share, collections) {
  const principal = Math.round(contractTotal(c) * share.pct / 100);
  const down = (c.downs || {})[share.person] || 0;
  const financed = Math.max(0, principal - down);
  const months = c.months || 6;
  const interestAmt = shareInterest(c, financed, share.pct);
  const mine = collections.filter((x) => x.contract === c.id && x.person === share.person);
  const settle = mine.find((x) => x.settle);
  const owed = financed + interestAmt - (settle ? settle.discount || 0 : 0);
  const base = Math.floor(owed / months);
  const d0 = new Date(c.date); d0.setMonth(d0.getMonth() + (c.grace || 0));
  const paid = mine.filter((x) => !x.settle);
  const weights = c.weights && c.weights.length === months ? c.weights : null;
  const schedule = [];
  let sumPrev = 0;
  for (let i = 0; i < months; i++) {
    const d = new Date(d0);
    d.setMonth(d.getMonth() + i);
    const amount = i === months - 1 ? owed - sumPrev : weights ? Math.round(owed * weights[i] / 100) : base;
    sumPrev += amount;
    const p = paid[i];
    const paidOn = p ? p.date : settle ? settle.date : null;
    const method = p ? p.method : settle ? "Early settlement" : null;
    schedule.push({ no: i + 1, due: d.toLocaleDateString(uiLocale(), { month: "short", day: "2-digit", year: "numeric" }), amount, paidOn, method, ref: p ? p.ref : settle ? settle.ref : null, note: p ? p.note : settle ? settle.note : null });
  }
  const paidAmt = schedule.filter((i) => i.paidOn).reduce((s, i) => s + i.amount, 0);
  const overdue = schedule.some((i) => !i.paidOn && new Date(i.due) < INST_TODAY);
  const status = paidAmt >= owed ? "Completed" : overdue ? "Overdue" : "Active";
  return { owed, principal, down, financed, interestAmt, schedule, paidAmt, status, settled: !!settle };
}

// Print-only receipt sheet, portal-mounted on <body>; @media print hides the app and shows this
function ReceiptSheet({ r }) {
  const buyer = (D.poolPeople || []).find((p) => p.name === r.person);
  const cum = r.plan.schedule.filter((x) => x.paidOn && x.no <= r.inst.no).reduce((s, x) => s + x.amount, 0);
  const remaining = Math.max(0, r.plan.owed - cum);
  return ReactDOM.createPortal(
    <div className="rc-sheet">
      <div className="rc-head">
        <span className="rc-logo"></span>
        <span className="rc-brand"><b>{T("app.brand")}</b><small>{T("app.brandTag")} · {T("inst.installmentManager")}</small></span>
        <span className="rc-no"><small>{T("inst.paymentReceipt")}</small><b>{r.inst.ref}</b></span>
      </div>
      <div className="rc-amount"><small>{T("inst.amountReceived")}</small><b>{money(r.inst.amount)}</b><span>{TV(r.inst.method)} · {r.inst.paidOn}</span></div>
      <div className="rc-kv">
        <span>{T("inst.receivedFrom")}</span><b>{r.person}</b>
        {buyer && (buyer.phone || buyer.email) ? <><span>{T("inst.contact")}</span><b>{[buyer.phone, buyer.email].filter(Boolean).join(" · ")}</b></> : null}
        <span>{T("inst.contract")}</span><b>{r.contract.id}{r.contract.note ? " — " + r.contract.note : ""}</b>
        <span>{T("inst.items")}</span><b>{r.contract.items.map((i) => i.name + (i.qty > 1 ? " ×" + i.qty : "")).join(", ")}</b>
        <span>{T("inst.installment")}</span><b>{T("inst.instOfDue", { no: r.inst.no, total: r.plan.schedule.length, due: r.inst.due })}</b>
        <span>{T("inst.planTotal")}</span><b>{money(r.plan.owed)}{r.plan.down ? " " + T("inst.afterDownPayment", { amount: money(r.plan.down) }) : ""}</b>
        <span>{T("inst.paidToDate")}</span><b>{money(cum)}</b>
        <span>{T("inst.balanceRemaining")}</span><b>{money(remaining)}</b>
        {r.inst.note ? <><span>{T("common.note")}</span><b>{r.inst.note}</b></> : null}
      </div>
      <div className="rc-sign"><span>{T("inst.receivedBy")}</span><span>{T("inst.payerSignature")}</span></div>
      <p className="rc-foot">{T("inst.receiptFooter", { date: "Jul 27, 2026", id: r.contract.id })}</p>
    </div>, document.body);
}

function AddFundsModal({ open, people, onClose, onSave }) {
  const { useState, useEffect } = React;
  const [f, setF] = useState({ person: "", newName: "", amount: "" });
  const [errs, setErrs] = useState({});
  useEffect(() => { if (open) { setF({ person: people[0] || "__new", newName: "", amount: "" }); setErrs({}); } }, [open]);
  if (!open) return null;
  const save = () => {
    const e = {};
    const name = f.person === "__new" ? f.newName.trim() : f.person;
    const amt = Math.round(parseFloat(f.amount) || 0);
    if (!name) e.newName = T("inst.errContributorName");
    if (amt <= 0) e.amount = T("inst.errEnterAmount");
    setErrs(e);
    if (Object.keys(e).length) return;
    onSave({ person: name, amount: amt, date: "Jul 27, 2026" });
  };
  return (
    <Modal open={true} onClose={onClose} title={T("inst.addFundsTitle")} width={420} z={120}
      footer={<div className="btnrow"><Btn onClick={onClose}>{T("common.cancel")}</Btn><Btn variant="primary" icon="check" onClick={save}>{T("inst.addFunds")}</Btn></div>}>
      <Field label={T("inst.contributor")}>
        <Select value={f.person} onChange={(e) => setF({ ...f, person: e.target.value })}
          options={people.map((p) => ({ value: p, label: p })).concat([{ value: "__new", label: T("inst.newContributor") }])} />
      </Field>
      {f.person === "__new" ? <Field label={T("common.name")} error={errs.newName}><Input value={f.newName} onChange={(e) => setF({ ...f, newName: e.target.value })} autoFocus /></Field> : null}
      <Field label={T("common.amount")} error={errs.amount}><Input type="number" min="1" placeholder="0" value={f.amount} onChange={(e) => setF({ ...f, amount: e.target.value })} /></Field>
    </Modal>
  );
}

function NewContractModal({ open, contribs, people, balance, onClose, onSave, onAddPerson }) {
  const { useState, useEffect } = React;
  const [addBuyer, setAddBuyer] = useState(null); // null | prefill name
  const byPerson = {};
  contribs.forEach((c) => { byPerson[c.person] = (byPerson[c.person] || 0) + c.amount; });
  const contributors = Object.keys(byPerson);
  const allPeople = [...new Set([...(people || []).map((p) => p.name), ...contributors])];
  const poolTotal = contribs.reduce((s, c) => s + c.amount, 0);
  const defShares = () => {
    let shares = contributors.map((p) => ({ person: p, pct: poolTotal ? Math.round((byPerson[p] / poolTotal) * 100) : 0 }));
    const diff = 100 - shares.reduce((s, x) => s + x.pct, 0);
    if (shares.length) shares[0] = { ...shares[0], pct: shares[0].pct + diff };
    return shares;
  };
  const [items, setItems] = useState([{ name: "", qty: "1", price: "" }]);
  const [shares, setShares] = useState([]);
  const [note, setNote] = useState("");
  const [months, setMonths] = useState("6");
  const [interest, setInterest] = useState("0");
  const [interestType, setInterestType] = useState("flat");
  const [fee, setFee] = useState("0");
  const [grace, setGrace] = useState("0");
  const [buyer, setBuyer] = useState("");
  const [down, setDown] = useState("");
  const [schedMode, setSchedMode] = useState("equal");
  const [repayMode, setRepayMode] = useState("months");
  const [monthly, setMonthly] = useState("");
  const [weights, setWeights] = useState([]);
  const [errs, setErrs] = useState({});
  useEffect(() => { if (open) { setItems([{ name: "", qty: "1", price: "" }]); setShares(defShares()); setNote(""); setMonths("6"); setInterest("0"); setInterestType("flat"); setFee("0"); setGrace("0"); setBuyer(""); setDown(""); setSchedMode("equal"); setRepayMode("months"); setMonthly(""); setWeights([]); setErrs({}); } }, [open]);
  if (!open) return null;

  const cleanItems = items.filter((i) => i.name.trim() && (parseFloat(i.price) || 0) > 0)
    .map((i) => ({ name: i.name.trim(), qty: Math.max(1, parseInt(i.qty, 10) || 1), price: Math.round(parseFloat(i.price) || 0) }));
  const total = cleanItems.reduce((s, i) => s + i.qty * i.price, 0);
  const rI = (parseFloat(interest) || 0) / 100;
  const downAmt = Math.max(0, Math.round(parseFloat(down) || 0));
  const financedAmt = Math.max(0, total - downAmt);
  const interestFor = (m) => interestType === "fee" ? (parseFloat(fee) || 0) : interestType === "declining" ? financedAmt * (rI / 12) * (m + 1) / 2 : financedAmt * rI;
  const monthlyAmt = Math.max(0, Math.round(parseFloat(monthly) || 0));
  const monthsFromAmount = () => {
    if (!monthlyAmt || !financedAmt) return 0;
    for (let m = 1; m <= 120; m++) { if (financedAmt + interestFor(m) <= monthlyAmt * m) return m; }
    return 0;
  };
  const rM = repayMode === "amount" ? Math.max(1, monthsFromAmount() || 1) : Math.max(1, parseInt(months, 10) || 6);
  const interestAmt = interestFor(rM);
  const repayTotal = Math.round(financedAmt + interestAmt);
  const wArr = Array.from({ length: rM }, (_, i) => parseFloat(weights[i]) || 0);
  const wSum = Math.round(wArr.reduce((a, b) => a + b, 0));
  const setItem = (idx, patch) => {
    const next = items.map((x, i) => (i === idx ? { ...x, ...patch } : x));
    if (idx === items.length - 1 && (patch.name || patch.price) && next[idx].name) next.push({ name: "", qty: "1", price: "" });
    setItems(next);
  };

  const save = () => {
    const e = {};
    if (!cleanItems.length) e.items = T("inst.errOneItemWithPrice");
    if (!buyer) e.buyer = T("inst.errChooseBuyer");
    if (total > balance) e.items = T("inst.errExceedsPool", { total: money(total), balance: money(balance) });
    if (schedMode === "custom" && wSum !== 100) e.sched = T("inst.errWeightsSum", { sum: wSum });
    if (repayMode === "amount" && total > 0 && !monthsFromAmount()) e.repay = T("inst.errMonthlyTooSmall");
    setErrs(e);
    if (Object.keys(e).length) return;
    onSave({ id: "PC-" + String(D.instContracts.length + 1).padStart(2, "0"), date: "Jul 27, 2026", note: note.trim(), months: rM,
      interest: Math.max(0, parseFloat(interest) || 0), interestType, fee: Math.max(0, parseFloat(fee) || 0), grace: Math.max(0, parseInt(grace, 10) || 0),
      weights: schedMode === "custom" ? wArr : null,
      downs: downAmt > 0 ? { [buyer]: downAmt } : {},
      items: cleanItems, shares: [{ person: buyer, pct: 100 }] });
  };

  return (
    <Modal open={true} onClose={onClose} title={T("inst.newContractTitle")} sub={T("inst.poolBalanceSub", { amount: money(balance) })} width={640} z={120}
      footer={<div className="btnrow"><Btn onClick={onClose}>{T("common.cancel")}</Btn><Btn variant="primary" icon="check" onClick={save}>{T("inst.createContractAmount", { amount: money(total) })}</Btn></div>}>
      {addBuyer !== null ? <PersonModal open={true} person={null} prefillName={addBuyer} onClose={() => setAddBuyer(null)} onSave={(p) => { onAddPerson(p); setBuyer(p.name); setAddBuyer(null); }} /> : null}
      <div className="formgrid">
        <Field label={T("inst.buyer")} error={errs.buyer}><SearchSelect options={allPeople} value={buyer} onChange={setBuyer} placeholder={T("inst.chooseBuyer")} onCreate={(name) => setAddBuyer(name)} addLabel={T("inst.newBuyer")} /></Field>
        <Field label={T("inst.downPayment")}><Input type="number" min="0" placeholder="0" value={down} onChange={(e) => setDown(e.target.value)} /></Field>
      </div>
      <div className="formgrid three">
        <Field label={T("inst.purposeOptional")}><Input placeholder={T("inst.purposePlaceholder")} value={note} onChange={(e) => setNote(e.target.value)} /></Field>
        <Field label={T("inst.repayment")} error={errs.repay}>
          <div style={{ display: "flex", gap: 6 }}>
            <Select value={repayMode} onChange={(e) => setRepayMode(e.target.value)} options={[{ value: "months", label: T("inst.byMonths") }, { value: "amount", label: T("inst.byMonthlyAmount") }]} style={{ flex: 1 }} />
            {repayMode === "months"
              ? <Select options={["3", "6", "9", "12", "18", "24"]} value={months} onChange={(e) => setMonths(e.target.value)} style={{ width: 74 }} />
              : <Input type="number" min="1" placeholder={T("inst.perMonthPlaceholder")} value={monthly} onChange={(e) => setMonthly(e.target.value)} style={{ width: 90 }} />}
          </div>
        </Field>
        <Field label={T("inst.gracePeriod")}><Select value={grace} onChange={(e) => setGrace(e.target.value)} options={[{ value: "0", label: T("inst.graceNone") }, { value: "1", label: T("inst.monthsN", { n: 1 }) }, { value: "2", label: T("inst.monthsN", { n: 2 }) }, { value: "3", label: T("inst.monthsN", { n: 3 }) }, { value: "6", label: T("inst.monthsN", { n: 6 }) }]} /></Field>
      </div>
      <div className="formgrid">
        <Field label={T("inst.interestType")}><Select value={interestType} onChange={(e) => setInterestType(e.target.value)} options={[{ value: "flat", label: T("inst.interestFlat") }, { value: "declining", label: T("inst.interestDeclining") }, { value: "fee", label: T("inst.interestFee") }]} /></Field>
        {interestType === "fee"
          ? <Field label={T("inst.feeAmount")}><Input type="number" min="0" value={fee} onChange={(e) => setFee(e.target.value)} /></Field>
          : <Field label={interestType === "declining" ? T("inst.annualRatePct") : T("inst.interestPct")}><Input type="number" min="0" step="0.5" value={interest} onChange={(e) => setInterest(e.target.value)} /></Field>}
      </div>
      {total > 0 ? <p className="formhint" style={{ marginTop: -6 }}>{T("inst.repaymentSummary", { total: money(repayTotal), months: rM, monthly: money(Math.ceil(repayTotal / rM)) })}{downAmt ? " " + T("inst.repaymentAfterDown", { amount: money(downAmt) }) : ""}{grace !== "0" ? " " + T("inst.repaymentAfterGrace", { n: grace }) : ""}</p> : null}
      <Field label={T("inst.installmentSizes")} error={errs.sched}>
        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
          <Select value={schedMode} onChange={(e) => { setSchedMode(e.target.value); setWeights(Array.from({ length: rM }, () => (100 / rM).toFixed(1))); }}
            options={[{ value: "equal", label: T("inst.equalInstallments") }, { value: "custom", label: T("inst.customUneven") }]} />
          {schedMode === "custom" ? (
            <div>
              <div className="pool-weights">
                {Array.from({ length: rM }, (_, i) => (
                  <label className="pool-weight" key={i}>
                    <small>M{i + 1}</small>
                    <Input type="number" min="0" step="0.5" value={weights[i] || ""} onChange={(e) => { const w = [...weights]; w[i] = e.target.value; setWeights(w); }} />
                  </label>
                ))}
              </div>
              <p className="formhint" style={{ marginTop: 6 }}>{T("inst.weightsHintPre")} <span className={wSum === 100 ? "" : "strong"} style={wSum !== 100 ? { color: "var(--red)" } : {}}>{T("inst.weightsSum", { sum: wSum })}</span>. {T("inst.weightsHintPost")}</p>
            </div>
          ) : null}
        </div>
      </Field>
      <Field label={T("inst.items")} error={errs.items}>
        <div className="ep-list">
          <div className="ep-row ep-head pool-itemrow"><span>{T("inv.item")}</span><span className="ta-c">{T("common.qty")}</span><span className="ta-r">{T("acct.unitPrice")}</span><span className="ta-r">{T("inst.line")}</span><span></span></div>
          {items.map((it, idx) => {
            const line = (parseInt(it.qty, 10) || 0) * (parseFloat(it.price) || 0);
            return (
              <div className="ep-row pool-itemrow" key={idx}>
                <Input placeholder={T("inst.itemNamePlaceholder")} value={it.name} onChange={(e) => setItem(idx, { name: e.target.value })} />
                <Input type="number" min="1" value={it.qty} onChange={(e) => setItem(idx, { qty: e.target.value })} style={{ textAlign: "center" }} />
                <Input type="number" min="0" placeholder="0" value={it.price} onChange={(e) => setItem(idx, { price: e.target.value })} style={{ textAlign: "end" }} />
                <span className="ta-r mono strong">{line ? money(line) : "—"}</span>
                <span className="ta-r">{items.length > 1 ? <button type="button" className="ep-doc-del" onClick={() => setItems(items.filter((_, i) => i !== idx))} title={T("common.remove")}><Icon name="x" size={13} /></button> : null}</span>
              </div>
            );
          })}
        </div>
      </Field>
    </Modal>
  );
}

function PoolTab({ contribs, contracts, balance, onAddFunds }) {
  const byPerson = {};
  contribs.forEach((c) => { byPerson[c.person] = (byPerson[c.person] || 0) + c.amount; });
  const poolTotal = contribs.reduce((s, c) => s + c.amount, 0);
  const spent = contracts.reduce((s, c) => s + contractTotal(c), 0);
  return (
    <div className="grid-23">
      <div>
        <SectionHead title={T("inst.contributions")} action={<Btn small variant="primary" icon="plus" onClick={onAddFunds}>{T("inst.addFunds")}</Btn>} />
        <section className="card" style={{ marginTop: 8 }}>
          <DataTable tableId="pool-contrib" rowKey={(r, i) => r.person + r.date + r.amount} rows={[...contribs].reverse()} cols={[
            { k: "person", label: T("inst.contributor"), render: (r) => <span className="cellwho"><Avatar name={r.person} size={26} /><b>{r.person}</b></span> },
            { k: "date", label: T("common.date"), w: "120px", render: (r) => <span className="dim mono">{r.date}</span> },
            { k: "amount", label: T("common.amount"), align: "right", w: "110px", render: (r) => <span className="mono strong">{money(r.amount)}</span> }
          ]} />
        </section>
      </div>
      <div>
        <SectionHead title={T("inst.poolSummary")} />
        <section className="card pad" style={{ marginTop: 8, marginBottom: 18 }}>
          <div className="ep-list">
            <div className="ep-row" style={{ gridTemplateColumns: "1fr auto" }}><span className="dim">{T("inst.contributed")}</span><span className="mono strong">{money(poolTotal)}</span></div>
            <div className="ep-row" style={{ gridTemplateColumns: "1fr auto" }}><span className="dim">{T("inst.spentOnPurchases")}</span><span className="mono">{money(spent)}</span></div>
            <div className="ep-row" style={{ gridTemplateColumns: "1fr auto" }}><span><b>{T("inst.availableBalance")}</b></span><span className="mono strong" style={{ color: "var(--green)" }}>{money(balance)}</span></div>
          </div>
        </section>
        <SectionHead title={T("inst.ownership")} />
        <section className="card" style={{ marginTop: 8 }}>
          <DataTable tableId="pool-own" rowKey={(r) => r.person} rows={Object.keys(byPerson).map((p) => ({ person: p, amount: byPerson[p], pct: poolTotal ? Math.round((byPerson[p] / poolTotal) * 100) : 0 }))} cols={[
            { k: "person", label: T("inst.contributor"), render: (r) => <span className="cellwho"><Avatar name={r.person} size={26} /><b>{r.person}</b></span> },
            { k: "amount", label: T("inst.contributed"), align: "right", w: "120px", render: (r) => <span className="mono">{money(r.amount)}</span> },
            { k: "pct", label: T("inst.share"), align: "right", w: "80px", render: (r) => <span className="mono strong">{r.pct}%</span> }
          ]} />
        </section>
      </div>
    </div>
  );
}

function ContractDetail({ contract, collections, onClose, onCollect, onSettle }) {
  const { useState } = React;
  const [payFor, setPayForRaw] = useState(null);
  const [payNote, setPayNote] = useState("");
  const setPayFor = (v) => { setPayNote(""); setPayForRaw(v); };
  const [settleFor, setSettleFor] = useState(null);
  const [receipt, setReceipt] = useState(null);
  const [disc, setDisc] = useState("0");
  const [tab, setTab] = useState("overview");
  const total = contractTotal(contract);
  const share = contract.shares[0];
  const cur = { s: share, plan: sharePlan(contract, share, collections) };
  const owedAll = cur.plan.owed;
  const paidAll = cur.plan.paidAmt;
  const iType = contract.interestType === "declining" ? T("inst.decliningBalance") : contract.interestType === "fee" ? T("inst.fixedFee") : T("inst.flat");
  const iVal = contract.interestType === "fee" ? money(contract.fee || 0) : (contract.interest || 0) + "%";

  return (
    <Modal open={true} onClose={onClose} title={contract.id} sub={(contract.note || contract.items.map((i) => i.name).join(", ")) + " · " + contract.date} width={1000} height="86vh" className="modal-fixed" z={110}
      footer={<div className="btnrow"><Btn onClick={onClose}>{T("common.close")}</Btn></div>}>
      <Tabs active={tab} onChange={setTab} tabs={[
        { id: "overview", label: T("inst.overview") },
        { id: "items", label: T("inst.items"), count: contract.items.length },
        { id: "plan", label: T("inst.payments"), count: cur.plan.schedule.filter((i) => !i.paidOn).length }
      ]} />

      {tab === "overview" ? (
        <div className="ep-overview">
          <div className="ep-stats">
            <div className="ep-stat"><span className="ep-stat-v mono">{money(total)}</span><span className="ep-stat-l">{T("inst.purchaseTotalN", { n: contract.items.length })}</span></div>
            <div className="ep-stat"><span className="ep-stat-v mono">{money(owedAll)}</span><span className="ep-stat-l">{T("inst.toRepayWith", { type: iType, value: iVal })}</span></div>
            <div className="ep-stat"><span className="ep-stat-v mono">{money(paidAll)}</span><span className="ep-stat-l">{T("inst.collected")}</span></div>
            <div className="ep-stat"><span className="ep-stat-v mono">{money(owedAll - paidAll)}</span><span className="ep-stat-l">{T("inst.outstanding")}</span></div>
          </div>
          <div className="ep-info">
            <KV k={T("inst.buyer")} v={share.person} />
            <KV k={T("inst.contractDate")} v={contract.date} />
            <KV k={T("inst.purpose")} v={contract.note || "—"} />
            <KV k={T("inst.interest")} v={iType + " · " + iVal + " (" + money(cur.plan.interestAmt) + ")"} mono />
            <KV k={T("inst.downPayment")} v={cur.plan.down ? money(cur.plan.down) : "—"} mono />
            <KV k={T("inst.repayment")} v={T("inst.monthlyInstallmentsN", { n: contract.months || 6 }) + (contract.grace ? " " + T("inst.afterGraceN", { n: contract.grace }) : "")} />
            <KV k={T("common.status")} v={TV(cur.plan.status)} />
          </div>
        </div>
      ) : null}

      {tab === "items" ? (
      <section className="card">
        <DataTable rowKey={(r, idx) => r.name + idx} rows={contract.items} cols={[
          { k: "name", label: T("inv.item"), render: (r) => <b>{r.name}</b> },
          { k: "qty", label: T("common.qty"), align: "right", w: "70px", render: (r) => <span className="mono">{r.qty}</span> },
          { k: "price", label: T("acct.unitPrice"), align: "right", w: "110px", render: (r) => <span className="mono">{money(r.price)}</span> },
          { k: "line", label: T("inst.lineTotal"), align: "right", w: "110px", render: (r) => <span className="mono strong">{money(r.qty * r.price)}</span> }
        ]} />
      </section>
      ) : null}

      {tab === "plan" ? (<>
        <div className="toolbar page-toolbar">
          <span className="dim" style={{ fontSize: 13 }}>{T("inst.collectedOf", { paid: money(cur.plan.paidAmt), owed: money(cur.plan.owed) })} · {cur.plan.down ? T("inst.downPaymentAmount", { amount: money(cur.plan.down) }) + " · " : ""}{T("inst.interestAmount", { amount: money(cur.plan.interestAmt) })}</span>
          {cur.plan.status !== "Completed" ? <Btn small onClick={() => { setDisc("0"); setSettleFor(cur); }}>{T("inst.settleEarly")}</Btn> : null}
        </div>
        <section className="card">
          <DataTable rowKey={(r) => r.no} rows={cur.plan.schedule} cols={[
            { k: "no", label: "#", w: "50px", render: (r) => <span className="mono dim">{String(r.no).padStart(2, "0")}</span> },
            { k: "due", label: T("acct.due"), w: "130px", render: (r) => <span className="mono">{r.due}{!r.paidOn && new Date(r.due) < INST_TODAY ? <span className="ep-flag late" style={{ marginInlineStart: 6 }}>{T("inst.overdueFlag")}</span> : null}</span> },
            { k: "paidOn", label: T("inst.paidOn"), w: "150px", render: (r) => r.paidOn ? <span className="mono">{r.paidOn}{r.ref ? <span className="dim" style={{ marginInlineStart: 6 }}>{r.ref}</span> : null}</span> : <span className="dim">—</span> },
            { k: "method", label: T("inst.methodNote"), render: (r) => r.paidOn ? <span>{TV(r.method)}{r.note ? <span className="dim"> · {r.note}</span> : null}</span> : <span className="dim">—</span> },
            { k: "amount", label: T("common.amount"), align: "right", w: "100px", render: (r) => <span className="mono strong">{money(r.amount)}</span> },
            { k: "act", label: "", w: "110px", align: "right", render: (r) => r.paidOn
                ? (r.ref ? <Btn small onClick={(e) => { e.stopPropagation(); setReceipt({ contract, person: cur.s.person, inst: r, plan: cur.plan }); }}>{T("inst.receipt")}</Btn> : null)
                : (r.no === cur.plan.schedule.filter((x) => x.paidOn).length + 1 ? <Btn small icon="check" onClick={(e) => { e.stopPropagation(); setPayFor({ person: cur.s.person, inst: r }); }}>{T("inst.collect")}</Btn> : null) }
          ]} />
        </section>
      </>) : null}

      {payFor ? (
        <Modal open={true} onClose={() => setPayFor(null)} title={T("inst.collectInstallmentNo", { no: payFor.inst.no })} sub={T("inst.collectSub", { name: payFor.person, amount: money(payFor.inst.amount), due: payFor.inst.due })} width={380} z={140}
          footer={<div className="btnrow"><Btn onClick={() => setPayFor(null)}>{T("common.cancel")}</Btn></div>}>
          <Field label={T("common.noteOptional")}><Input placeholder={T("inst.collectNotePlaceholder")} value={payNote} onChange={(e) => setPayNote(e.target.value)} /></Field>
          <p className="formhint" style={{ marginTop: 0 }}>{T("inst.recordCollectionVia")}</p>
          <div className="btnrow">
            {["Bank transfer", "Cash", "Cheque"].map((m) => <Btn key={m} icon="check" onClick={() => { onCollect(contract, payFor.person, payFor.inst, m, payNote.trim()); setPayFor(null); }}>{TV(m)}</Btn>)}
          </div>
        </Modal>
      ) : null}
      {settleFor ? (() => {
        const rem = settleFor.plan.owed - settleFor.plan.paidAmt;
        const d = Math.min(rem, Math.max(0, Math.round(parseFloat(disc) || 0)));
        return (
          <Modal open={true} onClose={() => setSettleFor(null)} title={T("inst.settleEarlyTitle", { id: contract.id })} sub={T("inst.settleSub", { name: settleFor.s.person, amount: money(rem) })} width={420} z={140}
            footer={<div className="btnrow"><Btn onClick={() => setSettleFor(null)}>{T("common.cancel")}</Btn><Btn variant="primary" icon="check" onClick={() => { onSettle(contract, settleFor.s.person, rem, d); setSettleFor(null); }}>{T("inst.settleForAmount", { amount: money(rem - d) })}</Btn></div>}>
            <p className="formhint" style={{ marginTop: 0 }}>{T("inst.settleHint", { amount: money(settleFor.plan.interestAmt) })}</p>
            <Field label={T("inst.interestDiscount")}><Input type="number" min="0" max={rem} value={disc} onChange={(e) => setDisc(e.target.value)} autoFocus /></Field>
          </Modal>
        );
      })() : null}
      {receipt ? (
        <Modal open={true} onClose={() => setReceipt(null)} title={T("inst.receiptTitle", { ref: receipt.inst.ref })} sub={T("inst.receiptSub", { date: receipt.inst.paidOn })} width={420} z={140}
          footer={<div className="btnrow"><Btn onClick={() => setReceipt(null)}>{T("common.close")}</Btn><Btn variant="primary" icon="file" onClick={() => window.print()}>{T("common.print")}</Btn></div>}>
          <div className="ep-list">
            <div className="ep-row" style={{ gridTemplateColumns: "110px 1fr" }}><span className="dim">{T("inst.receiptNo")}</span><span className="mono strong">{receipt.inst.ref}</span></div>
            <div className="ep-row" style={{ gridTemplateColumns: "110px 1fr" }}><span className="dim">{T("inst.receivedFrom")}</span><b>{receipt.person}</b></div>
            <div className="ep-row" style={{ gridTemplateColumns: "110px 1fr" }}><span className="dim">{T("inst.installment")}</span><span className="mono">{T("inst.instNoDue", { no: receipt.inst.no, due: receipt.inst.due })}</span></div>
            <div className="ep-row" style={{ gridTemplateColumns: "110px 1fr" }}><span className="dim">{T("common.amount")}</span><span className="mono strong">{money(receipt.inst.amount)}</span></div>
            <div className="ep-row" style={{ gridTemplateColumns: "110px 1fr" }}><span className="dim">{T("inst.method")}</span><span>{TV(receipt.inst.method)}</span></div>
            <div className="ep-row" style={{ gridTemplateColumns: "110px 1fr" }}><span className="dim">{T("common.date")}</span><span className="mono">{receipt.inst.paidOn}</span></div>
            {receipt.inst.note ? <div className="ep-row" style={{ gridTemplateColumns: "110px 1fr" }}><span className="dim">{T("common.note")}</span><span>{receipt.inst.note}</span></div> : null}
          </div>
          <ReceiptSheet r={receipt} />
        </Modal>
      ) : null}
    </Modal>
  );
}

function ContractsTab({ contracts, collections, balance, onNew, onCollect, onSettle }) {
  const { useState } = React;
  const [open, setOpen] = useState(null);
  const [q, setQ] = useState("");
  const [filter, setFilter] = useState("All");
  const statusOf = (c) => {
    const ps = c.shares.map((s) => sharePlan(c, s, collections));
    if (ps.every((p) => p.status === "Completed")) return "Completed";
    if (ps.some((p) => p.status === "Overdue")) return "Overdue";
    return "Active";
  };
  const owedOf = (c) => c.shares.reduce((a, s) => a + sharePlan(c, s, collections).owed, 0);
  const paidOf = (c) => c.shares.reduce((a, s) => a + sharePlan(c, s, collections).paidAmt, 0);
  const buyerOf = (c) => (c.shares[0] || {}).person || "—";
  const rows = contracts.filter((c) => {
    if (filter !== "All" && statusOf(c) !== filter) return false;
    const s = q.trim().toLowerCase();
    return !s || (c.id + " " + (c.note || "") + " " + c.items.map((i) => i.name).join(" ") + " " + c.shares.map((x) => x.person).join(" ")).toLowerCase().includes(s);
  });
  const cur = open ? contracts.find((c) => c.id === open) : null;
  return (
    <div>
      <div className="toolbar page-toolbar">
        <div className="toolbar-left" style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
          <Chips active={filter} onChange={setFilter} options={["All", "Active", "Overdue", "Completed"].map((s) => ({ id: s, label: s === "All" ? T("common.all") : TV(s), count: s === "All" ? contracts.length : contracts.filter((c) => statusOf(c) === s).length }))} />
        </div>
        <div className="toolbar-right" style={{ display: "flex", alignItems: "center", gap: 10 }}>
          <div className="searchbox">
            <Icon name="search" size={15} />
            <input placeholder={T("inst.searchContracts")} value={q} onChange={(e) => setQ(e.target.value)} />
          </div>
          <Btn variant="primary" icon="plus" onClick={onNew}>{T("inst.newContract")}</Btn>
        </div>
      </div>
      <section className="card">
        <DataTable tableId="pool-contracts" rowKey={(r) => r.id} rows={rows} onRow={(r) => setOpen(r.id)}
          empty={T("inst.noContracts")}
          cols={[
            { k: "id", label: T("inst.contract"), render: (r) => <span className="who2"><b>{r.id}</b><small className="dim">{r.note || r.items.map((i) => i.name).join(", ")}</small></span> },
            { k: "date", label: T("common.date"), w: "115px", render: (r) => <span className="dim mono">{r.date}</span> },
            { k: "buyer", label: T("inst.buyer"), w: "170px", render: (r) => <span className="cellwho"><Avatar name={buyerOf(r)} size={26} /><b>{buyerOf(r)}</b></span> },
            { k: "months", label: T("inst.months"), align: "right", w: "80px", render: (r) => <span className="mono">{r.months || 6}</span> },
            { k: "total", label: T("inst.purchase"), align: "right", w: "105px", render: (r) => <span className="mono">{money(contractTotal(r))}</span> },
            { k: "repay", label: T("inst.toRepay"), align: "right", w: "105px", render: (r) => <span className="mono strong">{money(owedOf(r))}</span> },
            { k: "paid", label: T("inst.collected"), align: "right", w: "105px", render: (r) => paidOf(r) ? <span className="mono" style={{ color: "var(--green)" }}>{money(paidOf(r))}</span> : <span className="dim">—</span> },
            { k: "out", label: T("inst.outstanding"), align: "right", w: "110px", render: (r) => owedOf(r) - paidOf(r) > 0 ? <span className="mono">{money(owedOf(r) - paidOf(r))}</span> : <span className="dim">—</span> },
            { k: "status", label: T("common.status"), w: "105px", render: (r) => <Badge tone={instTone(statusOf(r))}>{statusOf(r)}</Badge> }
          ]} />
      </section>
      {cur ? <ContractDetail contract={cur} collections={collections} onClose={() => setOpen(null)} onCollect={onCollect} onSettle={onSettle} /> : null}
    </div>
  );
}

function PaymentsTab({ contracts, collections, onCollect }) {
  const { useState } = React;
  const [q, setQ] = useState("");
  const [payFor, setPayForRaw] = useState(null);
  const [payNote, setPayNote] = useState("");
  const setPayFor = (v) => { setPayNote(""); setPayForRaw(v); };
  // one row per contract, one column per month
  const rows = contracts.map((c) => {
    const s = c.shares[0];
    const plan = sharePlan(c, s, collections);
    const nextNo = plan.schedule.filter((x) => x.paidOn).length + 1;
    const cells = {};
    plan.schedule.forEach((i) => {
      const d = new Date(i.due);
      const key = d.getFullYear() * 12 + d.getMonth();
      const status = i.paidOn ? "Collected" : d < INST_TODAY ? "Overdue" : (d.getMonth() === INST_TODAY.getMonth() && d.getFullYear() === INST_TODAY.getFullYear()) ? "Due" : "Upcoming";
      cells[key] = { inst: i, status, collectable: !i.paidOn && i.no === nextNo };
    });
    return { c, person: s.person, plan, cells };
  }).filter((r) => {
    const s = q.trim().toLowerCase();
    return !s || (r.person + " " + r.c.id + " " + (r.c.note || "")).toLowerCase().includes(s);
  });
  const keys = [...new Set(rows.flatMap((r) => Object.keys(r.cells).map(Number)))].sort((a, b) => a - b);
  const nowKey = INST_TODAY.getFullYear() * 12 + INST_TODAY.getMonth();
  const label = (k) => new Date(Math.floor(k / 12), k % 12, 1).toLocaleDateString(uiLocale(), { month: "short", year: "2-digit" }).replace(" ", " '");
  const colTotal = (k, paidOnly) => rows.reduce((s, r) => { const cl = r.cells[k]; return s + (cl && (!paidOnly || cl.inst.paidOn) ? cl.inst.amount : 0); }, 0);
  const expected = colTotal(nowKey, false), got = colTotal(nowKey, true);
  return (
    <div>
      <div className="toolbar page-toolbar">
        <span className="dim" style={{ fontSize: 13 }}>{TV("July")}: <b className="mono" style={{ color: "var(--ink)" }}>{money(got)}</b> {T("inst.collectedOfWord")} <b className="mono" style={{ color: "var(--ink)" }}>{money(expected)}</b> {T("inst.expectedClickCell")}</span>
        <div className="searchbox">
          <Icon name="search" size={15} />
          <input placeholder={T("inst.searchPayers")} value={q} onChange={(e) => setQ(e.target.value)} />
        </div>
      </div>
      <section className="card dt">
        <table className="pay-matrix">
          <thead>
            <tr>
              <th className="pm-payer">{T("inst.contractPayer")}</th>
              {keys.map((k) => <th key={k} className={"ta-c" + (k === nowKey ? " pm-now" : "")}>{label(k)}</th>)}
              <th className="ta-r">{T("inst.collected")}</th>
            </tr>
          </thead>
          <tbody>
            {rows.length === 0 ? <tr><td colSpan={keys.length + 2} className="dim" style={{ textAlign: "center", padding: 24 }}>{T("inst.noContractsMatch")}</td></tr> : null}
            {rows.map((r) => (
              <tr key={r.c.id}>
                <td className="pm-payer"><span className="cellwho"><Avatar name={r.person} size={26} /><span className="who2"><b>{r.person}</b><small className="dim">{r.c.id}{r.c.note ? " · " + r.c.note : ""}</small></span></span></td>
                {keys.map((k) => {
                  const cl = r.cells[k];
                  if (!cl) return <td key={k} className="ta-c"><span className="dim">—</span></td>;
                  const cls = cl.inst.paidOn ? "pm-paid" : cl.status === "Overdue" ? "pm-over" : cl.status === "Due" ? "pm-due" : "pm-up";
                  return (
                    <td key={k} className={"ta-c " + cls + (k === nowKey ? " pm-now" : "")}>
                      {cl.collectable
                        ? <button type="button" className="pm-pill pm-btn" onClick={() => setPayFor({ c: r.c, person: r.person, inst: cl.inst })} title={T("inst.collectDue", { due: cl.inst.due })}><span className="mono">{money(cl.inst.amount)}</span><Icon name="plus" size={12} stroke={2.4} /></button>
                        : <span className="pm-pill" title={cl.inst.paidOn ? T("inst.paidOnDate", { date: cl.inst.paidOn }) + (cl.inst.ref ? " · " + cl.inst.ref : "") + (cl.inst.note ? " · " + cl.inst.note : "") : T("inst.dueOnDate", { date: cl.inst.due })}>{cl.inst.paidOn ? <Icon name="check" size={12} stroke={2.4} /> : null}<span className="mono">{money(cl.inst.amount)}</span></span>}
                    </td>
                  );
                })}
                <td className="ta-r pm-tot"><span className="mono strong" style={r.plan.paidAmt ? { color: "var(--green)" } : {}}>{r.plan.paidAmt ? money(r.plan.paidAmt) : "—"}</span><small className="dim mono">{T("inst.ofAmount", { amount: money(r.plan.owed) })}</small></td>
              </tr>
            ))}
          </tbody>
          <tfoot>
            <tr>
              <td className="pm-payer"><b>{T("inst.monthlyTotal")}</b></td>
              {keys.map((k) => <td key={k} className={"ta-c pm-tot" + (k === nowKey ? " pm-now" : "")}><span className="mono strong">{money(colTotal(k, false))}</span><small className="mono" style={colTotal(k, true) ? { color: "var(--green)" } : {}}>{colTotal(k, true) ? T("inst.amountIn", { amount: money(colTotal(k, true)) }) : "—"}</small></td>)}
              <td className="ta-r"><span className="mono strong">{money(rows.reduce((s, r) => s + r.plan.paidAmt, 0))}</span></td>
            </tr>
          </tfoot>
        </table>
      </section>
      {payFor ? (
        <Modal open={true} onClose={() => setPayFor(null)} title={T("inst.collectInstallmentNo", { no: payFor.inst.no })} sub={T("inst.collectSub", { name: payFor.person, amount: money(payFor.inst.amount), due: payFor.inst.due })} width={400} z={130}
          footer={<div className="btnrow"><Btn onClick={() => setPayFor(null)}>{T("common.cancel")}</Btn></div>}>
          <Field label={T("common.noteOptional")}><Input placeholder={T("inst.collectNotePlaceholder")} value={payNote} onChange={(e) => setPayNote(e.target.value)} /></Field>
          <p className="formhint" style={{ marginTop: 0 }}>{T("inst.recordCollectionVia")}</p>
          <div className="btnrow">
            {["Bank transfer", "Cash", "Cheque"].map((m) => <Btn key={m} icon="check" onClick={() => { onCollect(payFor.c, payFor.person, payFor.inst, m, payNote.trim()); setPayFor(null); }}>{TV(m)}</Btn>)}
          </div>
        </Modal>
      ) : null}
    </div>
  );
}

Object.assign(window, { AddFundsModal, NewContractModal, PoolTab, ContractsTab, ContractDetail, PersonModal, PeopleTab, PaymentsTab, sharePlan, contractTotal });
