// ============ Inbox · รับบิล/งานจากแอปพนักงาน (OPS) ============
// 5A: แสดงรายการ integrationInbox (eventType=purchase_bill) ที่พนักงานส่งเข้ามา
//     ดูรูป · ตีกลับ · กรองสถานะ  (AI อ่านบิล=5B, ยืนยันเข้าสต็อก=5C ทำต่อภายหลัง)

function inboxStatusMeta(status){
  switch(status){
    case 'new':       return {label:'รอตรวจ',   tone:'orange'};
    case 'parsing':   return {label:'AI กำลังอ่าน', tone:'blue'};
    case 'review':    return {label:'รอยืนยัน', tone:'blue'};
    case 'confirmed': return {label:'ยืนยันแล้ว', tone:'green'};
    case 'rejected':  return {label:'ตีกลับ',   tone:'red'};
    default:          return {label:status||'-', tone:'gray'};
  }
}

function inboxFmtTs(iso){
  if(!iso) return '–';
  const d=new Date(iso);
  if(isNaN(d)) return String(iso);
  return d.toLocaleString('th-TH',{dateStyle:'medium',timeStyle:'short'});
}

// ดึงตัวเลขออกจากข้อความ (กันคอมมา/สัญลักษณ์เงิน)
function billNum(v,d=0){
  if(typeof v==='number') return isNaN(v)?d:v;
  const n=parseFloat(String(v??'').replace(/[^0-9.\-]/g,''));
  return isNaN(n)?d:n;
}

// แปลงผลจาก AI Vision → ร่างบิลที่จับคู่วัตถุดิบแล้ว
function buildBillDraft(json, db){
  const src=(json&&(json.bill||json.data||json))||{};
  const rows=src.items||src.lines||src.ingredients||[];
  const lines=rows.map((row,i)=>{
    const label=row.name||row.item||row.ingredient||('รายการ #'+(i+1));
    const code=String(row.code??row.articleNumber??row.article??row.barcode??row.sku??'').trim();
    // จับคู่ด้วยรหัสก่อน (แม่นกว่า) ถ้าไม่เจอค่อยจับด้วยชื่อ
    let item=code?(db.ingredients||[]).find(ing=>(ing.codes||[]).includes(code)):null;
    if(!item) item=window.aiMatchNamed?window.aiMatchNamed(db.ingredients||[],label):null;
    return {
      label, code,
      ingId:item?item.id:'',
      qty:billNum(row.qty??row.quantity??row.amount,1),
      unit:(item&&item.unit)||row.unit||'',
      unitPrice:billNum(row.unitPrice??row.price??row.unit_price??row.unitprice,0),
    };
  });
  return {
    source:'vision',
    vendor:src.vendor||'',
    billDate:src.billDate||src.date||'',
    total:billNum(src.total,0),
    discount:billNum(src.discount??src.discountTotal??src.totalDiscount,0),
    lines,
    notes:src.notes||'',
  };
}

// รวมยอดร่างบิลจากบรรทัด (qty×unitPrice)
function billLinesTotal(lines){
  return (lines||[]).reduce((s,l)=>s+billNum(l.qty,0)*billNum(l.unitPrice,0),0);
}

