// Petty Cash module (ระบบเงินสดย่อย) — frontend.
// Pages exposed on window:
//   • PettyCashPage      — "เงินสดย่อยของฉัน" : 3 tabs (ผู้ขอเบิก / ผู้อนุมัติ / ผู้รักษาเงิน)
//   • PettyCashFundsPage — "จัดการวงเงิน" (admin)
// All authority lives in the backend; this is the view layer. Money via formatMoney.

// ---------------------------------------------------------------------------
// Status meta (mirrors petty-cash-logic.js labels)
// ---------------------------------------------------------------------------
const PC_STATUS_META = {
  DRAFT:                { label: "ร่าง",            color: "slate",   icon: "edit" },
  PENDING_APPROVAL:     { label: "รออนุมัติ",       color: "amber",   icon: "clock" },
  REJECTED:             { label: "ตีกลับแก้ไข",     color: "rose",    icon: "x" },
  WAITING_DISBURSEMENT: { label: "รอรับเงิน",       color: "sky",     icon: "send" },
  WAITING_CLEAR:        { label: "รอเคลียร์",       color: "violet",  icon: "fileText" },
  COMPLETED:            { label: "สำเร็จ",          color: "emerald", icon: "checkCircle" },
  CANCELLED:            { label: "ยกเลิก",          color: "slate",   icon: "ban" },
};
const PCStatusBadge = ({ status }) => {
  const m = PC_STATUS_META[status] || { label: status, color: "slate", icon: "info" };
  return <Badge color={m.color} icon={m.icon}>{m.label}</Badge>;
};
const PC_SETTLEMENT_LABEL = {
  REFUND_TO_FUND:      "คืนเข้าวง (ใช้ไม่หมด)",
  REIMBURSE_REQUESTER: "บริษัทคืนผู้ขอเบิก (ใช้เกิน)",
  EXACT:               "พอดี",
};
const PC_REFUND_METHODS = [
  { code: "CASH", label: "เงินสด" },
  { code: "TRANSFER", label: "โอน" },
  { code: "OTHER", label: "อื่นๆ" },
];
const canManagePettyCashUi = (role) => role === "admin" || role === "super_admin";

// Resolve a user's display name from the hydrated users[] (identity OR api id).
const pcUserName = (uid, users) => {
  if (!uid) return "—";
  const u = (users || []).find(x => x.id === uid || x.api_user_id === uid);
  if (!u) return uid;
  return (typeof displayName === "function") ? displayName(u) : (u.full_name || u.email || uid);
};

// ===========================================================================
// CREATE REQUEST MODAL
// ===========================================================================
const CreatePettyCashRequestModal = ({ tenant, currentUser, users, funds, presetFundId, onClose, onSaved }) => {
  const toast = useToast();
  const myId = currentUser?.id || currentUser?.api_user_id;
  const [fundId, setFundId] = useState(presetFundId || "");
  const [approverId, setApproverId] = useState("");
  const [item, setItem] = useState("");
  const [amount, setAmount] = useState("");
  const [reason, setReason] = useState("");
  const [busy, setBusy] = useState(false);

  // Only active funds that currently have an OPEN round can take requests.
  const eligible = useMemo(() => (funds || []).filter(f => f.is_active && f.open_round_id), [funds]);
  const selectedFund = eligible.find(f => f.id === fundId);
  const approverOptions = useMemo(() =>
    (users || []).filter(u => u.from_api && u.id !== myId && u.api_user_id !== myId)
      .map(u => ({ id: u.id, label: pcUserName(u.id, users), email: u.email })),
  [users, myId]);

  const submit = async (mode) => {
    if (!fundId) { toast({ kind:"error", msg:"กรุณาเลือกวงเงิน" }); return; }
    if (!item.trim()) { toast({ kind:"error", msg:"กรุณาระบุสินค้า/บริการ" }); return; }
    const amt = Number(amount);
    if (!isFinite(amt) || amt <= 0) { toast({ kind:"error", msg:"จำนวนเงินต้องมากกว่า 0" }); return; }
    if (mode === "submit" && !approverId) { toast({ kind:"error", msg:"กรุณาเลือกผู้อนุมัติ" }); return; }
    setBusy(true);
    try {
      const res = await window.apiClient.pcRequestCreate(tenant.id, {
        fund_id: fundId, approver_user_id: approverId || null,
        item_description: item.trim(), requested_amount: amt, reason: reason || null,
        mode,
      });
      toast({ kind:"success", msg: mode === "draft" ? "บันทึกร่างแล้ว" : `ส่งคำขอ ${res.doc_number} แล้ว` });
      onSaved && onSaved();
      onClose && onClose();
    } catch (e) { toast({ kind:"error", msg: e.message || "บันทึกไม่สำเร็จ" }); }
    finally { setBusy(false); }
  };

  return (
    <Modal open onClose={onClose} title="สร้างใบขอเบิกเงินสดย่อย" width={640}>
      <div className="space-y-3">
        <Field label="วงเงิน *" hint="เฉพาะวงที่เปิดรอบอยู่">
          <Select value={fundId} onChange={e=>setFundId(e.target.value)}>
            <option value="">— เลือกวงเงิน —</option>
            {eligible.map(f => (
              <option key={f.id} value={f.id}>{f.fund_code} · {f.name} (คงเหลือ {formatMoney(f.open_available_balance ?? 0)})</option>
            ))}
          </Select>
          {eligible.length === 0 && (
            <div className="text-[11px] text-rose-700 mt-1">⚠ ยังไม่มีวงเงินที่เปิดรอบ — ให้ผู้รักษาเงินเปิดรอบก่อน</div>
          )}
        </Field>
        {selectedFund && (
          <div className="rounded-lg border border-sky-200 bg-sky-50/60 px-3 py-2 text-[12px] text-sky-900">
            ผู้รักษาเงิน: <strong>{pcUserName(selectedFund.custodian_user_id, users)}</strong> · ยอดคงเหลือในรอบ: <strong>{formatMoney(selectedFund.open_available_balance ?? 0)}</strong>
          </div>
        )}
        <Field label="ผู้อนุมัติ *" hint="เลือกผู้อื่นในบริษัท">
          <Select value={approverId} onChange={e=>setApproverId(e.target.value)}>
            <option value="">— เลือกผู้อนุมัติ —</option>
            {approverOptions.map(u => <option key={u.id} value={u.id}>{u.label} ({u.email})</option>)}
          </Select>
        </Field>
        <Field label="สินค้า / บริการ *">
          <Input value={item} onChange={e=>setItem(e.target.value)} placeholder="เช่น กระดาษ A4, ค่าเดินทาง"/>
        </Field>
        <Field label="จำนวนเงินที่ขอเบิก (บาท) *">
          <Input type="number" min="0" step="0.01" value={amount} onChange={e=>setAmount(e.target.value)}/>
        </Field>
        <Field label="เหตุผลการขอเบิก">
          <Textarea rows={2} value={reason} onChange={e=>setReason(e.target.value)}/>
        </Field>
      </div>
      <div className="mt-5 flex justify-end gap-2">
        <Button variant="ghost" onClick={onClose}>ยกเลิก</Button>
        <Button variant="secondary" icon="edit" onClick={()=>submit("draft")} disabled={busy}>บันทึกร่าง</Button>
        <Button variant="primary" icon="send" onClick={()=>submit("submit")} disabled={busy}>
          {busy ? "กำลังส่ง…" : "ส่งขออนุมัติ"}
        </Button>
      </div>
    </Modal>
  );
};

