/* ============ ลูกหนี้ & เงินประกันสัญญา ============ */
function ReceivablesPage({ role, toast }) {
  const canEdit = role === 'owner' || role === 'staff' || role === 'accountant';
  const canDelete = role === 'owner';
  const [tab, setTab] = useState('ar');
  const [, setVer] = useState(0);
  const refresh = () => setVer((v) => v + 1);
  const [modal, setModal] = useState(null);   // null | 'new' | record
  const [delRow, setDelRow] = useState(null);

  const list = D.receivables || [];

  const saveR = async (rec, msg) => {
    const exists = D.receivables.some((x) => x.id === rec.id);
    const res = exists ? await API.updateReceivable(rec) : await API.addReceivable(rec);
    if (res.ok && res.data.ok) {
      const saved = res.data.record || rec;
      const i = D.receivables.findIndex((x) => x.id === saved.id);
      if (i >= 0) D.receivables[i] = saved; else D.receivables.push(saved);
      if (msg) toast(msg);
      setModal(null); refresh();
      return true;
    }
    toast((res.data && (res.data.msg || res.data.error)) || 'บันทึกไม่สำเร็จ', 'warn');
    return false;
  };
  const patch = (r, changes, msg) => saveR({ ...r, ...changes }, msg);
  const markBilled = (r) => patch(r, { status: 'billed', progress: 100 }, 'ส่งมอบงาน & ออกใบวางบิลแล้ว');
  const markPaid = (r) => patch(r, { status: 'paid', paidDate: todayTh(), retStatus: r.retention > 0 ? 'held' : r.retStatus }, 'ยืนยันรับชำระเรียบร้อย');
  const markRetReceived = (r) => patch(r, { retStatus: 'received', retReceivedDate: todayTh() }, 'บันทึกรับคืนเงินประกันแล้ว');

  const doDelete = async () => {
    const res = await API.deleteReceivable(delRow.id);
    if (res.ok && res.data.ok) { const i = D.receivables.findIndex((x) => x.id === delRow.id); if (i >= 0) D.receivables.splice(i, 1); toast('ลบงาน/ลูกหนี้แล้ว'); refresh(); }
    else toast('ลบไม่สำเร็จ', 'warn');
    setDelRow(null);
  };

  // summary
  const outstanding = list.filter((r) => r.status !== 'paid').reduce((a, r) => a + r.value, 0);
  const inprogressN = list.filter((r) => r.status === 'inprogress').length;
  const awaitingN = list.filter((r) => r.status === 'billed' || r.status === 'overdue').length;
  const overdueN = list.filter((r) => r.status === 'overdue').length;
  const retHeld = list.filter((r) => r.retStatus === 'held' || r.retStatus === 'pending').reduce((a, r) => a + r.retention, 0);
  const retDueN = list.filter((r) => r.retStatus === 'due').length;
  const retDueAmt = list.filter((r) => r.retStatus === 'due').reduce((a, r) => a + r.retention, 0);
  const retList = list.filter((r) => r.retention > 0);

  // ===== สรุปตามสัญญา (จับกลุ่มรายรับด้วยเลขที่สัญญา/PO รวมทุกงวด) =====
  const contracts = (() => {
    const m = new Map();
    (D.income || []).forEach((r) => {
      const key = (r.contractNo || '').trim();
      if (!key) return;
      if (!m.has(key)) m.set(key, { contractNo: key, customer: r.customer, payer: r.payer, project: r.project, items: [], total: 0, retention: 0, wht: 0 });
      const g = m.get(key);
      g.items.push(r);
      g.total += r.total || 0;
      g.retention += r.retention || 0;
      g.wht += r.wht || 0;
    });
    return [...m.values()].sort((a, b) => b.total - a.total);
  })();

  return (
    <>
      <div className="page-head">
        <div><div className="pt">ลูกหนี้ &amp; เงินประกันสัญญา</div><div className="ps">ติดตามงานที่กำลังดำเนินการ การรับชำระ และเงินประกันผลงานที่รอคืน</div></div>
        <div className="spacer"></div>
        {canEdit && <button className="btn btn-primary" onClick={() => setModal('new')}><Icon name="plus" className="ic" />เพิ่มงาน / ลูกหนี้</button>}
      </div>

      <div className="grid" style={{ gridTemplateColumns: 'repeat(auto-fit, minmax(185px, 1fr))', marginBottom: 16 }}>
        <Stat label="ลูกหนี้คงค้างรวม" icon="income" value={D.baht(outstanding, 0)} sub={awaitingN + ' งานรอชำระ'} />
        <Stat label="กำลังดำเนินการ" icon="refresh" iconBg="var(--warn-bg)" iconColor="var(--warn)" value={inprogressN} unit=" งาน" />
        <Stat label="เกินกำหนดชำระ" icon="alert" iconBg={overdueN ? 'var(--danger-bg)' : 'var(--surface-2)'} iconColor={overdueN ? 'var(--danger)' : 'var(--ink-3)'} value={overdueN} unit=" งาน" />
        <Stat label="เงินประกันถูกหักไว้" icon="lock" iconBg="var(--surface-2)" iconColor="var(--ink-2)" value={D.baht(retHeld, 0)} sub="รอครบกำหนดคืน" />
        <Stat label="ประกันครบกำหนดรับคืน" icon="checkCircle" iconBg={retDueN ? 'var(--ok-bg)' : 'var(--surface-2)'} iconColor={retDueN ? 'var(--ok)' : 'var(--ink-3)'} value={D.baht(retDueAmt, 0)} sub={retDueN + ' รายการพร้อมรับ'} />
      </div>

      <div className="seg" style={{ marginBottom: 18 }}>
        <button className={tab === 'ar' ? 'on' : ''} onClick={() => setTab('ar')}>ลูกหนี้ / การรับชำระ</button>
        <button className={tab === 'ret' ? 'on' : ''} onClick={() => setTab('ret')}>เงินประกันสัญญา{retDueN > 0 && <span className="nav-badge" style={{ marginLeft: 7, position: 'static' }}>{retDueN}</span>}</button>
        <button className={tab === 'contract' ? 'on' : ''} onClick={() => setTab('contract')}>ตามสัญญา (รวมงวด)</button>
      </div>

      {tab === 'ar' && (
        list.length === 0
          ? <Empty icon="bank" title="ยังไม่มีงาน/ลูกหนี้" sub="กด “เพิ่มงาน / ลูกหนี้” เพื่อเริ่มบันทึก" />
          : <div className="grid" style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(340px, 1fr))' }}>
              {list.map((r) => <ARCard key={r.id} r={r} canEdit={canEdit} canDelete={canDelete} onPaid={markPaid} onBilled={markBilled} onEdit={() => setModal(r)} onDelete={() => setDelRow(r)} />)}
            </div>
      )}

      {tab === 'ret' && (
        <>
          {retDueN > 0 && <div className="callout info" style={{ marginBottom: 14 }}><Icon name="bell" className="ic" /><div>มีเงินประกันสัญญา <b>{retDueN} รายการ</b> ที่ครบกำหนดแล้ว รวม <b>{D.baht(retDueAmt)}</b> — ติดต่อหน่วยงานเพื่อขอรับคืน แล้วกด "ได้รับคืนแล้ว"</div></div>}
          <div className="card">
            <div className="tbl-wrap">
              <table className="tbl">
                <thead><tr><th>โครงการ / คู่สัญญา</th><th>เลขที่สัญญา</th><th className="r">เงินประกัน</th><th className="c">ระยะประกัน</th><th>ครบกำหนด</th><th>สถานะ</th><th className="c">จัดการ</th></tr></thead>
                <tbody>
                  {retList.map((r) => {
                    const mo = r.retDueISO ? D.monthsUntil(r.retDueISO) : 0;
                    const due = r.retStatus === 'due' || (r.retStatus === 'held' && mo <= 0);
                    const effStatus = (r.retStatus === 'held' && due) ? 'due' : r.retStatus;
                    return (
                      <tr key={r.id}>
                        <td style={{ minWidth: 180 }}><div style={{ fontWeight: 600 }}>{r.project}</div><div style={{ fontSize: 11.5, color: 'var(--ink-3)' }}>{r.customer}</div></td>
                        <td className="mono" style={{ fontSize: 12.5 }}>{r.contractNo}</td>
                        <td className="r num" style={{ fontWeight: 600 }}>{D.fmt(r.retention)}<div style={{ fontSize: 10.5, color: 'var(--ink-3)' }}>{r.retRate}%</div></td>
                        <td className="c">{r.retYears} ปี</td>
                        <td>
                          <div style={{ fontWeight: 500, fontSize: 13 }}>{r.retDueISO ? thDate(r.retDueISO) : '—'}</div>
                          <div style={{ fontSize: 11.5, color: due ? 'var(--ok)' : 'var(--ink-3)', fontWeight: 600 }}>{r.retStatus === 'received' ? 'รับคืนเมื่อ ' + r.retReceivedDate : r.retStatus === 'pending' ? 'เริ่มนับเมื่อส่งมอบ' : due ? 'ครบกำหนดแล้ว' : 'อีก ' + remainLabel(mo)}</div>
                        </td>
                        <td><span className={'badge ' + D.retStatusInfo[effStatus].badge}><span className="dot"></span>{D.retStatusInfo[effStatus].label}</span></td>
                        <td className="c">
                          <div style={{ display: 'flex', gap: 4, justifyContent: 'center', alignItems: 'center', flexWrap: 'wrap' }}>
                            {(effStatus === 'due') && canEdit && <button className="btn btn-primary btn-sm" onClick={() => markRetReceived(r)}><Icon name="check" className="ic" />ได้รับคืนแล้ว</button>}
                            {r.retStatus === 'received' && <Icon name="checkCircle" size={18} style={{ color: 'var(--info)' }} />}
                            {canEdit && <button className="x-btn" title="แก้ไข" onClick={() => setModal(r)}><Icon name="edit" size={16} /></button>}
                            {canDelete && <button className="x-btn" title="ลบ" style={{ color: 'var(--danger)' }} onClick={() => setDelRow(r)}><Icon name="trash" size={16} /></button>}
                          </div>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </div>
          <div className="callout warn" style={{ marginTop: 14 }}><Icon name="info" className="ic" /><div>เงินประกันผลงานเป็น<b>ลูกหนี้ระยะยาว</b>ในงบดุล ไม่ใช่ค่าใช้จ่าย — หน่วยงานราชการมักคืนหลังพ้นระยะรับประกันงาน (โดยทั่วไป 1–2 ปี) เมื่อไม่มีงานชำรุดบกพร่อง</div></div>
        </>
      )}

      {tab === 'contract' && (
        contracts.length === 0
          ? <Empty icon="bank" title="ยังไม่มีงานที่ระบุเลขที่สัญญา" sub="ใส่ “เลขที่สัญญา/PO” ในหน้ารายรับ — งานงวดที่สัญญาเดียวกันจะถูกรวมยอดให้อัตโนมัติที่นี่" />
          : <>
            <div className="callout info" style={{ marginBottom: 14 }}><Icon name="sparkle" className="ic" /><div>รวมจาก<b>รายรับที่กรอกไว้</b>โดยจับกลุ่มด้วยเลขที่สัญญา/PO — งานงวดสัญญาเดียวกันถูกรวมยอดและเงินประกันให้อัตโนมัติ (ไม่ต้องกรอกซ้ำ)</div></div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              {contracts.map((c) => (
                <div key={c.contractNo} className="card">
                  <div className="card-head" style={{ flexWrap: 'wrap' }}>
                    <div>
                      <h3 style={{ whiteSpace: 'normal' }}>{c.project || c.customer}</h3>
                      <div className="sub">{c.customer} · <span className="mono">{c.contractNo}</span></div>
                    </div>
                    <span className={'badge ' + D.payerInfo[c.payer].badge} style={{ marginLeft: 'auto' }}>{D.payerInfo[c.payer].label}</span>
                    <span className="badge muted">{c.items.length} งวด</span>
                  </div>
                  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))', borderBottom: '1px solid var(--line-2)' }}>
                    {[['ยอดรวมทุกงวด', c.total, 'var(--ink)'], ['เงินประกันรวมทุกงวด', c.retention, 'var(--warn)'], ['หัก ณ ที่จ่ายรวม', c.wht, 'var(--info)']].map(([l, v, col]) => (
                      <div key={l} style={{ padding: '13px 18px', borderRight: '1px solid var(--line-2)' }}>
                        <div style={{ fontSize: 12, color: 'var(--ink-3)' }}>{l}</div>
                        <div className="num" style={{ fontSize: 19, fontWeight: 700, marginTop: 4, color: col }}>{D.baht(v, 0)}</div>
                      </div>
                    ))}
                  </div>
                  <div className="tbl-wrap">
                    <table className="tbl">
                      <thead><tr><th>วันที่ (งวด)</th><th>เลขที่ใบกำกับ</th><th className="r">ยอดรวม</th><th className="r">เงินประกัน</th><th className="r">หัก ณ ที่จ่าย</th><th>สถานะ</th></tr></thead>
                      <tbody>
                        {c.items.map((it) => (
                          <tr key={it.id}>
                            <td className="num" style={{ whiteSpace: 'nowrap', color: 'var(--ink-2)' }}>{it.date}</td>
                            <td className="mono" style={{ fontSize: 12.5 }}>{it.docNo}</td>
                            <td className="r num" style={{ fontWeight: 600 }}>{D.fmt(it.total)}</td>
                            <td className="r num" style={{ color: it.retention > 0 ? 'var(--warn)' : 'var(--ink-3)' }}>{it.retention > 0 ? D.fmt(it.retention) : '—'}</td>
                            <td className="r num" style={{ color: it.wht > 0 ? 'var(--info)' : 'var(--ink-3)' }}>{it.wht > 0 ? D.fmt(it.wht) : '—'}</td>
                            <td><Status status={it.status} /></td>
                          </tr>
                        ))}
                      </tbody>
                      <tfoot><tr style={{ background: 'var(--surface-2)', fontWeight: 700 }}>
                        <td colSpan="2" style={{ padding: 12 }}>รวม {c.items.length} งวด</td>
                        <td className="r num" style={{ padding: 12 }}>{D.fmt(c.total)}</td>
                        <td className="r num" style={{ padding: 12, color: 'var(--warn)' }}>{D.fmt(c.retention)}</td>
                        <td className="r num" style={{ padding: 12, color: 'var(--info)' }}>{D.fmt(c.wht)}</td>
                        <td></td>
                      </tr></tfoot>
                    </table>
                  </div>
                </div>
              ))}
            </div>
          </>
      )}

      {modal && <ReceivableModal record={modal === 'new' ? null : modal} onClose={() => setModal(null)} onSave={(rec) => saveR(rec, (modal === 'new' ? 'เพิ่มงาน/ลูกหนี้แล้ว' : 'บันทึกการแก้ไขแล้ว'))} />}
      {delRow && (
        <Modal title="ยืนยันการลบงาน/ลูกหนี้" icon="trash" onClose={() => setDelRow(null)}
          footer={<><button className="btn btn-ghost" onClick={() => setDelRow(null)}>ยกเลิก</button><button className="btn btn-danger" onClick={doDelete}><Icon name="trash" className="ic" />ลบ</button></>}>
          <div style={{ fontSize: 14, lineHeight: 1.7 }}>ต้องการลบ <b>{delRow.project}</b> ({delRow.customer}) มูลค่า <b>{D.baht(delRow.value)}</b> ใช่หรือไม่? ข้อมูลเงินประกันของงานนี้จะถูกลบด้วย</div>
        </Modal>
      )}
    </>
  );
}

function ARCard({ r, canEdit, canDelete, onPaid, onBilled, onEdit, onDelete }) {
  const si = D.arStatusInfo[r.status];
  const hasRet = r.retention > 0;
  const mo = r.retDueISO ? D.monthsUntil(r.retDueISO) : 0;
  const retDue = r.retStatus === 'due' || (r.retStatus === 'held' && mo <= 0);
  return (
    <div className="card" style={{ display: 'flex', flexDirection: 'column' }}>
      <div style={{ padding: '15px 18px 12px', borderBottom: '1px solid var(--line-2)' }}>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginBottom: 3 }}>
              <span className={'badge ' + D.payerInfo[r.payer].badge} style={{ fontSize: 10.5 }}>{D.payerInfo[r.payer].label}</span>
              <span className="mono" style={{ fontSize: 11, color: 'var(--ink-3)' }}>{r.contractNo}</span>
            </div>
            <div style={{ fontWeight: 700, fontSize: 14.5, lineHeight: 1.3 }}>{r.project}</div>
            <div style={{ fontSize: 12.5, color: 'var(--ink-2)', marginTop: 1 }}>{r.customer}</div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 6 }}>
            <span className={'badge ' + si.badge}><span className="dot"></span>{si.label}</span>
            {canEdit && (
              <div style={{ display: 'flex', gap: 2 }}>
                <button className="x-btn" title="แก้ไข" style={{ width: 28, height: 28 }} onClick={onEdit}><Icon name="edit" size={15} /></button>
                {canDelete && <button className="x-btn" title="ลบ" style={{ width: 28, height: 28, color: 'var(--danger)' }} onClick={onDelete}><Icon name="trash" size={15} /></button>}
              </div>
            )}
          </div>
        </div>
      </div>

      <div style={{ padding: '13px 18px', display: 'flex', flexDirection: 'column', gap: 11, flex: 1 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
          <span style={{ fontSize: 12.5, color: 'var(--ink-3)' }}>มูลค่างาน</span>
          <span className="num" style={{ fontWeight: 700, fontSize: 18 }}>{D.baht(r.value, 0)}</span>
        </div>

        {r.status === 'inprogress' && (
          <div>
            <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, marginBottom: 5 }}><span style={{ color: 'var(--ink-2)' }}>ความคืบหน้างาน</span><span style={{ fontWeight: 700 }}>{r.progress}%</span></div>
            <div className="bar-track"><div className="bar-fill" style={{ width: r.progress + '%', background: 'var(--warn)' }}></div></div>
          </div>
        )}

        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12.5 }}>
          <span style={{ color: 'var(--ink-3)' }}>{r.status === 'paid' ? 'รับชำระเมื่อ' : 'กำหนดชำระ'}</span>
          <span style={{ fontWeight: 600, color: r.status === 'overdue' ? 'var(--danger)' : 'var(--ink)' }}>{r.status === 'paid' ? r.paidDate : r.dueDate}{r.status === 'overdue' && ' · เลยกำหนด'}</span>
        </div>

        {hasRet && (
          <div style={{ background: retDue ? 'var(--ok-bg)' : 'var(--surface-2)', borderRadius: 10, padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 10 }}>
            <Icon name="lock" size={16} style={{ color: retDue ? 'var(--ok)' : 'var(--ink-3)', flexShrink: 0 }} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 12, fontWeight: 600 }}>เงินประกันสัญญา {D.fmt0(r.retention)} ฿ ({r.retRate}%)</div>
              <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>
                {r.retStatus === 'received' ? 'รับคืนแล้ว ' + r.retReceivedDate
                  : r.retStatus === 'pending' ? 'ประกัน ' + r.retYears + ' ปี · เริ่มนับเมื่อส่งมอบงาน'
                  : retDue ? 'ครบกำหนดแล้ว · พร้อมรับคืน'
                  : 'ครบกำหนด ' + thDate(r.retDueISO) + ' · อีก ' + remainLabel(mo)}
              </div>
            </div>
          </div>
        )}

        <div style={{ marginTop: 'auto', paddingTop: 4 }}>
          {r.status === 'inprogress' && canEdit && <button className="btn btn-soft btn-block btn-sm" onClick={() => onBilled(r)}><Icon name="send" className="ic" />ส่งมอบงาน &amp; วางบิล</button>}
          {(r.status === 'billed' || r.status === 'overdue') && canEdit && <button className="btn btn-primary btn-block btn-sm" onClick={() => onPaid(r)}><Icon name="check" className="ic" />ยืนยันรับชำระเงิน</button>}
          {r.status === 'paid' && <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, padding: '7px', color: 'var(--ok)', fontWeight: 600, fontSize: 13 }}><Icon name="checkCircle" size={16} />รับชำระเรียบร้อยแล้ว</div>}
        </div>
      </div>
    </div>
  );
}