function InboxPage(){
  const { db, setDb, flash, settings, addMediaAsset, logActivity } = useData();
  const inbox = (db.integrationInbox||[])
    .filter(r=>r.eventType==='purchase_bill')
    .slice().sort((a,b)=>String(b.createdAt||'').localeCompare(String(a.createdAt||'')));

  const [filter,setFilter]=React.useState('all');
  const [viewImg,setViewImg]=React.useState(null);   // {url,name}
  const [rejectFor,setRejectFor]=React.useState(null); // record
  const [rejectReason,setRejectReason]=React.useState('');
  const [reviewFor,setReviewFor]=React.useState(null); // record ที่เปิดร่างบิล
  const [busyId,setBusyId]=React.useState(null);       // id ที่ AI กำลังอ่าน
  const [addOpen,setAddOpen]=React.useState(false);    // modal เพิ่มบิลเอง

  const aiEndpoint=(typeof localStorage!=='undefined' && localStorage.getItem('jebar_ai_chat_endpoint'))||'';

  const counts = {
    new:       inbox.filter(r=>r.status==='new').length,
    review:    inbox.filter(r=>r.status==='review'||r.status==='parsing').length,
    confirmed: inbox.filter(r=>r.status==='confirmed').length,
    rejected:  inbox.filter(r=>r.status==='rejected').length,
  };
  const pendingValue = inbox.filter(r=>r.status==='new'||r.status==='review')
    .reduce((s,r)=>s+(+(r.hint&&r.hint.totalAmount)||0),0);

  const rows = inbox.filter(r=>filter==='all' || r.status===filter
    || (filter==='review' && r.status==='parsing'));

  const updateRecord=(id,patch)=>{
    setDb(prev=>({
      ...prev,
      integrationInbox:(prev.integrationInbox||[]).map(r=>r.id===id?{...r,...patch}:r)
    }));
  };

  const doReject=()=>{
    if(!rejectFor) return;
    updateRecord(rejectFor.id,{
      status:'rejected',
      reviewedAt:new Date().toISOString(),
      parsed:{...(rejectFor.parsed||{}),rejectReason:rejectReason.trim()||'ไม่ระบุเหตุผล'}
    });
    flash('ตีกลับบิลแล้ว');
    setRejectFor(null); setRejectReason('');
  };

  const firstImage=(r)=>(r.images&&r.images[0])||null;

  // เรียก AI อ่านบิล → จับคู่วัตถุดิบ → เปิดร่างให้ตรวจ
  const runAiParse=async(r)=>{
    const img=firstImage(r);
    if(!aiEndpoint){
      // ไม่มี endpoint → เปิดร่างเปล่าให้กรอกเอง
      const draft=(r.parsed&&r.parsed.lines)?r.parsed:{source:'manual',vendor:(r.hint&&r.hint.vendor)||'',billDate:(r.hint&&r.hint.billDate)||'',total:0,lines:[],notes:''};
      updateRecord(r.id,{status:'review',parsed:draft});
      setReviewFor({...r,status:'review',parsed:draft});
      flash('ยังไม่ได้ตั้งค่า AI endpoint (หน้า AI) — เปิดโหมดกรอกเองให้แทน','warn');
      return;
    }
    setBusyId(r.id);
    updateRecord(r.id,{status:'parsing'});
    try{
      const res=await fetch(aiEndpoint,{
        method:'POST',headers:{'Content-Type':'application/json'},
        body:JSON.stringify({
          mode:'parse_bill',
          imageUrl:(img&&img.url)||null,
          image:r.imageData||null,
          ingredients:(db.ingredients||[]).map(i=>({id:i.id,name:i.name,unit:i.unit})),
        })
      });
      if(!res.ok) throw new Error((await res.text())||('AI error '+res.status));
      const json=await res.json();
      if(json.error) throw new Error(json.error);
      const draft=buildBillDraft(json, db);
      updateRecord(r.id,{status:'review',parsed:draft});
      setReviewFor({...r,status:'review',parsed:draft});
      flash('AI อ่านบิลแล้ว ตรวจและแก้ก่อนยืนยัน');
    }catch(e){
      updateRecord(r.id,{status:'new'});
      flash('AI อ่านบิลไม่สำเร็จ: '+(e.message||e),'err');
    }finally{
      setBusyId(null);
    }
  };

  const saveDraft=(record,draft)=>{
    updateRecord(record.id,{status:'review',parsed:draft});
    flash('บันทึกร่างบิลแล้ว');
    setReviewFor(null);
  };

  // 5C: ยืนยันร่างบิล → สร้าง purchaseEvent + รับเข้าสต็อก + (ออปชัน) อัปเดตต้นทุน
  const confirmToStock=(record,draft)=>{
    const lines=(draft.lines||[]).filter(l=>l.ingId && billNum(l.qty,0)>0);
    if(!lines.length){ flash('ต้องมีอย่างน้อย 1 บรรทัดที่จับคู่วัตถุดิบและมีจำนวน','err'); return; }
    const now=new Date().toISOString();
    // บิลย้อนหลัง: ใช้วันที่บนบิลเป็นวันที่มีผลต่อสต็อก/ต้นทุน ถ้าไม่มี/ไม่ถูกต้องค่อย fallback เป็นวันนี้
    let effDate=now;
    if(draft.billDate){
      const d=new Date(draft.billDate+'T12:00:00');
      if(!isNaN(d)) effDate=d.toISOString();
    }
    // เฉลี่ยส่วนลดทั้งบิลลงทุกบรรทัดตามสัดส่วนมูลค่า (pro-rata)
    const discount=billNum(draft.discount,0);
    const grossConf=lines.reduce((s,l)=>s+billNum(l.qty,0)*billNum(l.unitPrice,0),0);
    const factor=(discount>0 && grossConf>0) ? Math.max(0,(grossConf-discount))/grossConf : 1;

    let work={...db};
    const peIds=[]; const updatedCost={};
    lines.forEach(l=>{
      const qty=billNum(l.qty,0);
      const unitPrice=billNum(l.unitPrice,0)*factor; // ราคาหลังเฉลี่ยส่วนลด
      // หา/สร้าง stockItem ของวัตถุดิบนี้
      let item=(work.stockItems||[]).find(s=>s.refType==='ingredient'&&s.refId===l.ingId);
      if(!item){ item=stockNewItem(work,'ingredient',l.ingId); work={...work,stockItems:[...(work.stockItems||[]),item]}; }
      // รับเข้าสต็อก (ลงวันที่ตามบิล)
      const upd=stockApplyMovement(work,item.id,qty,'receive',`บิล ${draft.vendor||record.id}`,'purchase',record.id,effDate);
      work={...work,...upd};
      // purchaseEvent (เมื่อมีราคา)
      if(unitPrice>0){
        const peId=nextCode(work.purchaseEvents||[],'PEV');
        peIds.push(peId);
        work={...work,purchaseEvents:[...(work.purchaseEvents||[]),{
          id:peId, stockItemId:item.id, qty, unitCost:unitPrice, totalCost:qty*unitPrice,
          supplier:draft.vendor||'', receivedAt:effDate, note:'จากบิล '+record.id+(discount>0?` (เฉลี่ยส่วนลด ${Math.round((1-factor)*100)}%)`:''),
        }]};
        updatedCost[l.ingId]=unitPrice;
      }
    });
    // เรียนรู้รหัสสินค้า: ผูกรหัสในบิลเข้ากับวัตถุดิบที่จับคู่ (ครั้งหน้าจับด้วยรหัสได้เลย)
    const learnCodes={}; // ingId -> [codes]
    lines.forEach(l=>{
      const code=String(l.code||'').trim();
      if(code){ (learnCodes[l.ingId]=learnCodes[l.ingId]||[]).push(code); }
    });

    // อัปเดตต้นทุน + เรียนรู้รหัส ในรอบเดียว
    if((draft.updateCost!==false && Object.keys(updatedCost).length) || Object.keys(learnCodes).length){
      work={...work, ingredients:(work.ingredients||[]).map(i=>{
        let ni=i;
        if(draft.updateCost!==false && updatedCost[i.id]!=null) ni={...ni,costPerUnit:updatedCost[i.id]};
        if(learnCodes[i.id]){
          const merged=Array.from(new Set([...(ni.codes||[]), ...learnCodes[i.id]]));
          ni={...ni,codes:merged};
        }
        return ni;
      })};
    }
    // ปิดงานบิลใน inbox
    work={...work, integrationInbox:(work.integrationInbox||[]).map(r=>r.id===record.id?{
      ...r, status:'confirmed', reviewedAt:now,
      parsed:{...draft,total:billLinesTotal(draft.lines)},
      resultRefs:{purchaseEventIds:peIds},
    }:r)};
    setDb(work);
    if(logActivity) logActivity('inbox.confirm',{entityType:'inbox',entityId:record.id,note:`ยืนยันบิล ${draft.vendor||record.id} · ${lines.length} รายการ`});
    flash(`ยืนยันเข้าสต็อกแล้ว ${lines.length} รายการ`);
    setReviewFor(null);
  };

  // เจ้าของเพิ่มบิลเอง: สร้าง record ใหม่ใน inbox แล้วเปิดร่างให้กรอก/แก้
  const createOwnerBill=(rec)=>{
    setDb(prev=>({...prev, integrationInbox:[...(prev.integrationInbox||[]), rec]}));
    setReviewFor(rec);
  };

  // สร้างวัตถุดิบใหม่จากบรรทัดในบิล (กรณีสินค้าไม่มีในระบบ) แล้วคืน object ให้ผูกกับบรรทัด
  const createIngredient=({name,unit,costPerUnit,category,code})=>{
    const id=nextCode(db.ingredients||[],'ING');
    const cat=category||'ของใช้สิ้นเปลือง';
    const ing={ id, name:(name||'').trim()||id, unit:unit||'หน่วย',
      costPerUnit:billNum(costPerUnit,0), category:cat,
      type:cat, status:'active', buyPrice:billNum(costPerUnit,0), buyQty:1, yield:1,
      codes:code?[String(code).trim()]:[] };
    setDb(prev=>({...prev, ingredients:[...(prev.ingredients||[]), ing]}));
    if(logActivity) logActivity('ingredient.created',{entityType:'ingredient',entityId:id,note:`สร้างจากบิล: ${ing.name}`});
    return ing;
  };

  return <div className="view-enter" style={{display:'grid',gap:18}}>
    {/* summary */}
    <div style={{display:'grid',gridTemplateColumns:'repeat(4,1fr)',gap:14}} className="r-2col">
      <Stat label="รอตรวจ" value={fmt(counts.new)} icon="receipt" tone="var(--orange)" sub="บิลใหม่จากพนักงาน"/>
      <Stat label="กำลังดำเนินการ" value={fmt(counts.review)} icon="doc" sub="AI อ่าน / รอยืนยัน"/>
      <Stat label="ยืนยันแล้ว" value={fmt(counts.confirmed)} icon="check" tone="var(--green)" sub="เข้าสต็อกเรียบร้อย"/>
      <Stat label="มูลค่าค้างตรวจ" value={fmtB(pendingValue,0)} icon="wallet" sub="ยอดรวมที่พนักงานกรอกมา"/>
    </div>

    <Card>
      <SectionTitle sub="บิลซื้อของที่พนักงานถ่ายส่งเข้ามา รอเจ้าของตรวจและยืนยันเข้าสต็อก"
        right={<Button size="sm" icon="plus" onClick={()=>setAddOpen(true)}>เพิ่มบิลเอง</Button>}>กล่องรับบิล (Inbox)</SectionTitle>

      <div style={{display:'flex',gap:10,alignItems:'center',marginBottom:16,flexWrap:'wrap'}}>
        <div style={{minWidth:220}}>
          <Select value={filter} onChange={e=>setFilter(e.target.value)} options={[
            {value:'all',label:`ทั้งหมด (${inbox.length})`},
            {value:'new',label:`รอตรวจ (${counts.new})`},
            {value:'review',label:`กำลังดำเนินการ (${counts.review})`},
            {value:'confirmed',label:`ยืนยันแล้ว (${counts.confirmed})`},
            {value:'rejected',label:`ตีกลับ (${counts.rejected})`},
          ]}/>
        </div>
      </div>

      {rows.length===0
        ? <Empty icon="receipt" title="ยังไม่มีบิลในกล่อง"
            sub="เมื่อพนักงานถ่ายบิลซื้อของจากแอปพนักงาน บิลจะเข้ามารอตรวจที่นี่อัตโนมัติ"/>
        : <div style={{display:'flex',flexDirection:'column',gap:12}}>
            {rows.map(r=>{
              const meta=inboxStatusMeta(r.status);
              const img=firstImage(r);
              const hint=r.hint||{};
              const isDone=r.status==='confirmed'||r.status==='rejected';
              return <div key={r.id} style={{display:'flex',gap:14,alignItems:'flex-start',
                background:'var(--surface-2)',borderRadius:14,padding:14,
                opacity:isDone?.72:1}}>
                {/* thumbnail */}
                <button onClick={()=>img&&setViewImg({url:img.url,name:hint.vendor||r.id})}
                  style={{width:64,height:64,borderRadius:11,flexShrink:0,overflow:'hidden',
                    background:'var(--chip)',display:'grid',placeItems:'center',
                    border:'1px solid var(--line-2)',cursor:img?'zoom-in':'default'}}>
                  {img
                    ? <img src={img.url} alt="bill" style={{width:'100%',height:'100%',objectFit:'cover'}}/>
                    : <Icon name="box" size={22} color="var(--ink-3)"/>}
                </button>

                {/* info */}
                <div style={{flex:1,minWidth:0}}>
                  <div style={{display:'flex',alignItems:'center',gap:8,flexWrap:'wrap',marginBottom:4}}>
                    <span style={{fontWeight:700,fontSize:14.5}}>{hint.vendor||'ไม่ระบุร้าน'}</span>
                    <Badge tone={meta.tone}>{meta.label}</Badge>
                    {hint.totalAmount>0 && <span className="tnum" style={{fontSize:13.5,fontWeight:600,color:'var(--ink-2)'}}>{fmtB(hint.totalAmount)}</span>}
                  </div>
                  <div style={{fontSize:12.5,color:'var(--ink-3)',lineHeight:1.7}}>
                    <div>ส่งโดย {(r.submittedBy&&r.submittedBy.staffName)||'ไม่ทราบ'} · {inboxFmtTs(r.createdAt)}</div>
                    {hint.billDate && <div>วันที่บนบิล {hint.billDate}</div>}
                    {hint.note && <div>“{hint.note}”</div>}
                    {r.status==='rejected' && r.parsed&&r.parsed.rejectReason &&
                      <div style={{color:'var(--red)'}}>เหตุผลตีกลับ: {r.parsed.rejectReason}</div>}
                  </div>
                </div>

                {/* actions */}
                <div style={{display:'flex',flexDirection:'column',gap:8,flexShrink:0}}>
                  {(r.status==='new'||r.status==='parsing') &&
                    <Button size="sm" icon="chart" onClick={()=>runAiParse(r)}
                      disabled={busyId===r.id}
                      style={busyId===r.id?{opacity:.6,cursor:'wait'}:undefined}>
                      {busyId===r.id?'AI กำลังอ่าน…':'ให้ AI อ่านบิล'}</Button>}
                  {r.status==='review' &&
                    <Button size="sm" icon="doc" onClick={()=>setReviewFor(r)}>ตรวจร่างบิล</Button>}
                  {r.status==='confirmed' && r.parsed &&
                    <Button size="sm" variant="ghost" icon="doc" onClick={()=>setReviewFor(r)}>ดูบิล</Button>}
                  {(r.status==='new'||r.status==='review') &&
                    <Button size="sm" variant="secondary" icon="close"
                      onClick={()=>{setRejectFor(r);setRejectReason('');}}>ตีกลับ</Button>}
                  {img && <Button size="sm" variant="ghost" onClick={()=>setViewImg({url:img.url,name:hint.vendor||r.id})}>ดูรูป</Button>}
                </div>
              </div>;
            })}
          </div>}

      <p style={{fontSize:12,color:'var(--ink-3)',marginTop:16,lineHeight:1.7}}>
        บิลเหล่านี้มาจาก <code>db.integrationInbox</code> (eventType=purchase_bill) ที่แอปพนักงานส่งเข้ามา ·
        ขั้นถัดไป: ให้ AI อ่านรายการในบิล แล้วยืนยันเพื่อสร้าง purchaseEvent + ตัดเข้าสต็อกอัตโนมัติ
      </p>
    </Card>

    {/* bill review / edit draft */}
    <BillReviewModal record={reviewFor} db={db} onClose={()=>setReviewFor(null)} onSave={saveDraft} onConfirm={confirmToStock} onCreateIngredient={createIngredient}/>

    {/* owner: add bill manually */}
    <AddBillModal open={addOpen} onClose={()=>setAddOpen(false)} db={db} settings={settings}
      addMediaAsset={addMediaAsset} aiEndpoint={aiEndpoint} flash={flash} onCreate={createOwnerBill}/>

    {/* image viewer */}
    <Modal open={!!viewImg} onClose={()=>setViewImg(null)} title={viewImg?viewImg.name:''} width={560}>
      {viewImg && <img src={viewImg.url} alt="bill" style={{width:'100%',borderRadius:12,display:'block'}}/>}
    </Modal>

    {/* reject reason */}
    <Modal open={!!rejectFor} onClose={()=>setRejectFor(null)} title="ตีกลับบิล" width={420}
      footer={<><Button variant="secondary" onClick={()=>setRejectFor(null)}>ยกเลิก</Button>
        <Button variant="danger" icon="close" onClick={doReject}>ยืนยันตีกลับ</Button></>}>
      <div style={{display:'flex',flexDirection:'column',gap:12}}>
        <p style={{fontSize:13.5,color:'var(--ink-2)'}}>
          ระบุเหตุผลที่ตีกลับ เพื่อให้พนักงานเห็นและส่งใหม่ได้ถูกต้อง
        </p>
        <Field label="เหตุผล">
          <textarea rows={3} value={rejectReason}
            onChange={e=>setRejectReason(e.target.value)}
            placeholder="เช่น รูปไม่ชัด อ่านยอดไม่ออก / ไม่ใช่บิลซื้อของ"
            style={{width:'100%',padding:'10px 12px',borderRadius:10,border:'1px solid var(--line)',
              background:'var(--surface)',color:'var(--ink)',font:'inherit',resize:'vertical',outline:'none'}}
            onFocus={e=>{e.target.style.borderColor='var(--accent)';e.target.style.boxShadow='0 0 0 3.5px var(--accent-soft)';}}
            onBlur={e=>{e.target.style.borderColor='var(--line)';e.target.style.boxShadow='none';}}/>
        </Field>
      </div>
    </Modal>
  </div>;
}
// ---- Modal ตรวจ/แก้ร่างบิล ก่อนยืนยันเข้าสต็อก (ยืนยันจริง = 5C) ----
function BillReviewModal({ record, db, onClose, onSave, onConfirm, onCreateIngredient }){
  const [draft,setDraft]=React.useState(null);
  const [newIng,setNewIng]=React.useState(null); // ฟอร์มถามหมวดตอนสร้างของใหม่
  React.useEffect(()=>{
    if(record){
      const base=record.parsed?JSON.parse(JSON.stringify(record.parsed)):{source:'manual',vendor:'',billDate:'',total:0,lines:[],notes:''};
      if(base.updateCost===undefined) base.updateCost=true;
      setDraft(base);
    } else setDraft(null);
  },[record]);
  if(!record || !draft) return null;
  const isConfirmed=record.status==='confirmed';

  const ingOptions=[{value:'',label:'— ยังไม่จับคู่ —'},
    {value:'__new__',label:'➕ เพิ่มของใหม่เข้าระบบ…'},
    ...(db.ingredients||[]).map(i=>({value:i.id,label:i.name}))];

  const setLine=(idx,patch)=>setDraft(d=>({...d,lines:d.lines.map((l,i)=>i===idx?{...l,...patch}:l)}));
  const onPickIng=(idx,ingId)=>{
    if(ingId==='__new__'){
      const line=draft.lines[idx];
      // โหมดถาม: เปิดฟอร์มให้ใส่ชื่อ + เลือกหมวดเองครั้งแรก (อาจเป็นวัตถุดิบ หรือของใช้สิ้นเปลือง)
      setNewIng({ idx, name:(line.label||'').trim(), unit:line.unit||'', costPerUnit:line.unitPrice||0, category:'ของใช้สิ้นเปลือง', code:line.code||'' });
      return;
    }
    const ing=(db.ingredients||[]).find(x=>x.id===ingId);
    setLine(idx,{ingId, unit:ing?ing.unit:'', label:(draft.lines[idx].label||(ing&&ing.name))||''});
  };
  const confirmNewIng=()=>{
    if(!newIng || !onCreateIngredient) return;
    if(!(newIng.name||'').trim()){ if(window.alert) window.alert('กรุณาใส่ชื่อ'); return; }
    const ing=onCreateIngredient({ name:newIng.name, unit:newIng.unit, costPerUnit:newIng.costPerUnit, category:newIng.category, code:newIng.code });
    setLine(newIng.idx,{ ingId:ing.id, unit:ing.unit, label:newIng.name });
    setNewIng(null);
  };
  const addLine=()=>setDraft(d=>({...d,lines:[...d.lines,{label:'',code:'',ingId:'',qty:1,unit:'',unitPrice:0}]}));
  const removeLine=(idx)=>setDraft(d=>({...d,lines:d.lines.filter((_,i)=>i!==idx)}));

  const linesTotal=billLinesTotal(draft.lines);
  const matched=draft.lines.filter(l=>l.ingId).length;
  const unmatched=draft.lines.length-matched;

  return <Modal open={!!record} onClose={onClose} title={isConfirmed?'บิลที่ยืนยันแล้ว':'ตรวจร่างบิล'} width={760}
    footer={isConfirmed
      ? <Button variant="secondary" onClick={onClose}>ปิด</Button>
      : <>
        <Button variant="ghost" onClick={addLine} icon="plus">เพิ่มบรรทัด</Button>
        <div style={{flex:1}}/>
        <Button variant="secondary" onClick={()=>onSave(record,{...draft,total:linesTotal})}>บันทึกร่าง</Button>
        <Button icon="check" onClick={()=>onConfirm&&onConfirm(record,{...draft,total:linesTotal})}>ยืนยันเข้าสต็อก</Button>
      </>}>
    <div style={{display:'flex',flexDirection:'column',gap:14}}>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Field label="ร้านที่ซื้อ">
          <Input value={draft.vendor||''} onChange={e=>setDraft({...draft,vendor:e.target.value})} placeholder="เช่น แม็คโคร"/>
        </Field>
        <Field label="วันที่บนบิล (มีผลต่อสต็อก/ต้นทุน)">
          <Input type="date" value={draft.billDate||''} onChange={e=>setDraft({...draft,billDate:e.target.value})}/>
        </Field>
      </div>

      {!draft.billDate && !isConfirmed &&
        <Badge tone="orange">ยังไม่ได้ใส่วันที่บนบิล — ถ้าไม่ใส่ ระบบจะลงเป็นวันนี้</Badge>}
      {draft.source==='vision' && <Badge tone="blue">AI อ่านมา {draft.lines.length} รายการ · จับคู่ได้ {matched} · ต้องเลือกเอง {unmatched}</Badge>}

      <div style={{display:'flex',flexDirection:'column',gap:8}}>
        <div style={{display:'grid',gridTemplateColumns:'2.2fr 1fr .8fr 1fr 32px',gap:8,fontSize:12,color:'var(--ink-3)',padding:'0 2px'}}>
          <span>วัตถุดิบ</span><span>รายการในบิล</span><span>จำนวน</span><span>ราคา/หน่วย</span><span/>
        </div>
        {draft.lines.length===0 && <div style={{fontSize:13,color:'var(--ink-3)',padding:'8px 2px'}}>ยังไม่มีรายการ กด “เพิ่มบรรทัด” เพื่อกรอกเอง</div>}
        {draft.lines.map((l,idx)=>(
          <div key={idx} style={{display:'grid',gridTemplateColumns:'2.2fr 1fr .8fr 1fr 32px',gap:8,alignItems:'start'}}>
            <Select value={l.ingId||''} onChange={e=>onPickIng(idx,e.target.value)} options={ingOptions} style={{marginTop:0}}/>
            <div style={{display:'flex',flexDirection:'column',gap:4}}>
              <Input value={l.label||''} onChange={e=>setLine(idx,{label:e.target.value})} placeholder="ชื่อจากบิล"/>
              <Input value={l.code||''} onChange={e=>setLine(idx,{code:e.target.value})} placeholder="รหัสสินค้า"
                style={{fontSize:12,padding:'5px 9px',color:'var(--ink-2)'}}/>
            </div>
            <Input type="number" value={l.qty} onChange={e=>setLine(idx,{qty:e.target.value})}/>
            <Input type="number" value={l.unitPrice} onChange={e=>setLine(idx,{unitPrice:e.target.value})}/>
            <IconBtn name="trash" danger title="ลบ" onClick={()=>removeLine(idx)} />
          </div>
        ))}
      </div>

      <div style={{borderTop:'1px solid var(--line-2)',paddingTop:12,display:'flex',flexDirection:'column',gap:8}}>
        <div style={{display:'flex',justifyContent:'space-between',alignItems:'center'}}>
          <span style={{fontSize:13,color:'var(--ink-2)'}}>ยอดรวมจากบรรทัด (ก่อนลด)</span>
          <span className="tnum" style={{fontSize:15,fontWeight:600}}>{fmtB(linesTotal)}</span>
        </div>
        {!isConfirmed &&
          <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',gap:12}}>
            <span style={{fontSize:13,color:'var(--ink-2)'}}>ส่วนลดทั้งบิล</span>
            <div style={{width:140}}>
              <Input type="number" value={draft.discount||0} onChange={e=>setDraft({...draft,discount:e.target.value})}/>
            </div>
          </div>}
        <div style={{display:'flex',justifyContent:'space-between',alignItems:'center'}}>
          <span style={{fontSize:13.5,fontWeight:600}}>ยอดจ่ายจริง (หลังลด)</span>
          <span className="tnum" style={{fontSize:17,fontWeight:800,color:'var(--green)'}}>{fmtB(Math.max(0,linesTotal-billNum(draft.discount,0)))}</span>
        </div>
        {billNum(draft.discount,0)>0 &&
          <span style={{fontSize:12,color:'var(--ink-3)'}}>ส่วนลดจะถูกเฉลี่ยลงทุกบรรทัดตามสัดส่วน — ราคาต่อหน่วยที่บันทึกจะลดลงตามจริง</span>}
      </div>
      {draft.total>0 && Math.abs(draft.total-linesTotal)>1 &&
        <Badge tone="orange">ยอดที่ AI/พนักงานระบุ {fmtB(draft.total)} ต่างจากผลรวมบรรทัด — ตรวจอีกครั้ง</Badge>}

      {!isConfirmed && <>
        <label style={{display:'flex',alignItems:'center',gap:10,fontSize:13.5,cursor:'pointer'}}>
          <input type="checkbox" checked={draft.updateCost!==false}
            onChange={e=>setDraft({...draft,updateCost:e.target.checked})}
            style={{width:17,height:17,accentColor:'var(--accent)'}}/>
          อัปเดตต้นทุนวัตถุดิบ (costPerUnit) เป็นราคา/หน่วยจากบิลนี้
        </label>
        <div style={{background:'var(--surface-2)',borderRadius:10,padding:'10px 14px',fontSize:12.5,color:'var(--ink-3)'}}>
          กด “ยืนยันเข้าสต็อก” จะสร้าง purchaseEvent + รับเข้าสต็อก (เฉพาะบรรทัดที่จับคู่วัตถุดิบและมีจำนวน)
          {draft.updateCost!==false?' และอัปเดตต้นทุนวัตถุดิบเป็นราคาล่าสุด':''} · ทำแล้วบิลจะถูกปิดเป็น “ยืนยันแล้ว”
        </div>
      </>}
      {isConfirmed && <Badge tone="green">บิลนี้ยืนยันเข้าสต็อกแล้ว · แก้ไม่ได้</Badge>}
    </div>

    {/* โหมดถาม: สร้างของใหม่ + เลือกหมวดเอง */}
    <Modal open={!!newIng} onClose={()=>setNewIng(null)} title="เพิ่มของใหม่เข้าระบบ" width={420}
      footer={<><Button variant="secondary" onClick={()=>setNewIng(null)}>ยกเลิก</Button>
        <Button icon="check" onClick={confirmNewIng}>เพิ่ม</Button></>}>
      {newIng && <div style={{display:'flex',flexDirection:'column',gap:12}}>
        <Field label="ชื่อ"><Input value={newIng.name} onChange={e=>setNewIng({...newIng,name:e.target.value})}/></Field>
        <Field label="หมวดหมู่" hint="เลือกให้ถูกครั้งแรก — วัตถุดิบจะถูกนำไปคิดต้นทุนเมนู ส่วนของใช้สิ้นเปลืองไม่คิด">
          <Select value={newIng.category} onChange={e=>setNewIng({...newIng,category:e.target.value})} options={[
            {value:'วัตถุดิบ',label:'วัตถุดิบ (ใช้ในสูตร/คิดต้นทุน)'},
            {value:'ของใช้สิ้นเปลือง',label:'ของใช้สิ้นเปลือง'},
            {value:'บรรจุภัณฑ์',label:'บรรจุภัณฑ์'},
            {value:'ของใช้ทำความสะอาด',label:'ของใช้ทำความสะอาด'},
          ]}/>
        </Field>
        <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
          <Field label="หน่วย"><Input value={newIng.unit} onChange={e=>setNewIng({...newIng,unit:e.target.value})} placeholder="เช่น ขวด, แพ็ค"/></Field>
          <Field label="ราคา/หน่วย"><Input type="number" value={newIng.costPerUnit} onChange={e=>setNewIng({...newIng,costPerUnit:e.target.value})}/></Field>
        </div>
      </div>}
    </Modal>
  </Modal>;
}