// ===========================================================================
// CLEAR MODAL (popup เคลียร์เงิน) — actual amount + attachment(s) + refund method
// ===========================================================================
const ClearPettyCashModal = ({ tenant, request, onClose, onDone }) => {
  const toast = useToast();
  const [actual, setActual] = useState("");
  const [refundMethod, setRefundMethod] = useState("CASH");
  const [refundNote, setRefundNote] = useState("");
  const [files, setFiles] = useState([]);          // already-uploaded attachments
  const [busy, setBusy] = useState(false);
  const [uploading, setUploading] = useState(false);

  const reloadFiles = async () => {
    try {
      const d = await window.apiClient.pcRequestGet(tenant.id, request.id);
      setFiles(d.attachments || []);
    } catch {}
  };
  useEffect(() => { reloadFiles(); /* eslint-disable-next-line */ }, [request.id]);

  const requested = Number(request.requested_amount || 0);
  const actualNum = Number(actual);
  const diff = isFinite(actualNum) ? Math.round((requested - actualNum) * 100) / 100 : null;
  const settlement = diff === null ? null : diff > 0 ? "REFUND_TO_FUND" : diff < 0 ? "REIMBURSE_REQUESTER" : "EXACT";

  const upload = async (file) => {
    if (!file) return;
    if (file.size > 10 * 1024 * 1024) { toast({ kind:"error", msg:"ไฟล์เกิน 10MB" }); return; }
    setUploading(true);
    try {
      await window.apiClient.pcUploadAttachment(tenant.id, request.id, file, { stage: "clearing" });
      await reloadFiles();
    } catch (e) { toast({ kind:"error", msg: e.message || "อัปโหลดไม่สำเร็จ" }); }
    finally { setUploading(false); }
  };
  const removeFile = async (att) => {
    try { await window.apiClient.pcDeleteAttachment(tenant.id, request.id, att.id); await reloadFiles(); }
    catch (e) { toast({ kind:"error", msg: e.message }); }
  };

  const submit = async () => {
    if (!isFinite(actualNum) || actualNum < 0) { toast({ kind:"error", msg:"กรุณากรอกจำนวนเงินที่ใช้จริง" }); return; }
    if (files.length < 1) { toast({ kind:"error", msg:"ต้องแนบไฟล์อย่างน้อย 1 ไฟล์" }); return; }
    if (settlement !== "EXACT" && !refundMethod) { toast({ kind:"error", msg:"กรุณาเลือกช่องทางคืนเงิน" }); return; }
    setBusy(true);
    try {
      await window.apiClient.pcRequestClear(tenant.id, request.id, {
        actual_amount: actualNum,
        refund_method: settlement === "EXACT" ? null : refundMethod,
        refund_note: refundNote || null,
      });
      toast({ kind:"success", msg:"เคลียร์เงินสดย่อยสำเร็จ" });
      onDone && onDone();
      onClose && onClose();
    } catch (e) { toast({ kind:"error", msg: e.message || "เคลียร์ไม่สำเร็จ" }); }
    finally { setBusy(false); }
  };

  return (
    <Modal open onClose={onClose} title={`เคลียร์เงินสดย่อย · ${request.doc_number}`} width={620}>
      <div className="space-y-3">
        <div className="rounded-lg border border-ink-100 bg-ink-50/60 px-3 py-2 text-[12.5px]">
          <div>{request.item_description}</div>
          <div className="text-ink-500 mt-0.5">ขอเบิก: <strong>{formatMoney(requested)}</strong></div>
        </div>
        <Field label="จำนวนเงินที่ใช้จริง (บาท) *">
          <Input type="number" min="0" step="0.01" value={actual} onChange={e=>setActual(e.target.value)} autoFocus/>
        </Field>
        {settlement && (
          <div className={`rounded-lg px-3 py-2 text-[12.5px] border ${
            settlement === "REFUND_TO_FUND" ? "border-amber-200 bg-amber-50/60 text-amber-900" :
            settlement === "REIMBURSE_REQUESTER" ? "border-violet-200 bg-violet-50/60 text-violet-900" :
            "border-emerald-200 bg-emerald-50/60 text-emerald-900"}`}>
            {settlement === "REFUND_TO_FUND" && <>เหลือต้องคืนเข้าวง: <strong>{formatMoney(diff)}</strong></>}
            {settlement === "REIMBURSE_REQUESTER" && <>ใช้เกิน บริษัทคืนให้ผู้ขอเบิก: <strong>{formatMoney(-diff)}</strong></>}
            {settlement === "EXACT" && <>พอดี ไม่มีเงินคืน</>}
          </div>
        )}
        {settlement && settlement !== "EXACT" && (
          <div className="grid grid-cols-2 gap-3">
            <Field label="ช่องทางคืนเงิน *">
              <Select value={refundMethod} onChange={e=>setRefundMethod(e.target.value)}>
                {PC_REFUND_METHODS.map(m => <option key={m.code} value={m.code}>{m.label}</option>)}
              </Select>
            </Field>
            <Field label="หมายเหตุ (เลขอ้างอิงโอน ฯลฯ)">
              <Input value={refundNote} onChange={e=>setRefundNote(e.target.value)}/>
            </Field>
          </div>
        )}
        <Field label="แนบไฟล์ใบเสร็จ * (อย่างน้อย 1)">
          <input type="file" accept=".pdf,.jpg,.jpeg,.png,.docx,.xlsx" disabled={uploading}
            onChange={e=>{ const f = e.target.files?.[0]; if (f) upload(f); e.target.value=""; }}
            className="block w-full text-[12px] file:mr-3 file:px-3 file:py-1.5 file:rounded-md file:border-0 file:bg-brand-50 file:text-brand-700 hover:file:bg-brand-100"/>
          {uploading && <div className="text-[11px] text-ink-500 mt-1">กำลังอัปโหลด…</div>}
        </Field>
        {files.length > 0 && (
          <div className="space-y-1">
            {files.map(f => (
              <div key={f.id} className="flex items-center gap-2 text-[12px] px-2.5 py-1.5 rounded-lg border border-ink-100 bg-white">
                <Icon name="paperclip" size={13} className="text-ink-500"/>
                <span className="flex-1 truncate">{f.filename} · {formatBytes(f.file_size || 0)}</span>
                <button onClick={()=>removeFile(f)} className="text-rose-600 hover:underline text-[11px]">ลบ</button>
              </div>
            ))}
          </div>
        )}
      </div>
      <div className="mt-5 flex justify-end gap-2">
        <Button variant="ghost" onClick={onClose}>ยกเลิก</Button>
        <Button variant="primary" icon="checkCircle" onClick={submit} disabled={busy || uploading}>
          {busy ? "กำลังเคลียร์…" : "ยืนยันเคลียร์เงิน"}
        </Button>
      </div>
    </Modal>
  );
};

