/* ==========================================================================
 * ADMIN NEXT — page-creditmanage.jsx  (จัดการเครดิต)
 * ========================================================================== */

function CreditManagePage({ toast }) {
  const [tab,setTab]=useState("adjust"); // adjust | history
  const Tb=({k,label})=><button onClick={()=>setTab(k)} className={"rounded-lg px-4 py-2 text-sm font-medium transition-colors "+(tab===k?"bg-accent text-accent-fg":"text-fg-2 hover:bg-sunken")}>{label}</button>;

  return (<div className="space-y-5">
    <div className="flex gap-1 rounded-lg bg-sunken p-1"><Tb k="adjust" label="เติม/ตัดเครดิต"/><Tb k="history" label="ประวัติ"/></div>
    {tab==="adjust"&&<CreditAdjustForm toast={toast}/>}
    {tab==="history"&&<CreditHistory toast={toast}/>}
  </div>);
}

function CreditAdjustForm({ toast }) {
  const [username,setUsername]=useState("");
  const [selectedUser,setSelectedUser]=useState(null);
  const [amount,setAmount]=useState("");
  const [adjustType,setAdjustType]=useState("direct");
  const [reason,setReason]=useState("");
  const [saving,setSaving]=useState(false);
  const [result,setResult]=useState(null);
  const [userSearch,setUserSearch]=useState(null);
  const [searching,setSearching]=useState(false);
  const [accounts,setAccounts]=useState([]);
  const [accountsError,setAccountsError]=useState("");
  const [accountId,setAccountId]=useState("");
  const [slip,setSlip]=useState(null);
  const [slipRead,setSlipRead]=useState(null);
  const slipInputRef=useRef(null);
  const [readingSlip,setReadingSlip]=useState(false);
  const [slipTimeMode,setSlipTimeMode]=useState("manual");
  const [slipTime,setSlipTime]=useState("");
  const [turnoverMode,setTurnoverMode]=useState("multiplier");
  const [turnoverType,setTurnoverType]=useState("deposit");
  const [turnoverValue,setTurnoverValue]=useState("1");
  const [withdrawType,setWithdrawType]=useState("max_by_turnover");
  const [maxWithdraw,setMaxWithdraw]=useState("");

  useEffect(()=>{
    let active=true;
    api("/deposit-accounts").then(rows=>{
      if(active) setAccounts((Array.isArray(rows)?rows:[]).filter(a=>a.is_active!==false&&!a.deleted_at));
    }).catch(e=>{
      if(active) setAccountsError(e.message||"โหลดบัญชีรับเงินไม่สำเร็จ");
    });
    return ()=>{active=false;};
  },[]);

  const searchUser=async()=>{
    if(!username.trim()) return;
    setSearching(true);
    try{
      const d=await api(`/users?q=${encodeURIComponent(username.trim())}&limit=5`);
      setUserSearch(Array.isArray(d?.rows)?d.rows:Array.isArray(d)?d:[]);
    }catch(e){ toast(e.message||"ค้นหาไม่สำเร็จ"); }
    finally{ setSearching(false); }
  };

  const accountLabel=(a)=>a.type==="wallet"
    ? [a.wallet_phone,a.account_name].filter(Boolean).join(" · ")
    : [a.bank_name||bankName(a.bank_code),a.account_no,a.account_name].filter(Boolean).join(" · ");

  const onSlipPick=(event)=>{
    const file=event.target.files?.[0];
    setSlip(null);
    setSlipRead(null);
    setAccountId("");
    setAmount("");
    setSlipTime("");
    if(!file) return;
    const reader=new FileReader();
    reader.onload=()=>setSlip({data:String(reader.result||""),name:file.name||"slip.jpg",mime:file.type||"image/jpeg"});
    reader.onerror=()=>toast("อ่านไฟล์สลิปไม่สำเร็จ กรุณาเลือกรูปใหม่");
    reader.readAsDataURL(file);
  };

  const readSlip=async()=>{
    if(!slip?.data){ toast("กรุณาแนบรูปสลิปก่อน"); return; }
    setReadingSlip(true);
    try{
      const data=await api("/slip/read",{method:"POST",body:{slipImageData:slip.data,slipFilename:slip.name,slipMimetype:slip.mime}});
      let duplicateConfirmed=false;
      if(data.duplicate?.status==="success"){
        duplicateConfirmed=window.confirm("สลิปนี้เคยใช้เติมเครดิตแล้ว ต้องการดำเนินการต่อหรือไม่?");
      }
      setSlipRead({...data,duplicateConfirmed});
      if(Number(data.amountSatang)>0) setAmount((Number(data.amountSatang)/100).toFixed(2));
      if(data.dateTime) setSlipTime(String(data.dateTime).slice(0,16));
      if(data.account?.id) setAccountId(String(data.account.id));
      toast(duplicateConfirmed?"อ่านสลิปแล้ว (ยืนยันใช้ซ้ำ)":data.duplicate?.status==="success"?"อ่านสลิปแล้ว":"อ่านสลิปสำเร็จ");
    }catch(e){
      toast(e.message==="slip_already_used"?"สลิปนี้เคยใช้แล้ว":e.message||"อ่านสลิปไม่สำเร็จ");
    }finally{setReadingSlip(false);}
  };

  const submit=async()=>{
    const amountBaht=Number(amount);
    if(!selectedUser){ toast("กรุณาค้นหาและเลือกสมาชิกก่อน"); return; }
    if(!Number.isFinite(amountBaht)||amountBaht<=0){ toast("กรุณากรอกจำนวนที่ถูกต้อง"); return; }
    if(!reason.trim()){ toast("กรุณากรอกหมายเหตุ"); return; }
    if(adjustType==="direct"&&!accountId){ toast("กรุณาเลือกบัญชีรับเงิน"); return; }
    if(adjustType==="direct"&&!slipTime){ toast("กรุณากรอกวันและเวลาตามสลิป หรืออ่านจากสลิป"); return; }
    if(slipRead?.duplicate?.status==="success"&&!slipRead.duplicateConfirmed){ toast("สลิปนี้เคยใช้แล้ว หากต้องการทำรายการซ้ำให้กดยืนยันจากการตรวจสอบสลิป"); return; }
    if(adjustType==="bonus"){
      const value=Number(turnoverValue);
      if(!Number.isFinite(value)||value<=0){ toast(turnoverMode==="fixed"?"กรุณากรอกยอดเทิร์นให้ถูกต้อง":"กรุณากรอกจำนวนเทิร์นให้ถูกต้อง"); return; }
    }
    setSaving(true); setResult(null);
    try{
      const body={amount:Math.round(amountBaht*100),adjustType,reason:reason.trim()};
      if(adjustType==="direct"){
        body.accountId=accountId;
        body.slipTimeMode=slipTimeMode;
        body.slipTimeManual=slipTime;
        if(slip?.data){
          body.slipImageData=slip.data;
          body.slipFilename=slip.name;
          body.slipMimetype=slip.mime;
          if(slipRead?.duplicateConfirmed) body.allowDuplicateSlip=true;
        }
      }
      if(adjustType==="bonus"){
        body.turnoverMode=turnoverMode;
        body.turnoverType=turnoverType;
        body.withdrawType=withdrawType;
        body.maxWithdraw=withdrawType==="fixed_max_withdraw"?Math.round((Number(maxWithdraw)||0)*100):0;
        if(turnoverMode==="fixed") body.turnoverAmount=Math.round(Number(turnoverValue)*100);
        else body.turnoverMultiplier=Number(turnoverValue);
      }
      const data=await api(`/users/${selectedUser.id||selectedUser._id}/adjust`,{method:"POST",body});
      setResult({...data,amountSatang:body.amount,username:selectedUser.username||selectedUser.phone});
      toast("ดำเนินการสำเร็จ");
      setAmount(""); setReason(""); setSlip(null); setSlipRead(null); setSlipTime(""); setAccountId("");
      if(slipInputRef.current) slipInputRef.current.value="";
    }catch(e){
      const messages={
        reason_required:"กรุณากรอกหมายเหตุ",
        invalid_amount:"กรุณากรอกจำนวนที่ถูกต้อง",
        deposit_account_not_found:"ไม่พบบัญชีรับเงินหรือบัญชีถูกปิดใช้งาน",
        slip_already_used:"สลิปนี้เคยใช้แล้ว กรุณาตรวจสอบและยืนยันก่อนทำรายการ",
        bank_mismatch:"บัญชีผู้รับบนสลิปไม่ตรงกับบัญชีที่เลือก",
        account_mismatch:"บัญชีผู้รับบนสลิปไม่ตรงกับบัญชีที่เลือก",
      };
      toast(messages[e.message]||e.message||"ดำเนินการไม่สำเร็จ");
    }
    finally{ setSaving(false); }
  };

  const allTypes=[["direct","Manual (เงินสด)"],["bonus","เติมโบนัส"],["deduct","ตัดเครดิต"]];
  const canManageTurnover=can("tool_manage_credit")||can("tool_clear_turnover");
  if(canManageTurnover) allTypes.splice(1,0,["turnover_sim","เติมเงินจำลองทำเทิร์น"],["turnover_reduce","ลดเทิร์นโดยตรง"]);
  const Lb=({children})=><label className="mb-1 block text-xs font-semibold text-fg-2">{children}</label>;
  const input="w-full rounded-lg border border-line bg-surface px-3 py-2 text-sm text-fg placeholder:text-faint focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20";

  return (<div className="space-y-4">
    <div className="rounded-xl border border-line bg-surface p-5 shadow-sm space-y-4">
      <h3 className="text-sm font-semibold text-fg">เติม/ตัดเครดิต</h3>
      <div><Lb>Username / เบอร์</Lb>
        <div className="flex gap-2"><input type="text" value={username} onChange={e=>{setUsername(e.target.value);setSelectedUser(null);setUserSearch(null);}} onKeyDown={e=>e.key==="Enter"&&searchUser()} placeholder="ค้นหา username หรือเบอร์" className={"flex-1 "+input}/>
        <button type="button" onClick={searchUser} disabled={searching} className="rounded-lg border border-line bg-surface px-4 py-2 text-sm font-medium text-fg-2 hover:bg-sunken disabled:opacity-50">{searching?"กำลังค้นหา…":"ค้นหา"}</button></div>
      </div>
      {userSearch&&userSearch.length>0&&(<div className="rounded-lg border border-line bg-sunken p-2 space-y-1">{userSearch.map((u,i)=>(
        <button type="button" key={i} onClick={()=>{setSelectedUser(u);setUsername(u.username||u.phone||"");setUserSearch(null);}} className="w-full rounded-lg px-3 py-2 text-left text-sm hover:bg-surface">
          <span className="font-semibold">{u.username||u.phone}</span> {u.full_name?`(${u.full_name})`:""} — <span className="mono tnum text-muted">{baht(Number(u.balance||0)+Number(u.bonus_balance||0))}</span>
        </button>))}</div>)}
      {userSearch&&userSearch.length===0&&<div className="text-xs text-muted">ไม่พบ user</div>}
      {selectedUser&&<div className="flex flex-wrap items-center gap-2 rounded-lg border border-accent/30 bg-accent-soft px-3 py-2 text-sm">
        <span className="font-semibold text-accent">{selectedUser.username||selectedUser.phone}</span>
        <span className="text-fg-2">{selectedUser.full_name||""}</span>
        <span className="ml-auto text-xs text-muted">เครดิตปัจจุบัน {baht(Number(selectedUser.balance||0)+Number(selectedUser.bonus_balance||0))}</span>
      </div>}

      <div><Lb>ประเภท</Lb>
        <select value={adjustType} onChange={e=>setAdjustType(e.target.value)} className={input}>
          {allTypes.map(([v,l])=><option key={v} value={v}>{l}</option>)}
        </select></div>
      <div className="grid gap-3 sm:grid-cols-2">
        <div><Lb>{adjustType==="bonus"?"จำนวนโบนัส (บาท)":"จำนวน (บาท)"} *</Lb><input type="number" min="0.01" step="0.01" value={amount} onChange={e=>setAmount(e.target.value)} placeholder="0.00" className={input+" mono"}/></div>
        <div><Lb>หมายเหตุ *</Lb><input type="text" required value={reason} onChange={e=>setReason(e.target.value)} placeholder="ระบุเหตุผลการปรับเครดิต" className={input}/></div>
      </div>
      {adjustType==="direct"&&<div className="space-y-3 rounded-lg border border-line bg-sunken/50 p-4">
        <h4 className="text-sm font-semibold">ข้อมูลการฝาก</h4>
        <div><Lb>บัญชีรับเงิน *</Lb>
          <select required value={accountId} onChange={e=>setAccountId(e.target.value)} className={input}>
            <option value="">เลือกบัญชีรับเงิน</option>
            {accounts.map(a=><option key={a.id} value={a.id}>{accountLabel(a)}</option>)}
          </select>
          {accountsError&&<p role="alert" className="mt-1 text-xs text-danger">โหลดบัญชีไม่สำเร็จ: {accountsError}</p>}
        </div>
        <div>
          <Lb>แนบสลิป (ไม่บังคับ)</Lb>
          <div className="flex flex-wrap items-center gap-2">
            <input ref={slipInputRef} type="file" accept="image/*" onChange={onSlipPick} className="min-w-0 flex-1 text-xs text-fg-2"/>
            <button type="button" onClick={readSlip} disabled={!slip||readingSlip} className="rounded-lg border border-line bg-surface px-3 py-2 text-xs font-medium text-fg-2 hover:bg-sunken disabled:opacity-50">
              {readingSlip?"กำลังอ่านสลิป…":"ตรวจสอบสลิป"}
            </button>
          </div>
          {slip&&<div className="mt-2 flex items-center gap-2 rounded-lg border border-line bg-surface p-2">
            <img src={slip.data} alt="ตัวอย่างสลิป" className="h-12 w-12 rounded object-cover"/>
            <span className="min-w-0 flex-1 truncate text-xs text-muted">{slip.name}{slipRead?.duplicateConfirmed?" · ยืนยันใช้ซ้ำ":""}</span>
            <button type="button" onClick={()=>{setSlip(null);setSlipRead(null);if(slipInputRef.current) slipInputRef.current.value="";}} className="rounded px-2 py-1 text-xs text-muted hover:bg-sunken">นำออก</button>
          </div>}
        </div>
        <div className="grid gap-3 sm:grid-cols-2">
          <div><Lb>รูปแบบอ่านเวลาสลิป</Lb><select value={slipTimeMode} onChange={e=>setSlipTimeMode(e.target.value)} className={input}>
            {can("perm_slip_time_slip2go")&&<option value="slip2go">อ่านจากสลิปอัตโนมัติ</option>}
            <option value="manual">กรอกเอง</option>
          </select></div>
          <div><Lb>วันและเวลาตามสลิป *</Lb><input type="datetime-local" required value={slipTime} onChange={e=>setSlipTime(e.target.value)} className={input}/></div>
        </div>
        <p className="text-xs leading-5 text-muted">กรอกเวลาตามสลิปทุกครั้ง หากแนบสลิปสามารถกด “ตรวจสอบสลิป” เพื่อเติมยอด เวลา และบัญชีรับเงินให้อัตโนมัติ</p>
      </div>}
      {adjustType==="bonus"&&<div className="space-y-3 rounded-lg border border-line bg-sunken/50 p-4">
        <h4 className="text-sm font-semibold">เงื่อนไขโบนัส</h4>
        <div><Lb>รูปแบบเทิร์น</Lb><select value={turnoverMode} onChange={e=>setTurnoverMode(e.target.value)} className={input}>
          <option value="multiplier">จำนวนเท่า</option><option value="fixed">ระบุยอดเทิร์น</option>
        </select></div>
        {turnoverMode==="multiplier"&&<div><Lb>ประเภทเทิร์น</Lb><select value={turnoverType} onChange={e=>setTurnoverType(e.target.value)} className={input}>
          <option value="deposit">เทิร์นโอเวอร์</option><option value="credit">เทิร์นเครดิต</option><option value="revolving">เทิร์นหมุนเวียน</option>
        </select></div>}
        <div><Lb>{turnoverMode==="fixed"?"ยอดเทิร์น (บาท)":"จำนวนเท่า"}</Lb><input type="number" min="0.01" step="0.01" value={turnoverValue} onChange={e=>setTurnoverValue(e.target.value)} className={input}/></div>
        <div><Lb>เงื่อนไขการถอน</Lb><select value={withdrawType} onChange={e=>setWithdrawType(e.target.value)} className={input}>
          <option value="max_by_turnover">ถอนได้เมื่อครบเทิร์น</option><option value="fixed_max_withdraw">จำกัดยอดถอนสูงสุด</option>
        </select></div>
        {withdrawType==="fixed_max_withdraw"&&<div><Lb>ยอดถอนสูงสุด (บาท)</Lb><input type="number" min="0" step="0.01" value={maxWithdraw} onChange={e=>setMaxWithdraw(e.target.value)} className={input}/></div>}
      </div>}
      <div className="flex justify-end"><button type="button" onClick={submit} disabled={saving||readingSlip} className="rounded-lg bg-accent px-6 py-2.5 text-sm font-medium text-accent-fg hover:bg-accent-h disabled:opacity-50">{saving?"กำลังดำเนินการ…":"ยืนยันทำรายการ"}</button></div>
    </div>
    {result&&<div className="rounded-lg border border-success/30 bg-success-soft p-4 text-sm text-success"><strong>สำเร็จ</strong> — {result.username} · {baht(result.amountSatang)}</div>}
  </div>);
}