function ReceivableModal({ record, onClose, onSave }) {
  const r = record || {};
  const [f, setF] = useState({
    customer: r.customer || '', payer: r.payer || 'gov', project: r.project || '', contractNo: r.contractNo || '',
    value: r.value != null ? String(r.value) : '', dueDate: r.dueDate || '', status: r.status || 'inprogress', progress: r.progress != null ? String(r.progress) : '0',
    retention: r.retention != null ? String(r.retention) : '', retRate: r.retRate != null ? String(r.retRate) : '5', retYears: r.retYears != null ? String(r.retYears) : '1',
    retDueISO: r.retDueISO || '', retStatus: r.retStatus || 'none',
  });
  const [err, setErr] = useState('');
  const [saving, setSaving] = useState(false);
  const [sugFor, setSugFor] = useState(null); // 'cust' | 'contract' | null
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));

  // ===== ค้นจากข้อมูลที่มีอยู่ (รายรับ + ลูกหนี้เดิม) =====
  // ช่อง "ลูกค้า" ดึงเป็นรายงาน (โครงการ+จำนวนเงิน) จากรายรับ — กดแล้วเติมครบ
  const incomeJobs = React.useMemo(() =>
    (D.income || []).map((x) => ({ customer: x.customer, project: x.project, payer: x.payer, total: x.total, retention: x.retention, contractNo: x.contractNo, date: x.date }))
  , []);
  const contractBook = React.useMemo(() => {
    const m = new Map();
    (D.income || []).forEach((x) => { const k = (x.contractNo || '').trim(); if (!k) return; if (!m.has(k)) m.set(k, { contractNo: k, customer: x.customer, project: x.project, payer: x.payer, value: 0, retention: 0 }); const g = m.get(k); g.value += x.total || 0; g.retention += x.retention || 0; });
    (D.receivables || []).forEach((x) => { const k = (x.contractNo || '').trim(); if (k && !m.has(k)) m.set(k, { contractNo: k, customer: x.customer, project: x.project, payer: x.payer, value: x.value || 0, retention: x.retention || 0 }); });
    return [...m.values()];
  }, []);
  const cq = f.customer.trim().toLowerCase(), kq = f.contractNo.trim().toLowerCase();
  const suggestions = sugFor === 'contract'
    ? (kq ? contractBook.filter((c) => c.contractNo.toLowerCase().includes(kq) || (c.customer || '').toLowerCase().includes(kq)) : contractBook).slice(0, 6)
    : sugFor === 'cust'
      ? (cq ? incomeJobs.filter((j) => (j.customer || '').toLowerCase().includes(cq) || (j.project || '').toLowerCase().includes(cq)) : incomeJobs).slice(0, 8)
      : [];
  const pickCustomer = (j) => { setF((p) => ({ ...p, customer: j.customer, project: j.project || p.project, payer: j.payer || p.payer, value: j.total ? String(Math.round(j.total)) : p.value, retention: j.retention ? String(Math.round(j.retention)) : p.retention, contractNo: j.contractNo || p.contractNo })); setSugFor(null); };
  const pickContract = (c) => { setF((p) => ({ ...p, contractNo: c.contractNo, customer: c.customer || p.customer, project: c.project || p.project, payer: c.payer || p.payer, value: c.value ? String(Math.round(c.value)) : p.value, retention: c.retention ? String(Math.round(c.retention)) : p.retention })); setSugFor(null); };

  const save = async () => {
    setErr('');
    if (!f.customer.trim()) { setErr('กรุณากรอกคู่สัญญา/ลูกค้า'); return; }
    if (!(parseFloat(f.value) > 0)) { setErr('กรุณากรอกมูลค่างาน'); return; }
    setSaving(true);
    const retention = parseFloat(f.retention) || 0;
    const rec = {
      id: r.id || ('AR' + Date.now()),
      customer: f.customer.trim(), payer: f.payer, project: f.project.trim(), contractNo: f.contractNo.trim(),
      value: parseFloat(f.value) || 0, billed: r.billed || 0, dueDate: f.dueDate.trim(), status: f.status, progress: parseInt(f.progress) || 0,
      paidDate: r.paidDate || null, retention, retRate: parseFloat(f.retRate) || 0, retYears: parseInt(f.retYears) || 0,
      retStartISO: r.retStartISO || null, retDueISO: f.retDueISO || null,
      retStatus: retention > 0 ? (f.retStatus === 'none' ? 'pending' : f.retStatus) : 'none',
      retReceivedDate: r.retReceivedDate || null,
    };
    await onSave(rec);
    setSaving(false);
  };

  return (
    <Modal title={record ? 'แก้ไขงาน / ลูกหนี้' : 'เพิ่มงาน / ลูกหนี้'} icon="bank" onClose={onClose} wide
      footer={<><button className="btn btn-ghost" onClick={onClose}>ยกเลิก</button><button className="btn btn-primary" onClick={save} disabled={saving}><Icon name="check" className="ic" />{saving ? 'กำลังบันทึก…' : 'บันทึก'}</button></>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 13 }}>
        {err && <div className="callout warn" style={{ padding: '9px 12px' }}><Icon name="alert" className="ic" />{err}</div>}
        <div style={{ position: 'relative' }}>
          <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 12 }}>
            <Field label="คู่สัญญา / ลูกค้า"><input className="input" value={f.customer} onFocus={() => setSugFor('cust')} onChange={(e) => { set('customer', e.target.value); setSugFor('cust'); }} onBlur={() => setTimeout(() => setSugFor(null), 160)} placeholder="พิมพ์เพื่อค้นหาจากที่เคยบันทึก" /></Field>
            <Field label="เลขที่สัญญา/PO"><input className="input mono" value={f.contractNo} onFocus={() => setSugFor('contract')} onChange={(e) => { set('contractNo', e.target.value); setSugFor('contract'); }} onBlur={() => setTimeout(() => setSugFor(null), 160)} placeholder="ค้นหา/พิมพ์เลขสัญญา" /></Field>
          </div>
          {sugFor && suggestions.length > 0 && (
            <div className="card" style={{ position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 6, marginTop: 4, boxShadow: 'var(--shadow-lg)', maxHeight: 260, overflowY: 'auto', padding: 4 }}>
              <div style={{ fontSize: 11, color: 'var(--ink-3)', padding: '6px 10px 4px', display: 'flex', alignItems: 'center', gap: 6 }}><Icon name="search" size={12} />{sugFor === 'contract' ? 'สัญญาที่เคยบันทึก (ดึงมูลค่า+เงินประกันรวมให้)' : 'ลูกค้า/คู่สัญญาที่เคยบันทึก'}</div>
              {suggestions.map((c, i) => (
                <button type="button" key={i} onMouseDown={(e) => { e.preventDefault(); sugFor === 'contract' ? pickContract(c) : pickCustomer(c); }}
                  style={{ display: 'flex', alignItems: 'center', gap: 10, width: '100%', textAlign: 'left', padding: '8px 10px', borderRadius: 8 }}
                  onMouseEnter={(e) => e.currentTarget.style.background = 'var(--surface-2)'} onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    {sugFor === 'contract'
                      ? <><div style={{ fontWeight: 600, fontSize: 13 }}><span className="mono">{c.contractNo}</span> · {c.customer}</div><div style={{ fontSize: 11.5, color: 'var(--ink-3)' }}>{c.project || '—'} · รวม {D.fmt0(c.value)} · ประกัน {D.fmt0(c.retention)}</div></>
                      : <><div style={{ fontWeight: 600, fontSize: 13 }}>{c.customer}</div><div style={{ fontSize: 11.5, color: 'var(--ink-3)' }}>{(c.project || 'ไม่ระบุงาน')} · {D.fmt0(c.total || 0)} บาท{c.contractNo ? ' · ' + c.contractNo : ''}</div></>}
                  </div>
                  {sugFor === 'cust' && c.payer && <span className={'badge ' + D.payerInfo[c.payer].badge} style={{ fontSize: 10 }}>{D.payerInfo[c.payer].label}</span>}
                </button>
              ))}
            </div>
          )}
        </div>
        <Field label="ชื่องาน / โครงการ"><input className="input" value={f.project} onChange={(e) => set('project', e.target.value)} placeholder="เช่น งานวางท่อระบายน้ำ" /></Field>
        <Field label="ประเภทผู้จ่ายเงิน">
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 8 }}>
            {[['gov', 'ราชการ'], ['company', 'นิติบุคคล'], ['individual', 'บุคคล']].map(([k, l]) => (
              <button key={k} onClick={() => set('payer', k)} style={{ padding: '9px 8px', borderRadius: 10, border: '1px solid ' + (f.payer === k ? 'var(--primary)' : 'var(--line)'), background: f.payer === k ? 'var(--primary-tint)' : 'var(--surface)', fontWeight: 600, fontSize: 13 }}>{l}</button>
            ))}
          </div>
        </Field>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
          <Field label="มูลค่างาน (บาท)"><input className="input right mono" value={f.value} onChange={(e) => set('value', e.target.value)} placeholder="0.00" /></Field>
          <Field label="กำหนดชำระ"><input className="input" value={f.dueDate} onChange={(e) => set('dueDate', e.target.value)} placeholder="30 มิ.ย. 68" /></Field>
          <Field label="สถานะงาน"><select className="select" value={f.status} onChange={(e) => set('status', e.target.value)}>{Object.entries(D.arStatusInfo).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}</select></Field>
        </div>
        {f.status === 'inprogress' && <Field label="ความคืบหน้างาน (%)"><input className="input right mono" value={f.progress} onChange={(e) => set('progress', e.target.value)} placeholder="0-100" /></Field>}

        <div style={{ background: 'var(--surface-2)', borderRadius: 11, padding: 14, display: 'flex', flexDirection: 'column', gap: 11 }}>
          <div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink-2)' }}>เงินประกันสัญญา (ถ้ามี)</div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
            <Field label="จำนวนเงิน"><input className="input right mono" value={f.retention} onChange={(e) => set('retention', e.target.value)} placeholder="0.00" /></Field>
            <Field label="อัตรา (%)"><input className="input right mono" value={f.retRate} onChange={(e) => set('retRate', e.target.value)} placeholder="5" /></Field>
            <Field label="ระยะประกัน (ปี)"><input className="input right mono" value={f.retYears} onChange={(e) => set('retYears', e.target.value)} placeholder="1" /></Field>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <Field label="วันครบกำหนดคืน"><ThaiDatePicker value={f.retDueISO || ''} onChange={(v) => set('retDueISO', v)} placeholder="เลือกวันครบกำหนด" /></Field>
            <Field label="สถานะเงินประกัน"><select className="select" value={f.retStatus} onChange={(e) => set('retStatus', e.target.value)}>{Object.entries(D.retStatusInfo).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}</select></Field>
          </div>
        </div>
      </div>
    </Modal>
  );
}

// helpers
function thDate(iso) {
  const d = new Date(iso);
  return d.getDate() + ' ' + D.thMonthsShort[d.getMonth()] + ' ' + ((d.getFullYear() + 543) % 100);
}
function todayTh() {
  const d = new Date();
  return d.getDate() + ' ' + D.thMonthsShort[d.getMonth()] + ' ' + String((d.getFullYear() + 543) % 100).padStart(2, '0');
}
function remainLabel(mo) {
  if (mo <= 0) return 'ครบแล้ว';
  if (mo < 12) return mo + ' เดือน';
  const y = Math.floor(mo / 12), m = mo % 12;
  return y + ' ปี' + (m ? ' ' + m + ' เดือน' : '');
}

window.ReceivablesPage = ReceivablesPage;