// ===========================================================================
// REQUEST DETAIL DRAWER — info + attachments + timeline + role-aware actions
// ===========================================================================
const PettyCashRequestDrawer = ({ tenant, currentUser, currentRole, requestId, users, onClose, onChanged }) => {
  const toast = useToast();
  const myId = currentUser?.id || currentUser?.api_user_id;
  const [d, setD] = useState(null);
  const [loading, setLoading] = useState(false);
  const [rejectMode, setRejectMode] = useState(false);
  const [rejectReason, setRejectReason] = useState("");
  const [clearOpen, setClearOpen] = useState(false);
  const [preview, setPreview] = useState(null);
  const [busy, setBusy] = useState(false);
  const closePreview = () => { if (preview?.url) { try { URL.revokeObjectURL(preview.url); } catch {} } setPreview(null); };

  const reload = async () => {
    setLoading(true);
    try { setD(await window.apiClient.pcRequestGet(tenant.id, requestId)); }
    catch (e) { toast({ kind:"error", msg: e.message || "โหลดไม่สำเร็จ" }); }
    finally { setLoading(false); }
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [requestId]);

  const act = async (fn, okMsg) => {
    setBusy(true);
    try { await fn(); toast({ kind:"success", msg: okMsg }); await reload(); onChanged && onChanged(); }
    catch (e) { toast({ kind:"error", msg: e.message || "ดำเนินการไม่สำเร็จ" }); }
    finally { setBusy(false); }
  };
  const downloadAtt = async (att, asPreview) => {
    try {
      const blob = await window.apiClient.pcDownloadAttachmentBlob(tenant.id, requestId, att.id);
      const url = URL.createObjectURL(blob);
      if (asPreview && window.FAFilePreviewModal) setPreview({ url, contentType: att.content_type || blob.type, filename: att.filename, att });
      else { const a = document.createElement("a"); a.href = url; a.download = att.filename; document.body.appendChild(a); a.click(); a.remove(); setTimeout(()=>URL.revokeObjectURL(url), 1000); }
    } catch (e) { toast({ kind:"error", msg: e.message }); }
  };

  if (!d && loading) return <Drawer open onClose={onClose} title="กำลังโหลด…" width={640}><div className="p-6 text-center text-ink-500">กำลังโหลด…</div></Drawer>;
  if (!d) return null;

  const isRequester = d.requester_user_id === myId;
  const isApprover = d.approver_user_id === myId;
  const isCustodian = d.custodian_user_id === myId;

  return (
    <Drawer open onClose={onClose} title={d.doc_number} subtitle={`${d.fund_code} · ${d.item_description}`} width={680}>
      <div className="flex items-center gap-2 mb-3">
        <PCStatusBadge status={d.status}/>
        <span className="ml-auto text-[13px] font-semibold text-ink-900">{formatMoney(d.requested_amount)}</span>
      </div>

      <div className="grid grid-cols-2 gap-3 text-[12.5px] mb-3">
        <KVp label="วงเงิน" value={`${d.fund_code} · ${d.fund_name}`}/>
        <KVp label="จำนวนที่ขอเบิก" value={formatMoney(d.requested_amount)}/>
        <KVp label="ผู้ขอเบิก" value={pcUserName(d.requester_user_id, users)}/>
        <KVp label="ผู้อนุมัติ" value={pcUserName(d.approver_user_id, users)}/>
        <KVp label="ผู้รักษาเงิน" value={pcUserName(d.custodian_user_id, users)}/>
        <KVp label="สร้างเมื่อ" value={formatDateTime(d.created_at)}/>
        <div className="col-span-2"><KVp label="สินค้า/บริการ" value={d.item_description}/></div>
        {d.reason && <div className="col-span-2"><KVp label="เหตุผล" value={d.reason}/></div>}
        {d.reject_reason && (
          <div className="col-span-2 rounded-lg border border-rose-200 bg-rose-50/60 p-2.5 text-rose-800">
            <div className="text-[10.5px] uppercase tracking-wider font-semibold mb-0.5">เหตุผลที่ตีกลับ</div>
            <div className="whitespace-pre-wrap">{d.reject_reason}</div>
          </div>
        )}
      </div>

      {/* Clearing result */}
      {d.clearing && (
        <div className="rounded-lg border border-emerald-200 bg-emerald-50/50 p-3 mb-3 text-[12.5px] text-emerald-900">
          <div className="text-[10.5px] uppercase tracking-wider font-semibold mb-1">ผลการเคลียร์</div>
          <div>ใช้จริง: <strong>{formatMoney(d.clearing.actual_amount)}</strong> · {PC_SETTLEMENT_LABEL[d.clearing.settlement_type]}</div>
          {d.clearing.settlement_type !== "EXACT" && (
            <div>ส่วนต่าง: <strong>{formatMoney(Math.abs(d.clearing.difference))}</strong> · ช่องทาง: {PC_REFUND_METHODS.find(m=>m.code===d.clearing.refund_method)?.label || "—"}{d.clearing.refund_note ? ` · ${d.clearing.refund_note}` : ""}</div>
          )}
        </div>
      )}

      {/* Attachments */}
      <div className="text-[11px] uppercase tracking-wider text-ink-500 font-semibold mb-1.5">ไฟล์แนบ ({(d.attachments||[]).length})</div>
      {(d.attachments || []).length === 0 ? (
        <div className="rounded-xl border-2 border-dashed border-ink-200 bg-ink-50/30 p-3 text-center text-[12px] text-ink-500 mb-3">— ไม่มีไฟล์แนบ —</div>
      ) : (d.attachments).map(att => (
        <div key={att.id} className="flex items-center gap-3 px-3 py-2 mb-1.5 rounded-lg border border-ink-100 bg-white">
          <Icon name="paperclip" size={14} className="text-ink-500"/>
          <div className="flex-1 min-w-0"><div className="text-[12.5px] text-ink-900 truncate">{att.filename}</div><div className="text-[10.5px] text-ink-500">{formatBytes(att.file_size||0)}</div></div>
          <Button variant="ghost" icon="eye" onClick={()=>downloadAtt(att, true)}>ดู</Button>
          <Button variant="ghost" icon="download" onClick={()=>downloadAtt(att, false)}>โหลด</Button>
        </div>
      ))}

      {/* Timeline */}
      <div className="text-[11px] uppercase tracking-wider text-ink-500 font-semibold mb-1.5 mt-3">ประวัติ (Timeline)</div>
      <div className="space-y-1.5 mb-3">
        {(d.audit || []).map(a => (
          <div key={a.id} className="flex items-start gap-2 text-[11.5px]">
            <Icon name="clock" size={12} className="text-ink-400 mt-0.5"/>
            <div className="flex-1">
              <span className="text-ink-800">{a.action}</span>
              {a.to_status && <span className="text-ink-500"> → {PC_STATUS_META[a.to_status]?.label || a.to_status}</span>}
              {a.note && <span className="text-ink-500"> · {a.note}</span>}
              <span className="text-ink-400"> · {pcUserName(a.actor_user_id, users)} · {formatDateTime(a.created_at)}</span>
            </div>
          </div>
        ))}
      </div>

      {/* Action footer — role + status aware */}
      <div className="border-t border-ink-100 pt-3">
        {rejectMode ? (
          <div className="space-y-2">
            <Field label="เหตุผลที่ตีกลับ *"><Textarea rows={3} value={rejectReason} onChange={e=>setRejectReason(e.target.value)}/></Field>
            <div className="flex justify-end gap-2">
              <Button variant="ghost" onClick={()=>{ setRejectMode(false); setRejectReason(""); }}>ยกเลิก</Button>
              <Button variant="danger" icon="x" disabled={busy} onClick={()=>{
                if (!rejectReason.trim()) { toast({ kind:"error", msg:"กรุณาระบุเหตุผล" }); return; }
                act(()=>window.apiClient.pcRequestReject(tenant.id, requestId, rejectReason.trim()), "ตีกลับแล้ว").then(()=>{ setRejectMode(false); setRejectReason(""); });
              }}>ยืนยันตีกลับ</Button>
            </div>
          </div>
        ) : (
          <div className="flex items-center gap-2 justify-end flex-wrap">
            {/* approver */}
            {isApprover && d.status === "PENDING_APPROVAL" && (<>
              <Button variant="ghost" icon="x" onClick={()=>setRejectMode(true)}>ตีกลับ</Button>
              <Button variant="primary" icon="checkCircle" disabled={busy} onClick={()=>act(()=>window.apiClient.pcRequestApprove(tenant.id, requestId), "อนุมัติแล้ว")}>อนุมัติ</Button>
            </>)}
            {/* custodian */}
            {isCustodian && d.status === "WAITING_DISBURSEMENT" && (
              <Button variant="primary" icon="send" disabled={busy} onClick={()=>act(()=>window.apiClient.pcRequestMarkDisbursed(tenant.id, requestId), "ส่งมอบเงินแล้ว")}>ส่งมอบเงินแล้ว</Button>
            )}
            {/* requester */}
            {isRequester && d.status === "WAITING_CLEAR" && (
              <Button variant="primary" icon="checkCircle" onClick={()=>setClearOpen(true)}>เคลียร์เงินสดย่อย</Button>
            )}
            {isRequester && ["DRAFT","REJECTED"].includes(d.status) && (
              <Button variant="primary" icon="send" disabled={busy} onClick={()=>act(()=>window.apiClient.pcRequestSubmit(tenant.id, requestId), "ส่งขออนุมัติแล้ว")}>ส่งขออนุมัติ</Button>
            )}
            {isRequester && ["PENDING_APPROVAL","REJECTED"].includes(d.status) && (
              <Button variant="ghost" icon="ban" disabled={busy} onClick={()=>{ if(confirm("ยกเลิกใบขอเบิกนี้?")) act(()=>window.apiClient.pcRequestCancel(tenant.id, requestId), "ยกเลิกแล้ว"); }}>ยกเลิกใบ</Button>
            )}
            {["COMPLETED","CANCELLED"].includes(d.status) && <span className="text-[11.5px] text-ink-400">รายการนี้สิ้นสุดแล้ว</span>}
          </div>
        )}
      </div>

      {clearOpen && <ClearPettyCashModal tenant={tenant} request={d} onClose={()=>setClearOpen(false)} onDone={()=>{ reload(); onChanged && onChanged(); }}/>}
      {window.FAFilePreviewModal && <window.FAFilePreviewModal preview={preview} onClose={closePreview} onDownload={()=>{ if(preview?.att) downloadAtt(preview.att, false); }}/>}
    </Drawer>
  );
};
const KVp = ({ label, value }) => (
  <div className="rounded-lg border border-ink-100 bg-white px-3 py-2">
    <div className="text-[10.5px] uppercase tracking-wider text-ink-400 font-semibold">{label}</div>
    <div className="text-ink-900 mt-0.5 break-words">{value}</div>
  </div>
);