function CreditHistory({ toast }) {
  const [rows,setRows]=useState([]);
  const [daily,setDaily]=useState([]);
  const [loading,setLoading]=useState(true);
  const [err,setErr]=useState(null);
  const [subKind,setSubKind]=useState("");
  const [range,setRange]=useState("month");
  const [custom,setCustom]=useState({from:bkkDate(0).slice(0,8)+"01",to:bkkDate(0)});
  const [q,setQ]=useState("");
  const [page,setPage]=useState(1);
  const [size,setSize]=useState(50);

  const load=useCallback(async()=>{ setLoading(true); setErr(null);
    const {from,to}=rangeToDates(range,custom);
    const qs=new URLSearchParams({date_from:from,date_to:to,limit:"500"});
    if(subKind) qs.set("sub_kind",subKind);
    if(q.trim()) qs.set("q",q.trim());
    try{ const d=await api(`/reports/manual-adjustments?${qs}`); setRows(d.rows||[]); setDaily(d.daily||[]); }
    catch(e){ if(e.status===401||e.status===403){window.__nxAuthFail?.();} setErr(e.message||"โหลดไม่สำเร็จ"); }
    finally{ setLoading(false); } },[subKind,range,custom,q]);
  useEffect(()=>{ load(); },[load]);
  useEffect(()=>{ setPage(1); },[subKind,range,custom,q,rows.length]);

  if(err) return <HistErr msg={err} onRetry={load}/>;

  const kinds=[["","ทั้งหมด"],["manual_topup","เติมเครดิตมือ"],["manual_deduct","ตัดเครดิต"],["admin_bonus","โบนัสจากแอดมิน"],["manual_topup_forced","เติมเครดิตแบบบังคับ"],["turnover_sim","จำลองทำเทิร์น"],["turnover_reduce","ลดเทิร์น"]];
  const typeLabel={manual_topup:"เติมเครดิตมือ",manual_deduct:"ตัดเครดิต",admin_bonus:"โบนัสจากแอดมิน",manual_topup_forced:"เติมเครดิตแบบบังคับ",turnover_sim:"จำลองทำเทิร์น",turnover_reduce:"ลดเทิร์น",direct:"เติมเครดิตมือ",deduct:"ตัดเครดิต",bonus:"โบนัสจากแอดมิน"};
  const sums=daily.reduce((acc,r)=>{
    acc.count+=Number(r.count||0);
    if(["manual_topup","manual_topup_forced"].includes(r.sub_kind)) acc.manual+=Number(r.credit_total||0);
    else if(r.sub_kind==="manual_deduct") acc.deduct+=Number(r.debit_total||0);
    else if(r.sub_kind==="admin_bonus") acc.bonus+=Number(r.credit_total||0);
    return acc;
  },{manual:0,deduct:0,bonus:0,count:0});
  const paged=rows.slice((page-1)*size,page*size);
  const exportRows=rows.map(r=>[
    fmtDT(r.created_at||r.date),
    r.username||r.phone,
    typeLabel[r.sub_kind||r.adjustType]||r.sub_kind||r.adjustType||"",
    r.amount,
    r.meta?.reason||r.reason||"",
    r.admin_actor||r.admin_name||"",
  ]);

  return (<div className="space-y-4">
    <div className="flex flex-wrap items-center gap-2">
      <select value={subKind} onChange={e=>setSubKind(e.target.value)} className="rounded-lg border border-line bg-surface px-3 py-2 text-sm">
        {kinds.map(([v,l])=><option key={v} value={v}>{l}</option>)}
      </select>
      <select value={range} onChange={e=>setRange(e.target.value)} className="rounded-lg border border-line bg-surface px-3 py-2 text-sm">
        {RANGES.map(([k,label])=><option key={k} value={k}>{label}</option>)}
      </select>
      {range==="custom"&&<div className="flex items-center gap-1.5">
        <input type="date" value={custom.from} onChange={e=>setCustom(c=>({...c,from:e.target.value}))} className="rounded-lg border border-line bg-surface px-2 py-2 text-sm"/>
        <span className="text-xs text-muted">ถึง</span>
        <input type="date" value={custom.to} onChange={e=>setCustom(c=>({...c,to:e.target.value}))} className="rounded-lg border border-line bg-surface px-2 py-2 text-sm"/>
      </div>}
      <input type="text" value={q} onChange={e=>setQ(e.target.value)} placeholder="ค้นหา username / เบอร์" className="w-48 rounded-lg border border-line bg-surface px-3 py-2 text-sm"/>
      <button type="button" onClick={load} className="flex items-center gap-1.5 rounded-lg border border-line bg-surface px-3 py-2 text-sm font-medium text-fg-2 hover:bg-sunken"><Ic d={I.refresh} size={15} cls={loading?"animate-spin":""}/> รีเฟรช</button>
      <ExportBtn onClick={()=>csvDownload("credit-history-"+bkkDate(0)+".csv",[["วันที่","ยูสเซอร์เนม","ประเภท","จำนวน(สตางค์)","หมายเหตุ","ผู้ทำรายการ"],...exportRows])}/>
    </div>

    <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
      {[["เติมเครดิตมือ",sums.manual,"var(--info)"],["ตัดเครดิต",sums.deduct,"var(--danger)"],["โบนัส",sums.bonus,"var(--warn)"],["จำนวนรายการ",sums.count,"var(--accent)"]].map(([label,value,color])=>
        <div key={label} className="flex items-center justify-between gap-2 rounded-xl border border-line bg-surface px-4 py-3 shadow-sm">
          <span className="text-xs text-muted">{label}</span><strong className="text-sm tnum" style={{color}}>{label==="จำนวนรายการ"?Number(value).toLocaleString("th-TH")+" รายการ":baht(value)}</strong>
        </div>)}
    </div>

    {loading ? <div className="flex items-center gap-2 py-16 justify-center text-sm text-muted"><Ic d={I.refresh} size={16} cls="animate-spin"/> กำลังโหลด…</div> : (
    <div className="overflow-hidden rounded-xl border border-line bg-surface shadow-sm">
      <div className="overflow-x-auto"><table className="w-full min-w-[1120px] text-sm">
        <thead><tr className="border-b border-line bg-sunken/60 text-left text-xs font-semibold text-muted">
          <th className="px-3 py-3">#</th><th className="px-3 py-3">ประเภท</th><th className="px-3 py-3">Username / เบอร์</th>
          <th className="px-3 py-3 text-right">จำนวน</th><th className="px-3 py-3">เครดิตก่อน / หลัง</th><th className="px-3 py-3">วันที่</th>
          <th className="px-3 py-3">ผู้ทำรายการ</th><th className="px-3 py-3">สลิป</th><th className="px-3 py-3">หมายเหตุ / รายละเอียด</th>
        </tr></thead>
        <tbody>{rows.length===0?<tr><td colSpan={9} className="px-4 py-12 text-center text-muted">ไม่มีข้อมูล</td></tr>:paged.map((r,i)=>{
          const kind=r.sub_kind||r.adjustType||"";
          const meta=r.meta||{};
          const rawAmount=Number(r.amount||0);
          const displayAmount=kind==="turnover_reduce"?Number(meta.turnover_reduced||0):Math.abs(rawAmount);
          const sign=kind==="turnover_reduce"||rawAmount<0?"-":"+";
          const slipUrl=meta.slip_image_url||meta.slipImageUrl||"";
          const rawBank=meta.bankName||meta.bankCode;
          const bank=rawBank?[bankName(rawBank),meta.accountNo].filter(Boolean).join(" "):"";
          const holder=String(meta.accountName||meta.slip_read?.receiver?.account?.name||meta.slip_read?.receiver_name||"").trim();
          const slipTime=meta.slip_time?new Intl.DateTimeFormat("th-TH",{timeZone:"Asia/Bangkok",day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",hour12:false}).format(new Date(meta.slip_time)):"";
          const note=String(r.reason||meta.reason||meta.note||"").trim();
          const actor=r.admin_actor||r.admin_name||"ระบบ";
          return <tr key={r.id||i} className="border-b border-line last:border-0 hover:bg-sunken/40">
            <td className="px-3 py-3 text-xs text-muted">{(page-1)*size+i+1}</td>
            <td className="px-3 py-3"><Badge color={["manual_deduct","deduct"].includes(kind)?"red":["admin_bonus","bonus"].includes(kind)?"blue":"green"}>{typeLabel[kind]||kind||"-"}</Badge></td>
            <td className="px-3 py-3"><div className="font-medium">{r.username||r.phone||"-"}</div><div className="text-[11px] text-muted">{r.phone&&r.username?r.phone:""}</div></td>
            <td className="whitespace-nowrap px-3 py-3 text-right font-semibold mono tnum" style={{color:sign==="-"?"var(--danger)":"var(--info)"}}>{sign}{baht(displayAmount)}</td>
            <td className="whitespace-nowrap px-3 py-3 text-xs"><div className="text-muted">{r.credit_before!=null?baht(r.credit_before):"-"}</div><div className="font-semibold text-fg">{r.credit_after!=null?baht(r.credit_after):"-"}</div></td>
            <td className="whitespace-nowrap px-3 py-3 text-xs text-muted">{r.created_at?new Intl.DateTimeFormat("th-TH",{timeZone:"Asia/Bangkok",day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",hour12:false}).format(new Date(r.created_at)):fmtDT(r.date)}</td>
            <td className="px-3 py-3 text-xs">{actor}</td>
            <td className="px-3 py-3 text-center">{slipUrl?<a href={slipUrl} target="_blank" rel="noopener noreferrer" className="inline-flex rounded-lg border border-line px-2.5 py-1.5 text-xs font-medium text-accent hover:bg-accent-soft">ดูสลิป</a>:"-"}</td>
            <td className="max-w-[300px] px-3 py-3 text-xs text-fg-2"><div className="space-y-0.5">
              {bank&&<div>{bank}</div>}{holder&&<div>{holder}</div>}
              {slipTime?<div className="text-muted">{slipTime}</div>:kind==="manual_topup"?<div className="text-muted">ไม่มีเวลาสลิป</div>:null}
              <div className="whitespace-pre-wrap break-words">{note||"-"}</div>
            </div></td>
          </tr>;
        })}</tbody>
      </table></div>
      {!loading&&<Pager page={page} setPage={setPage} total={rows.length} size={size} setSize={setSize}/>}
    </div>)}
  </div>);
}