// ---- Modal เจ้าของเพิ่มบิลเอง (อัปรูป+AI หรือ กรอกเอง) ----
function AddBillModal({ open, onClose, db, settings, addMediaAsset, aiEndpoint, flash, onCreate }){
  const [vendor,setVendor]=React.useState('');
  const [billDate,setBillDate]=React.useState('');
  const [file,setFile]=React.useState(null);
  const [preview,setPreview]=React.useState('');
  const [busy,setBusy]=React.useState(false);
  const [aiModel,setAiModel]=React.useState('flash'); // โมเดลที่ใช้อ่านบิล: 'flash' เร็ว-ถูก (ค่าเริ่มต้น) / 'pro' แม่น
  const fileRef=React.useRef();

  React.useEffect(()=>{ if(open){ setVendor('');setBillDate('');setFile(null);setPreview('');setBusy(false);setAiModel('flash'); } },[open]);

  const newId=()=>{
    const d=new Date();
    const stamp=`${d.getFullYear()}${String(d.getMonth()+1).padStart(2,'0')}${String(d.getDate()).padStart(2,'0')}`;
    return `INBX-${stamp}-${String(Date.now()).slice(-4)}`;
  };
  const baseRecord=(extra)=>({
    id:newId(), source:'owner-manual', eventType:'purchase_bill',
    createdAt:new Date().toISOString(),
    submittedBy:{staffId:'owner',staffName:'เจ้าของร้าน'},
    hint:{vendor:vendor.trim(),billDate:billDate.trim()},
    images:[], ...extra,
  });

  const pickFile=async(f)=>{
    if(!f) return;
    setFile(f);
    try{ setPreview(await window.aiFileToDataUrl(f)); }catch(e){}
  };

  // อัปรูปขึ้น storage แบบ best-effort (ถ้า Supabase ตั้งค่าไว้)
  const tryUpload=async()=>{
    if(!file || !window.saveJebarImageAsset) return null;
    try{ return await window.saveJebarImageAsset(settings, addMediaAsset, file, {entityType:'inbox', entityId:'owner-bill', role:'bill-source'}); }
    catch(e){ return null; }
  };

  const manual=async()=>{
    const asset=await tryUpload();
    const rec=baseRecord({
      status:'review',
      images: asset?[{bucket:asset.bucket,path:asset.path,url:asset.url}]:[],
      parsed:{source:'manual',vendor:vendor.trim(),billDate:billDate.trim(),total:0,discount:0,lines:[],updateCost:true,notes:''},
    });
    onCreate(rec); onClose();
  };

  const withAi=async()=>{
    if(!file){ flash('กรุณาเลือกรูปบิลก่อน','err'); return; }
    if(!aiEndpoint){ flash('ยังไม่ได้ตั้งค่า AI endpoint (หน้า AI) — ใช้ “กรอกเอง” แทนได้','err'); return; }
    setBusy(true);
    try{
      const dataUrl=preview||await window.aiFileToDataUrl(file);
      const res=await fetch(aiEndpoint,{method:'POST',headers:{'Content-Type':'application/json'},
        body:JSON.stringify({mode:'parse_bill', image:dataUrl, model:aiModel,
          ingredients:(db.ingredients||[]).map(i=>({id:i.id,name:i.name,unit:i.unit}))})});
      if(!res.ok) throw new Error((await res.text())||('AI error '+res.status));
      const json=await res.json();
      if(json.error) throw new Error(json.error);
      const draft=buildBillDraft(json, db);
      draft.updateCost=true;
      if(vendor.trim()) draft.vendor=vendor.trim();
      if(billDate.trim()) draft.billDate=billDate.trim();
      const asset=await tryUpload();
      const rec=baseRecord({
        status:'review',
        images: asset?[{bucket:asset.bucket,path:asset.path,url:asset.url}]:[],
        parsed:draft,
      });
      onCreate(rec); onClose();
      flash('AI อ่านบิลแล้ว ตรวจและแก้ก่อนยืนยัน');
    }catch(e){ flash('AI อ่านบิลไม่สำเร็จ: '+(e.message||e),'err'); }
    finally{ setBusy(false); }
  };

  return <Modal open={open} onClose={onClose} title="เพิ่มบิลเอง" width={480}
    footer={<>
      <Button variant="secondary" onClick={onClose}>ยกเลิก</Button>
      <Button variant="soft" onClick={manual} disabled={busy}>กรอกเอง</Button>
      <Button icon="chart" onClick={withAi} disabled={busy} style={busy?{opacity:.6,cursor:'wait'}:undefined}>
        {busy?'AI กำลังอ่าน…':'อัปรูป + ให้ AI อ่าน'}</Button>
    </>}>
    <div style={{display:'flex',flexDirection:'column',gap:14}}>
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
        <Field label="ร้านที่ซื้อ"><Input value={vendor} onChange={e=>setVendor(e.target.value)} placeholder="เช่น แม็คโคร"/></Field>
        <Field label="วันที่บนบิล"><Input type="date" value={billDate} onChange={e=>setBillDate(e.target.value)}/></Field>
      </div>
      <Field label="รูปบิล (สำหรับให้ AI อ่าน — ไม่บังคับ)">
        <input ref={fileRef} type="file" accept="image/*" style={{display:'none'}}
          onChange={e=>{ pickFile(e.target.files[0]); e.target.value=''; }}/>
        <Button variant="secondary" icon="upload" onClick={()=>fileRef.current&&fileRef.current.click()}>เลือก / ถ่ายรูปบิล</Button>
      </Field>
      {preview && <img src={preview} alt="bill" style={{width:'100%',borderRadius:12,maxHeight:280,objectFit:'contain',background:'var(--chip)'}}/>}
      <Field label="AI ที่ใช้อ่านบิล" hint={aiModel==='pro'?'แม่นกว่า เหมาะกับบิลเขียนมือ/ภาษาไทย (~0.50 บาท/บิล)':'เร็วและถูกกว่า เหมาะกับบิลพิมพ์ชัด (~0.10 บาท/บิล)'}>
        <Select value={aiModel} onChange={e=>setAiModel(e.target.value)}
          options={[{value:'flash',label:'เร็ว-ประหยัด (Gemini 2.5 Flash)'},{value:'pro',label:'แม่นยำ (Gemini 2.5 Pro)'}]}/>
      </Field>
      <div style={{fontSize:12.5,color:'var(--ink-3)',lineHeight:1.7}}>
        • <b>อัปรูป + ให้ AI อ่าน</b>: AI แยกรายการให้ แล้วเปิดร่างให้ตรวจ<br/>
        • <b>กรอกเอง</b>: เปิดตารางเปล่าให้คีย์รายการเอง (ไม่ต้องมีรูปก็ได้)
      </div>
    </div>
  </Modal>;
}

Object.assign(window, { InboxPage, BillReviewModal, AddBillModal, buildBillDraft, billNum, billLinesTotal });