// ===========================================================================
// FUND EDIT MODAL (admin)
// ===========================================================================
const FundEditModal = ({ tenant, users, initial, onClose, onSaved }) => {
  const toast = useToast();
  const isEdit = !!initial?.id;
  const [form, setForm] = useState(() => ({
    fund_code: initial?.fund_code || "",
    name: initial?.name || "",
    limit_amount: initial?.limit_amount ?? "",
    custodian_user_id: initial?.custodian_user_id || "",
    remark: initial?.remark || "",
  }));
  const set = (p) => setForm(prev => ({ ...prev, ...p }));
  const [busy, setBusy] = useState(false);
  const memberOptions = useMemo(() => (users || []).filter(u => u.from_api)
    .map(u => ({ id: u.id, label: pcUserName(u.id, users), email: u.email })), [users]);

  const save = async () => {
    if (!isEdit && !form.fund_code.trim()) { toast({ kind:"error", msg:"กรุณาระบุรหัสวงเงิน" }); return; }
    if (!form.name.trim()) { toast({ kind:"error", msg:"กรุณาระบุชื่อวงเงิน" }); return; }
    const limit = Number(form.limit_amount);
    if (!isFinite(limit) || limit <= 0) { toast({ kind:"error", msg:"วงเงินต้องมากกว่า 0" }); return; }
    setBusy(true);
    try {
      if (isEdit) {
        await window.apiClient.pcFundUpdate(tenant.id, initial.id, { name: form.name.trim(), limit_amount: limit, custodian_user_id: form.custodian_user_id || null, remark: form.remark || null });
        toast({ kind:"success", msg:"บันทึกแล้ว" });
      } else {
        await window.apiClient.pcFundCreate(tenant.id, { fund_code: form.fund_code.trim().toUpperCase(), name: form.name.trim(), limit_amount: limit, custodian_user_id: form.custodian_user_id || null, remark: form.remark || null });
        toast({ kind:"success", msg:"สร้างวงเงินแล้ว" });
      }
      onSaved && onSaved(); onClose && onClose();
    } catch (e) { toast({ kind:"error", msg: e.message || "บันทึกไม่สำเร็จ" }); }
    finally { setBusy(false); }
  };

  return (
    <Modal open onClose={onClose} title={isEdit ? `แก้ไขวงเงิน · ${initial.fund_code}` : "สร้างวงเงินใหม่"} width={560}>
      <div className="grid grid-cols-2 gap-3">
        <Field label="รหัสวงเงิน *" hint={isEdit ? "แก้ไขไม่ได้" : "A-Z 0-9 (≤20)"}>
          <Input value={form.fund_code} onChange={e=>set({ fund_code: e.target.value.toUpperCase() })} disabled={isEdit} placeholder="เช่น FRONT"/>
        </Field>
        <Field label="วงเงินเต็ม (บาท) *">
          <Input type="number" min="0" step="0.01" value={form.limit_amount} onChange={e=>set({ limit_amount: e.target.value })}/>
        </Field>
        <Field label="ชื่อวงเงิน *" className="col-span-2">
          <Input value={form.name} onChange={e=>set({ name: e.target.value })} placeholder="เช่น เงินสดย่อยหน้าร้าน"/>
        </Field>
        <Field label="ผู้รักษาเงินสดย่อย" className="col-span-2" hint="ผู้เปิด/ปิดรอบ + จ่ายเงิน">
          <Select value={form.custodian_user_id} onChange={e=>set({ custodian_user_id: e.target.value })}>
            <option value="">— เลือกผู้รักษาเงิน —</option>
            {memberOptions.map(u => <option key={u.id} value={u.id}>{u.label} ({u.email})</option>)}
          </Select>
        </Field>
        <Field label="หมายเหตุ" className="col-span-2"><Textarea rows={2} value={form.remark} onChange={e=>set({ remark: e.target.value })}/></Field>
      </div>
      <div className="mt-5 flex justify-end gap-2">
        <Button variant="ghost" onClick={onClose}>ยกเลิก</Button>
        <Button variant="primary" icon="check" onClick={save} disabled={busy}>{busy ? "กำลังบันทึก…" : (isEdit ? "บันทึก" : "สร้างวงเงิน")}</Button>
      </div>
    </Modal>
  );
};

// ===========================================================================
// FUNDS ADMIN PAGE — จัดการวงเงิน
// ===========================================================================
const PettyCashFundsPage = ({ tenant, currentUser, currentRole, users }) => {
  const toast = useToast();
  const canManage = canManagePettyCashUi(currentRole);
  const [rows, setRows] = useState([]);
  const [loading, setLoading] = useState(false);
  const [editFor, setEditFor] = useState(null);  // "new" | fund

  const reload = async () => {
    if (!tenant?.id) return;
    setLoading(true);
    try { setRows(await window.apiClient.pcFundsList(tenant.id, { status: "__all__" })); }
    catch (e) { toast({ kind:"error", msg: e.message || "โหลดไม่สำเร็จ" }); }
    finally { setLoading(false); }
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [tenant?.id]);

  const toggle = async (f) => {
    try { await window.apiClient.pcFundToggleActive(tenant.id, f.id); reload(); }
    catch (e) { toast({ kind:"error", msg: e.message }); }
  };

  return (
    <div className="p-6 max-w-[1200px] mx-auto">
      <div className="text-[11px] tracking-wider text-sky-700 font-bold mb-1">▦ PETTY CASH · FUNDS</div>
      <div className="flex items-start justify-between gap-3 mb-3">
        <div>
          <div className="text-[24px] font-bold text-ink-900 leading-tight">จัดการวงเงินสดย่อย</div>
          <div className="text-[13px] text-ink-500 mt-1">สร้าง / แก้ไขวงเงิน · กำหนดผู้รักษาเงิน · เปิด-ปิดใช้งาน</div>
        </div>
        {canManage
          ? <Button variant="primary" icon="plus" onClick={()=>setEditFor("new")}>สร้างวงเงินใหม่</Button>
          : <Badge color="slate" icon="eye">🚫 อ่านอย่างเดียว</Badge>}
      </div>
      {!canManage && (
        <div className="rounded-lg border border-amber-200 bg-amber-50/60 px-3 py-2 text-[12px] text-amber-900 mb-3">
          🚫 เฉพาะ Admin / Super Admin เท่านั้นที่จัดการวงเงินได้
        </div>
      )}
      <div className="rounded-xl border border-ink-100 bg-white overflow-hidden">
        <div className="overflow-x-auto">
          <table className="w-full text-[12.5px]">
            <thead className="bg-ink-50 text-ink-600 text-[11px] uppercase tracking-wider">
              <tr>
                <th className="px-3 py-2 text-left">รหัส</th>
                <th className="px-3 py-2 text-left">ชื่อวงเงิน</th>
                <th className="px-3 py-2 text-right">วงเงินเต็ม</th>
                <th className="px-3 py-2 text-left">ผู้รักษาเงิน</th>
                <th className="px-3 py-2 text-left">รอบปัจจุบัน</th>
                <th className="px-3 py-2 text-right">คงเหลือ</th>
                <th className="px-3 py-2 text-center">สถานะ</th>
                <th className="px-3 py-2 text-right">Action</th>
              </tr>
            </thead>
            <tbody>
              {loading && <tr><td colSpan={8} className="px-3 py-6 text-center text-ink-500">กำลังโหลด…</td></tr>}
              {!loading && rows.length === 0 && <tr><td colSpan={8} className="px-3 py-10 text-center text-ink-500">ยังไม่มีวงเงิน — กด "สร้างวงเงินใหม่"</td></tr>}
              {rows.map(f => (
                <tr key={f.id} className="border-t border-ink-100 hover:bg-ink-50/50">
                  <td className="px-3 py-2 font-mono font-semibold text-ink-900">{f.fund_code}</td>
                  <td className="px-3 py-2 text-ink-900">{f.name}</td>
                  <td className="px-3 py-2 text-right font-mono">{formatMoney(f.limit_amount)}</td>
                  <td className="px-3 py-2 text-ink-700">{pcUserName(f.custodian_user_id, users)}</td>
                  <td className="px-3 py-2 text-ink-700">{f.open_round_id ? `รอบ #${f.open_round_number} (เปิด)` : <span className="text-ink-400">ยังไม่เปิดรอบ</span>}</td>
                  <td className="px-3 py-2 text-right font-mono">{f.open_round_id ? formatMoney(f.open_available_balance ?? 0) : "—"}</td>
                  <td className="px-3 py-2 text-center"><Badge color={f.is_active ? "emerald" : "slate"}>{f.is_active ? "ใช้งาน" : "ปิด"}</Badge></td>
                  <td className="px-3 py-2 text-right whitespace-nowrap">
                    {canManage && <>
                      <Button variant="ghost" icon="edit" onClick={()=>setEditFor(f)}>แก้ไข</Button>
                      <Button variant="ghost" icon={f.is_active ? "ban" : "check"} onClick={()=>toggle(f)}>{f.is_active ? "ปิด" : "เปิด"}</Button>
                    </>}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
      {editFor && <FundEditModal tenant={tenant} users={users} initial={editFor === "new" ? null : editFor} onClose={()=>setEditFor(null)} onSaved={reload}/>}
    </div>
  );
};

// ===========================================================================
// MAIN PAGE — เงินสดย่อยของฉัน (3 tabs)
// ===========================================================================
const PettyCashPage = ({ tenant, currentUser, currentRole, users }) => {
  const toast = useToast();
  const myId = currentUser?.id || currentUser?.api_user_id;
  const [tab, setTab] = useState("requester");
  const [funds, setFunds] = useState([]);
  const [myReqs, setMyReqs] = useState([]);
  const [approverReqs, setApproverReqs] = useState([]);
  const [custodianReqs, setCustodianReqs] = useState([]);
  const [managedFundDetails, setManagedFundDetails] = useState([]); // funds I'm custodian of, with rounds
  const [loading, setLoading] = useState(false);
  const [createOpen, setCreateOpen] = useState(false);
  const [openReqId, setOpenReqId] = useState(null);
  const [busy, setBusy] = useState(false);

  const managedFunds = useMemo(() => (funds || []).filter(f => f.custodian_user_id === myId), [funds, myId]);
  const showCustodianTab = managedFunds.length > 0;

  const reload = async () => {
    if (!tenant?.id) return;
    setLoading(true);
    try {
      const [fundsList, mine, asApprover] = await Promise.all([
        window.apiClient.pcFundsList(tenant.id, { status: "active" }),
        window.apiClient.pcRequestsList(tenant.id, { scope: "requester" }),
        window.apiClient.pcRequestsList(tenant.id, { scope: "approver", status: "PENDING_APPROVAL" }),
      ]);
      setFunds(Array.isArray(fundsList) ? fundsList : []);
      setMyReqs(Array.isArray(mine) ? mine : []);
      setApproverReqs(Array.isArray(asApprover) ? asApprover : []);
      // custodian: waiting-disbursement requests + managed fund details (rounds)
      const mf = (Array.isArray(fundsList) ? fundsList : []).filter(f => f.custodian_user_id === myId);
      if (mf.length > 0) {
        const [waiting, details] = await Promise.all([
          window.apiClient.pcRequestsList(tenant.id, { scope: "custodian", status: "WAITING_DISBURSEMENT" }),
          Promise.all(mf.map(f => window.apiClient.pcFundGet(tenant.id, f.id).catch(() => null))),
        ]);
        setCustodianReqs(Array.isArray(waiting) ? waiting : []);
        setManagedFundDetails(details.filter(Boolean));
      } else { setCustodianReqs([]); setManagedFundDetails([]); }
    } catch (e) { toast({ kind:"error", msg: e.message || "โหลดไม่สำเร็จ" }); }
    finally { setLoading(false); }
  };
  useEffect(() => { reload(); /* eslint-disable-next-line */ }, [tenant?.id]);

  const roundAct = async (fn, okMsg) => {
    setBusy(true);
    try { await fn(); toast({ kind:"success", msg: okMsg }); await reload(); }
    catch (e) { toast({ kind:"error", msg: e.message || "ดำเนินการไม่สำเร็จ" }); }
    finally { setBusy(false); }
  };

  const TABS = [
    { k: "requester", label: "ผู้ขอเบิก", n: myReqs.length },
    { k: "approver", label: "ผู้อนุมัติ", n: approverReqs.length },
    ...(showCustodianTab ? [{ k: "custodian", label: "ผู้รักษาเงิน", n: custodianReqs.length }] : []),
  ];

  const reqRow = (r) => (
    <tr key={r.id} className="border-t border-ink-100 hover:bg-ink-50/50 cursor-pointer" onClick={()=>setOpenReqId(r.id)}>
      <td className="px-3 py-2 font-mono font-semibold text-ink-900">{r.doc_number}</td>
      <td className="px-3 py-2 text-ink-700">{r.fund_code}</td>
      <td className="px-3 py-2 text-ink-900 truncate max-w-[240px]">{r.item_description}</td>
      <td className="px-3 py-2 text-right font-mono">{formatMoney(r.requested_amount)}</td>
      <td className="px-3 py-2 text-ink-700">{pcUserName(r.requester_user_id, users)}</td>
      <td className="px-3 py-2 text-center"><PCStatusBadge status={r.status}/></td>
      <td className="px-3 py-2 text-right"><Button variant="ghost" icon="eye" onClick={(e)=>{ e.stopPropagation(); setOpenReqId(r.id); }}>ดู</Button></td>
    </tr>
  );
  const reqTable = (rows, emptyMsg) => (
    <div className="rounded-xl border border-ink-100 bg-white overflow-hidden">
      <div className="overflow-x-auto"><table className="w-full text-[12.5px]">
        <thead className="bg-ink-50 text-ink-600 text-[11px] uppercase tracking-wider"><tr>
          <th className="px-3 py-2 text-left">เลขที่</th><th className="px-3 py-2 text-left">วง</th>
          <th className="px-3 py-2 text-left">รายการ</th><th className="px-3 py-2 text-right">จำนวน</th>
          <th className="px-3 py-2 text-left">ผู้ขอเบิก</th><th className="px-3 py-2 text-center">สถานะ</th>
          <th className="px-3 py-2 text-right">Action</th>
        </tr></thead>
        <tbody>
          {loading && <tr><td colSpan={7} className="px-3 py-6 text-center text-ink-500">กำลังโหลด…</td></tr>}
          {!loading && rows.length === 0 && <tr><td colSpan={7} className="px-3 py-10 text-center text-ink-500">{emptyMsg}</td></tr>}
          {rows.map(reqRow)}
        </tbody>
      </table></div>
    </div>
  );

  return (
    <div className="p-6 max-w-[1300px] mx-auto">
      <div className="text-[11px] tracking-wider text-sky-700 font-bold mb-1">▦ MY PETTY CASH</div>
      <div className="flex items-start justify-between gap-3 mb-3">
        <div>
          <div className="text-[24px] font-bold text-ink-900 leading-tight">เงินสดย่อยของฉัน</div>
          <div className="text-[13px] text-ink-500 mt-1">ขอเบิก · อนุมัติ · รักษาเงิน — ตามบทบาทของคุณ</div>
        </div>
        <div className="flex items-center gap-2">
          <Button variant="secondary" icon="refresh" onClick={reload} disabled={loading}>รีเฟรช</Button>
          <Button variant="primary" icon="plus" onClick={()=>setCreateOpen(true)}>สร้างใบขอเบิก</Button>
        </div>
      </div>

      <div className="flex items-center gap-1 border-b border-ink-200 mb-3 text-[12.5px]">
        {TABS.map(t => (
          <button key={t.k} onClick={()=>setTab(t.k)}
            className={`px-3 h-9 -mb-px border-b-2 transition flex items-center gap-1.5 ${tab===t.k?"border-brand-600 text-brand-700 font-semibold":"border-transparent text-ink-500 hover:text-ink-800"}`}>
            {t.label}{t.n > 0 && <span className="text-[10px] px-1.5 py-0.5 rounded-md bg-ink-100 text-ink-600">{t.n}</span>}
          </button>
        ))}
      </div>

      {tab === "requester" && reqTable(myReqs, "ยังไม่มีใบขอเบิก — กด \"สร้างใบขอเบิก\"")}
      {tab === "approver" && reqTable(approverReqs, "ไม่มีใบรออนุมัติของคุณ")}

      {tab === "custodian" && (
        <div className="space-y-4">
          {/* Managed funds — round controls */}
          {managedFundDetails.map(fd => {
            const open = (fd.rounds || []).find(r => r.status === "OPEN");
            const closed = (fd.rounds || []).find(r => r.status === "CLOSED");
            return (
              <div key={fd.id} className="rounded-xl border border-sky-200 bg-sky-50/40 p-4">
                <div className="flex items-center gap-3 flex-wrap">
                  <div className="flex-1 min-w-0">
                    <div className="text-[13px] font-semibold text-ink-900">{fd.fund_code} · {fd.name}</div>
                    <div className="text-[11.5px] text-ink-500">วงเงินเต็ม {formatMoney(fd.limit_amount)}
                      {open && <> · รอบ #{open.round_number} เปิดอยู่ · คงเหลือ <strong className="text-sky-800">{formatMoney(open.available_balance)}</strong></>}
                      {closed && <> · รอบ #{closed.round_number} ปิดแล้ว · คงเหลือ {formatMoney(closed.closing_balance)} · ต้องเบิกเพิ่ม {formatMoney(closed.replenish_amount)}</>}
                      {!open && !closed && <> · ยังไม่เปิดรอบ</>}
                    </div>
                  </div>
                  <div className="flex items-center gap-2">
                    {!open && !closed && <Button variant="primary" icon="plus" disabled={busy} onClick={()=>roundAct(()=>window.apiClient.pcRoundOpen(tenant.id, fd.id), "เปิดรอบแล้ว")}>เปิดรอบ</Button>}
                    {open && <Button variant="secondary" icon="ban" disabled={busy} onClick={()=>{ if(confirm("ปิดรอบนี้?")) roundAct(()=>window.apiClient.pcRoundClose(tenant.id, open.id), "ปิดรอบแล้ว"); }}>ปิดรอบ</Button>}
                    {closed && <Button variant="primary" icon="check" disabled={busy} onClick={()=>roundAct(()=>window.apiClient.pcRoundReceive(tenant.id, closed.id), "รับวงเงินแล้ว · เปิดรอบใหม่")}>รับวงเงิน</Button>}
                    {(open || closed) && <Button variant="ghost" icon="fileBarChart" onClick={()=>window.open(`?pcreport=${open?.id || closed.id}&pctenant=${tenant.id}`, "_blank")}>รายงานรอบ</Button>}
                  </div>
                </div>
              </div>
            );
          })}
          {/* Waiting disbursement */}
          <div>
            <div className="text-[12px] font-semibold text-ink-700 mb-1.5">รอรับเงิน (กด "ส่งมอบเงินแล้ว" หลังจ่ายเงินสดให้ผู้ขอเบิก)</div>
            {reqTable(custodianReqs, "ไม่มีใบรอจ่ายเงิน")}
          </div>
        </div>
      )}

      {createOpen && <CreatePettyCashRequestModal tenant={tenant} currentUser={currentUser} users={users} funds={funds} onClose={()=>setCreateOpen(false)} onSaved={reload}/>}
      {openReqId && <PettyCashRequestDrawer tenant={tenant} currentUser={currentUser} currentRole={currentRole} requestId={openReqId} users={users} onClose={()=>setOpenReqId(null)} onChanged={reload}/>}
    </div>
  );
};

// ===========================================================================
// ROUND REPORT — A4 print-friendly (opened standalone via ?pcreport=&pctenant=)
// ===========================================================================
const PettyCashRoundReport = ({ tenantId, roundId }) => {
  const [data, setData] = useState(null);
  const [users, setUsers] = useState([]);
  const [err, setErr] = useState("");
  useEffect(() => {
    if (!window.apiClient) return;
    Promise.all([
      window.apiClient.pcRoundReport(tenantId, roundId),
      window.apiClient.getUsers(tenantId).catch(() => []),
    ]).then(([rep, us]) => {
      setData(rep);
      setUsers((Array.isArray(us) ? us : []).map(u => ({
        id: u.user_id || u.id, api_user_id: u.user_id,
        full_name: ((u.first_name||'')+' '+(u.last_name||'')).trim() || u.email, email: u.email, nickname: u.nickname,
      })));
    }).catch(e => setErr(e.message || "โหลดรายงานไม่สำเร็จ"));
  }, [tenantId, roundId]);

  if (err) return <div style={{ padding: 40, fontFamily: "Sarabun, sans-serif" }}>⚠ {err}</div>;
  if (!data) return <div style={{ padding: 40, fontFamily: "Sarabun, sans-serif" }}>กำลังโหลดรายงาน…</div>;

  const { fund, round, requests } = data;
  const fmt = (n) => (typeof formatMoney === "function" ? formatMoney(n) : `฿${Number(n||0).toLocaleString()}`);
  const dt = (s) => s ? (typeof formatDate === "function" ? formatDate(String(s).slice(0,10)) : String(s).slice(0,10)) : "—";
  const uname = (uid) => pcUserName(uid, users);

  return (
    <div className="pc-report-root">
      <style>{`
        @page { size: A4; margin: 16mm; }
        .pc-report-root { font-family: 'Sarabun', sans-serif; color: #111; background: #f3f4f6; min-height: 100vh; padding: 24px; }
        .pc-sheet { background:#fff; max-width: 760px; margin: 0 auto; padding: 36px 40px; box-shadow: 0 2px 16px rgba(0,0,0,.12); }
        .pc-print-bar { max-width: 760px; margin: 0 auto 14px; display:flex; justify-content:flex-end; gap:8px; }
        .pc-btn { background:#0284c7; color:#fff; border:0; border-radius:8px; padding:8px 16px; font-size:14px; cursor:pointer; font-family:inherit; }
        .pc-btn.sec { background:#e5e7eb; color:#111; }
        .pc-h1 { font-size: 20px; font-weight: 700; text-align:center; margin: 0 0 2px; }
        .pc-h2 { font-size: 13px; text-align:center; color:#555; margin: 0 0 18px; }
        .pc-meta { display:grid; grid-template-columns: 1fr 1fr; gap: 4px 24px; font-size: 13px; margin-bottom: 18px; }
        .pc-meta b { color:#374151; }
        table.pc-tbl { width:100%; border-collapse: collapse; font-size: 12.5px; margin-bottom: 18px; }
        table.pc-tbl th, table.pc-tbl td { border: 1px solid #d1d5db; padding: 6px 8px; }
        table.pc-tbl th { background:#f3f4f6; text-align:left; }
        .pc-num { text-align: right; font-variant-numeric: tabular-nums; }
        .pc-recon { width: 320px; margin-left: auto; font-size: 13px; }
        .pc-recon div { display:flex; justify-content: space-between; padding: 3px 0; }
        .pc-recon .tot { border-top: 2px solid #111; font-weight: 700; margin-top: 4px; padding-top: 6px; }
        .pc-sign { display:flex; justify-content: space-between; margin-top: 48px; font-size: 13px; }
        .pc-sign div { width: 45%; text-align:center; }
        .pc-sign .line { border-top: 1px dotted #555; margin-top: 40px; padding-top: 6px; }
        @media print { .pc-report-root { background:#fff; padding:0; } .pc-sheet { box-shadow:none; max-width:none; padding:0; } .pc-print-bar { display:none; } }
      `}</style>
      <div className="pc-print-bar">
        <button className="pc-btn" onClick={()=>window.print()}>🖨 พิมพ์ / บันทึก PDF</button>
        <button className="pc-btn sec" onClick={()=>window.close()}>ปิด</button>
      </div>
      <div className="pc-sheet">
        <h1 className="pc-h1">รายงานเงินสดย่อยสิ้นรอบ</h1>
        <div className="pc-h2">{fund.name} ({fund.fund_code}) · รอบที่ {round.round_number}</div>
        <div className="pc-meta">
          <div><b>วงเงิน:</b> {fund.name} ({fund.fund_code})</div>
          <div><b>ผู้รักษาเงิน:</b> {uname(fund.custodian_user_id)}</div>
          <div><b>วงเงินเต็ม:</b> {fmt(fund.limit_amount)}</div>
          <div><b>สถานะรอบ:</b> {round.status}</div>
          <div><b>วันที่เปิดรอบ:</b> {dt(round.opened_at)}</div>
          <div><b>วันที่ปิดรอบ:</b> {dt(round.closed_at)}</div>
        </div>

        <table className="pc-tbl">
          <thead><tr>
            <th>เลขที่เอกสาร</th><th>ผู้ขอเบิก</th><th>รายการ</th>
            <th className="pc-num">ขอเบิก</th><th className="pc-num">ใช้จริง</th><th className="pc-num">ส่วนต่าง</th>
          </tr></thead>
          <tbody>
            {requests.length === 0 && <tr><td colSpan={6} style={{ textAlign:"center", color:"#888" }}>ไม่มีใบขอเบิกที่สำเร็จในรอบนี้</td></tr>}
            {requests.map(r => (
              <tr key={r.id}>
                <td>{r.doc_number}</td>
                <td>{uname(r.requester_user_id)}</td>
                <td>{r.item_description}</td>
                <td className="pc-num">{fmt(r.requested_amount)}</td>
                <td className="pc-num">{fmt(r.actual_amount)}</td>
                <td className="pc-num">{r.difference != null ? fmt(r.difference) : "—"}</td>
              </tr>
            ))}
          </tbody>
        </table>

        <div className="pc-recon">
          <div><span>เงินสดต้นรอบ</span><span>{fmt(round.opening_balance)}</span></div>
          <div><span>หัก จ่ายออก</span><span>- {fmt(round.total_disbursed)}</span></div>
          <div><span>บวก เงินคืนเข้าวง</span><span>+ {fmt(round.total_refunded)}</span></div>
          <div><span>หัก จ่ายเพิ่ม (ใช้เกิน)</span><span>- {fmt(round.total_overspend_reimbursed)}</span></div>
          <div className="tot"><span>คงเหลือสิ้นรอบ</span><span>{fmt(round.closing_balance)}</span></div>
          <div className="tot" style={{ borderTop:0 }}><span>ต้องขอเบิกเพิ่ม (เติมเต็มวง)</span><span>{fmt(round.replenish_amount)}</span></div>
        </div>

        <div className="pc-sign">
          <div><div className="line">ผู้รักษาเงินสดย่อย</div></div>
          <div><div className="line">ผู้อนุมัติ</div></div>
        </div>
      </div>
    </div>
  );
};

// ---------------------------------------------------------------------------
Object.assign(window, { PettyCashPage, PettyCashFundsPage, PettyCashRoundReport });
