/* global React, Ic, useStore, useToast, fireConfetti, Modal */
const { useState: useOS, useMemo: useOM, useRef: useOR } = React;

// ========= Goods Receipt =========
function PageReceive({ onNav }) {
  const store = useStore();
  const { state, receive } = store;
  const toast = useToast();
  const cwh = store.currentWarehouse();
  const [ref, setRef] = useOS('');
  const [lines, setLines] = useOS([]);
  const [pickerOpen, setPickerOpen] = useOS(false);
  const [step, setStep] = useOS(1);

  const todayMs = useOM(() => {
    const d = new Date(); d.setHours(0,0,0,0); return d.getTime();
  }, []);

  const addLine = (item) => {
    const sl = item.shelfLife || 0;
    setLines(prev => [...prev, {
      sku: item.sku, name: item.name_th, qty: '', locId: '', cost: item.unit_cost,
      shelfLife: sl,
      mfgDate: todayMs,
      lot: `L${Date.now().toString(36).toUpperCase().slice(-5)}-${prev.length+1}`,
    }]);
    setPickerOpen(false);
  };
  const updateLine = (i, patch) => setLines(prev => prev.map((l, idx) => idx === i ? { ...l, ...patch } : l));
  const removeLine = (i) => setLines(prev => prev.filter((_, idx) => idx !== i));

  const totalQty = lines.reduce((a, b) => a + Number(b.qty || 0), 0);
  const totalValue = lines.reduce((a, b) => a + Number(b.qty || 0) * Number(b.cost || 0), 0);

  const hasInvalid = lines.some(l => !l.locId || !l.qty || Number(l.qty) <= 0);

  const confirm = () => {
    if (lines.length === 0 || hasInvalid) return;
    receive(lines.map(l => ({
      sku: l.sku, locId: l.locId, qty: Number(l.qty),
      mfgDate: l.mfgDate, lot: l.lot,
    })), ref);
    fireConfetti();
    toast.success('บันทึกการรับเข้าสำเร็จ', `${lines.length} รายการ · ${totalQty} units`);
    setLines([]); setStep(1);
  };

  return (
    <div className="page-enter">
      <div className="page-header">
        <div>
          <h2 className="page-title">รับสินค้าเข้า <span className="muted mono" style={{fontSize:14, marginLeft:8}}>// GOODS RECEIPT</span></h2>
          <div className="page-subtitle">บันทึก inbound shipment เข้าสู่คลังโดยอัตโนมัติ</div>
        </div>
        <div className="row">
          <button className="btn btn-ghost" onClick={() => { setLines([]); setStep(1); }}><Ic name="refresh" size={14}/>เริ่มใหม่</button>
        </div>
      </div>

      <div className="stepper">
        <div className={`step ${step >= 1 ? 'active' : ''} ${step > 1 ? 'done' : ''}`}><span className="num">1</span>ข้อมูลเอกสาร</div>
        <Ic name="chevron-right" size={14} className="step-arrow"/>
        <div className={`step ${step >= 2 ? 'active' : ''} ${step > 2 ? 'done' : ''}`}><span className="num">2</span>เลือกสินค้า</div>
        <Ic name="chevron-right" size={14} className="step-arrow"/>
        <div className={`step ${step === 3 ? 'active' : ''}`}><span className="num">3</span>ยืนยันและเก็บเข้า</div>
      </div>

      <div className="grid-2" style={{ gridTemplateColumns: '1fr 340px', alignItems: 'flex-start' }}>
        <div className="card tech">
          <div style={{ marginBottom: 16 }}>
            <div className="field">
              <label>เลขที่เอกสาร / PO Reference</label>
              <div className="input-with-prefix">
                <span className="prefix">REF</span>
                <input className="input mono" value={ref} placeholder="PO-XXXX (ไม่บังคับ)" onChange={e => setRef(e.target.value)}/>
              </div>
            </div>
          </div>

          <div className="hr"/>

          <div className="row" style={{ marginBottom: 12, justifyContent: 'space-between' }}>
            <div className="card-title">รายการสินค้า ({lines.length})</div>
            <button className="btn btn-ghost btn-sm" onClick={() => setPickerOpen(true)}><Ic name="plus" size={12}/>เพิ่มรายการ</button>
          </div>

          {lines.length === 0 && (
            <div className="empty">
              <Ic name="box" size={32}/>
              <div>ยังไม่มีรายการสินค้า — เริ่มต้นด้วยการเพิ่มหรือสแกน barcode</div>
              <button className="btn btn-primary btn-sm" onClick={() => setPickerOpen(true)}><Ic name="plus" size={12}/>เลือกสินค้า</button>
            </div>
          )}

          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {lines.map((l, i) => {
              const expiryMs = l.shelfLife > 0 ? l.mfgDate + l.shelfLife * 86400000 : null;
              const exSt = expiryStatus(expiryMs);
              return (
                <div className="receipt-line" key={i}>
                  {/* Name header — always full width, never truncated */}
                  <div style={{ padding: '10px 12px 4px', borderBottom: '1px dashed var(--border)' }}>
                    <div style={{ fontSize: 13.5, fontWeight: 700, color: 'var(--text-primary)', lineHeight: 1.3 }}>{l.name}</div>
                    <div style={{ fontSize: 10.5, color: 'var(--text-muted)', fontFamily: 'var(--font-mono)', marginTop: 2 }}>{l.sku} · {l.shelfLife ? `อายุ ${fmtShelfLife(l.shelfLife)}` : 'ไม่ติดตามอายุ'}</div>
                  </div>
                  <div className="receipt-line-main">
                    <div className="thumb" style={{ flexShrink: 0 }}><Ic name="package" size={18}/></div>
                    <div style={{ flex: 1 }}>
                    </div>
                    <div className="row" style={{ gap: 4 }}>
                      <button className="btn btn-ghost btn-sm" onClick={() => updateLine(i, { qty: Math.max(1, Number(l.qty) - 1) })}><Ic name="minus" size={12}/></button>
                      <input className="input mono"
                        style={{ width: 60, textAlign: 'center', padding: '6px 8px', borderColor: (!l.qty || Number(l.qty) <= 0) ? 'var(--warning)' : undefined }}
                        placeholder="0"
                        value={l.qty} onChange={e => updateLine(i, { qty: e.target.value })}/>
                      <button className="btn btn-ghost btn-sm" onClick={() => updateLine(i, { qty: Number(l.qty) + 1 })}><Ic name="plus" size={12}/></button>
                    </div>
                    <select className="select"
                      style={{ fontSize: 11.5, padding: '7px 24px 7px 10px', minWidth: 160, borderColor: !l.locId ? 'var(--warning)' : undefined }}
                      value={l.locId} onChange={e => updateLine(i, { locId: e.target.value })}>
                      <option value="">⚠ เลือก Location...</option>
                      {state.locations.filter(loc => loc.wh === cwh.id).sort(cmpLoc).map(loc => (
                        <option key={loc.id} value={loc.id}>{loc.id} · {loc.zoneName}</option>
                      ))}
                    </select>
                    <div className="mono" style={{ fontSize: 12, color: 'var(--accent)', textAlign: 'right', minWidth: 70 }}>
                      ฿{(l.qty * l.cost).toLocaleString()}
                    </div>
                    <button className="icon-btn" onClick={() => removeLine(i)}><Ic name="trash" size={14}/></button>
                  </div>
                  <div className="receipt-line-meta">
                    <div className="field-inline">
                      <label>LOT</label>
                      <input className="input mono" style={{ padding: '6px 10px', fontSize: 12 }}
                        value={l.lot} onChange={e => updateLine(i, { lot: e.target.value })}/>
                    </div>
                    {l.shelfLife > 0 ? (
                      <>
                        <div className="field-inline">
                          <label>วันผลิต · MFG</label>
                          <input type="date" className="input mono" style={{ padding: '6px 10px', fontSize: 12 }}
                            value={fmtDateInput(l.mfgDate)}
                            max={fmtDateInput(Date.now())}
                            onChange={e => updateLine(i, { mfgDate: parseDateInput(e.target.value) })}/>
                        </div>
                        <div className="field-inline">
                          <label>วันหมดอายุ · EXP <span className="mono" style={{color:'var(--text-dim)'}}>(auto)</span></label>
                          <div className="mono" style={{ padding: '6px 10px', fontSize: 12, background: 'var(--bg-card-2)', borderRadius: 6, border: '1px solid var(--border)', color: exSt.cls === 'expired' || exSt.cls === 'crit' ? 'var(--danger)' : 'var(--text-primary)' }}>
                            {fmtDate(expiryMs)}
                          </div>
                        </div>
                        <div className="field-inline" style={{ alignItems: 'flex-end' }}>
                          <label>นับถอยหลัง</label>
                          <span className={`badge ${exSt.badge}`} style={{ padding: '4px 10px', fontSize: 11 }}>
                            <Ic name="alert" size={10}/>{exSt.label}
                          </span>
                        </div>
                      </>
                    ) : (
                      <div className="mono" style={{ fontSize: 11, color: 'var(--text-muted)', alignSelf: 'center', fontStyle: 'italic' }}>
                        สินค้านี้ไม่มีการติดตามอายุ — ตั้ง Shelf Life ใน Item Master เพื่อเปิดการนับถอยหลัง
                      </div>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        </div>

        <aside className="card tech" style={{ position: 'sticky', top: 0 }}>
          <div className="card-head">
            <div className="card-title">สรุปยอด</div>
            <span className="badge info">DRAFT</span>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            <SumRow label="จำนวนรายการ" value={`${lines.length} SKU`}/>
            <SumRow label="จำนวนรวม" value={`${totalQty.toLocaleString()} units`}/>
            <SumRow label="มูลค่ารวม" value={`฿${totalValue.toLocaleString()}`} highlight/>
            <div className="hr"/>
            <SumRow label="เลขที่เอกสาร" value={ref} small mono/>
            <SumRow label="ผู้ทำรายการ" value={store.currentUser?.name || '—'} small/>
            <SumRow label="เวลา" value={new Date().toLocaleString('th-TH')} small mono/>
          </div>
          <div className="hr"/>
          <button className="btn btn-primary" style={{ width: '100%', justifyContent: 'center' }}
            disabled={lines.length === 0 || hasInvalid} onClick={confirm}>
            <Ic name="check" size={14}/>ยืนยันรับเข้าทั้งหมด
          </button>
          {hasInvalid && lines.length > 0 && (
            <div className="mono" style={{ fontSize: 10.5, color: 'var(--warning)', marginTop: 6, textAlign: 'center' }}>
              ⚠ ยังมีรายการที่ยังไม่ได้ระบุ Location หรือจำนวน
            </div>
          )}
          <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 8, textAlign: 'center' }}>
            ระบบจะอัปเดต stock per location อัตโนมัติ
          </div>
        </aside>
      </div>

      <ItemPicker open={pickerOpen} onClose={() => setPickerOpen(false)} onPick={addLine}/>
    </div>
  );
}

// ========= Goods Issue =========
function PageIssue({ onNav }) {
  const store = useStore();
  const { state, issue } = store;
  const toast = useToast();
  const [customer, setCustomer] = useOS('');
  React.useEffect(() => {
    if (!customer && state.customers?.[0]) setCustomer(state.customers[0].name);
  }, [state.customers]);
  const [ref, setRef] = useOS('');
  const [lines, setLines] = useOS([]);
  const [pickerOpen, setPickerOpen] = useOS(false);

  // All available lots for a SKU (qty > 0), sorted by Location then FEFO
  const lotsOf = (sku) => state.stock
    .filter(s => s.sku === sku && s.qty > 0)
    .sort((a, b) => {
      const locCmp = a.locId.localeCompare(b.locId, 'en', { numeric: true });
      if (locCmp !== 0) return locCmp;
      return (a.expiry || Infinity) - (b.expiry || Infinity);
    });

  const addLine = (item) => {
    const lots = lotsOf(item.sku);
    if (lots.length === 0) { toast.error('ไม่มีสต็อกคงเหลือ', item.name_th); return; }
    // FEFO: pick the earliest-expiry lot that isn't already chosen in another line
    const used = new Set(lines.map(l => `${l.locId}||${l.lot}`));
    const fefoLot = lots.find(lt => !used.has(`${lt.locId}||${lt.lot}`));
    if (!fefoLot) { toast.error('ทุก lot ของสินค้านี้ถูกเลือกครบแล้ว', item.name_th); return; }
    setLines(prev => [...prev, {
      sku: item.sku,
      name: item.name_th,
      price: item.unit_price,
      locId: fefoLot.locId,
      lot: fefoLot.lot,
      qty: 1,
      available: fefoLot.qty,
      expiry: fefoLot.expiry,
      mfgDate: fefoLot.mfgDate,
    }]);
    setPickerOpen(false);
  };

  const updateLine = (i, patch) => setLines(prev => prev.map((l, idx) => {
    if (idx !== i) return l;
    const merged = { ...l, ...patch };
    // If lot changed, look up the specific stock row
    if (patch.lotKey !== undefined) {
      const [locId, lot] = patch.lotKey.split('||');
      const s = state.stock.find(x => x.sku === l.sku && x.locId === locId && x.lot === lot);
      return { ...merged, locId, lot, available: s?.qty || 0, expiry: s?.expiry, mfgDate: s?.mfgDate, lotKey: undefined };
    }
    return merged;
  }));

  const removeLine = (i) => setLines(prev => prev.filter((_, idx) => idx !== i));

  const totalQty = lines.reduce((a, b) => a + Number(b.qty || 0), 0);
  const totalValue = lines.reduce((a, b) => a + Number(b.qty || 0) * Number(b.price || 0), 0);
  const hasOver = lines.some(l => Number(l.qty) > l.available);

  const confirm = () => {
    if (lines.length === 0 || hasOver) return;
    issue(lines.map(l => ({ sku: l.sku, locId: l.locId, lot: l.lot, qty: Number(l.qty) })), ref, customer);
    fireConfetti();
    toast.success('จ่ายสินค้าออกสำเร็จ', `${lines.length} รายการ · ${totalQty} units`);
    setLines([]);
  };

  return (
    <div className="page-enter">
      <div className="page-header">
        <div>
          <h2 className="page-title">จ่ายสินค้าออก <span className="muted mono" style={{fontSize:14, marginLeft:8}}>// GOODS ISSUE</span></h2>
          <div className="page-subtitle">จ่ายสินค้าออกตาม FEFO · lot แยกต่างหากตาม location อัตโนมัติ</div>
        </div>
      </div>

      <div className="grid-2" style={{ gridTemplateColumns: '1fr 340px', alignItems: 'flex-start' }}>
        <div className="card tech">
          <div className="grid-2" style={{ marginBottom: 16 }}>
            <div className="field">
              <label>เลขที่เอกสาร / SO Reference</label>
              <div className="input-with-prefix">
                <span className="prefix">REF</span>
                <input className="input mono" value={ref} placeholder="SO-XXXX (ไม่บังคับ)" onChange={e => setRef(e.target.value)}/>
              </div>
            </div>
            <div className="field">
              <label>ลูกค้า / ปลายทาง</label>
              <CustomerPicker value={customer} onChange={setCustomer}/>
            </div>
          </div>

          <div className="hr"/>

          <div className="row" style={{ marginBottom: 12, justifyContent: 'space-between' }}>
            <div>
              <div className="card-title" style={{ display: 'inline' }}>รายการเบิก ({lines.length})</div>
              <span className="mono" style={{ fontSize: 10.5, color: 'var(--accent)', marginLeft: 10 }}>FEFO · หมดอายุก่อน = จ่ายก่อน</span>
            </div>
            <button className="btn btn-ghost btn-sm" onClick={() => setPickerOpen(true)}><Ic name="plus" size={12}/>เพิ่มรายการ</button>
          </div>

          {lines.length === 0 && (
            <div className="empty">
              <Ic name="truck" size={32}/>
              <div>ยังไม่มีรายการ — เลือกสินค้าจาก master หรือสแกน barcode</div>
              <button className="btn btn-primary btn-sm" onClick={() => setPickerOpen(true)}><Ic name="plus" size={12}/>เลือกสินค้า</button>
            </div>
          )}

          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {lines.map((l, i) => {
              const over = Number(l.qty) > l.available;
              const lots = lotsOf(l.sku);
              const exSt = expiryStatus(l.expiry);
              const lotKey = `${l.locId}||${l.lot}`;
              // lot keys chosen by OTHER lines (to block duplicate selection)
              const usedKeys = new Set(lines.filter((_, idx) => idx !== i).map(x => `${x.locId}||${x.lot}`));
              return (
                <div key={i} className="issue-line" style={{ borderColor: over ? 'rgba(255,86,115,0.5)' : undefined }}>
                  {/* Main row */}
                  <div className="issue-line-main">
                    <div className="thumb"><Ic name="package" size={18}/></div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-primary)' }}>{l.name}</div>
                      <div className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)', marginTop: 2 }}>{l.sku}</div>
                    </div>
                    {/* Qty controls */}
                    <div className="row" style={{ gap: 4 }}>
                      <button className="btn btn-ghost btn-sm" onClick={() => updateLine(i, { qty: Math.max(1, Number(l.qty) - 1) })}><Ic name="minus" size={12}/></button>
                      <input className="input mono"
                        style={{ width: 64, textAlign: 'center', padding: '6px 8px', borderColor: over ? 'var(--danger)' : undefined }}
                        value={l.qty} onChange={e => updateLine(i, { qty: e.target.value })}/>
                      <button className="btn btn-ghost btn-sm" onClick={() => updateLine(i, { qty: Math.min(l.available, Number(l.qty) + 1) })}><Ic name="plus" size={12}/></button>
                    </div>
                    <div className="mono" style={{ fontSize: 13, color: over ? 'var(--danger)' : 'var(--warning)', textAlign: 'right', minWidth: 72 }}>
                      ฿{(Number(l.qty||0) * l.price).toLocaleString()}
                    </div>
                    <button className="icon-btn" onClick={() => removeLine(i)}><Ic name="trash" size={14}/></button>
                  </div>

                  {/* Lot picker row */}
                  <div className="issue-line-lot">
                    <div className="field-inline" style={{ flex: '0 0 auto' }}>
                      <label>Lot · Location · EXP <span className="mono" style={{ color: 'var(--accent)' }}>({lots.length} lots)</span></label>
                      <select className="select" style={{ fontSize: 11.5, minWidth: 320 }}
                        value={lotKey}
                        onChange={e => updateLine(i, { lotKey: e.target.value })}>
                        {lots.map(s => {
                          const st = expiryStatus(s.expiry);
                          const daysLabel = s.expiry ? ` · ${st.label}` : '';
                          const expLabel = s.expiry ? ` · EXP ${fmtDate(s.expiry)}` : '';
                          const optKey = `${s.locId}||${s.lot}`;
                          // disable lots already chosen in another line (keep this line's own selection enabled)
                          const taken = usedKeys.has(optKey) && optKey !== lotKey;
                          return (
                            <option key={optKey} value={optKey} disabled={taken}>
                              {s.locId} · {s.lot}{expLabel}{daysLabel} · คงเหลือ {s.qty}{taken ? ' · เลือกแล้ว' : ''}
                            </option>
                          );
                        })}
                      </select>
                    </div>

                    <div className="field-inline">
                      <label>คงเหลือใน Lot</label>
                      <div className="mono" style={{ padding: '6px 10px', fontSize: 13, fontWeight: 700,
                        color: over ? 'var(--danger)' : 'var(--success)',
                        background: over ? 'var(--danger-soft)' : 'var(--success-soft)',
                        border: `1px solid ${over ? 'rgba(255,86,115,0.3)' : 'rgba(16,210,154,0.25)'}`,
                        borderRadius: 6 }}>
                        {l.available} units
                        {over && <span style={{ fontSize: 10, marginLeft: 6, color: 'var(--danger)' }}>⚠ เกิน</span>}
                      </div>
                    </div>

                    {l.expiry ? (
                      <div className="field-inline">
                        <label>อายุคงเหลือ</label>
                        <div className="row" style={{ gap: 6 }}>
                          <span className="mono" style={{ fontSize: 11.5, color: 'var(--text-primary)' }}>
                            EXP {fmtDate(l.expiry)}
                          </span>
                          <span className={`badge ${exSt.badge}`}>
                            {exSt.cls === 'expired' ? '⚠ EXPIRED' : `${exSt.label}`}
                          </span>
                        </div>
                      </div>
                    ) : (
                      <div className="field-inline">
                        <label>อายุ</label>
                        <span className="mono" style={{ fontSize: 11, color: 'var(--text-dim)' }}>ไม่ติดตาม</span>
                      </div>
                    )}

                    {l.mfgDate && (
                      <div className="field-inline">
                        <label>MFG</label>
                        <span className="mono" style={{ fontSize: 11, color: 'var(--text-muted)' }}>{fmtDate(l.mfgDate)}</span>
                      </div>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        </div>

        <aside className="card tech" style={{ position: 'sticky', top: 0 }}>
          <div className="card-head">
            <div className="card-title">สรุป Pick List</div>
            <span className="badge warn">PICKING</span>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            <SumRow label="จำนวนรายการ" value={`${lines.length} SKU`}/>
            <SumRow label="จำนวนรวม" value={`${totalQty.toLocaleString()} units`}/>
            <SumRow label="มูลค่ารวม" value={`฿${totalValue.toLocaleString()}`} highlight/>
            <div className="hr"/>
            <SumRow label="ใบสั่งขาย" value={ref} small mono/>
            <SumRow label="ผู้รับ" value={customer} small mono/>
            <SumRow label="ผู้ทำรายการ" value={store.currentUser?.name || '—'} small/>
          </div>

          {/* Expiry summary */}
          {lines.some(l => l.expiry) && (
            <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 6 }}>
              <div className="mono" style={{ fontSize: 10, color: 'var(--text-dim)', letterSpacing: '0.1em' }}>EXPIRY_SUMMARY</div>
              {lines.filter(l => l.expiry).map((l, i) => {
                const st = expiryStatus(l.expiry);
                return (
                  <div key={i} className="row" style={{ justifyContent: 'space-between', fontSize: 11.5 }}>
                    <span className="mono" style={{ color: 'var(--text-muted)' }}>{l.sku}</span>
                    <span className={`badge ${st.badge}`}>{st.label}</span>
                  </div>
                );
              })}
            </div>
          )}

          <div className="hr"/>
          {hasOver && (
            <div className="badge crit" style={{ marginBottom: 8, width: '100%', justifyContent: 'center' }}>
              <Ic name="alert" size={11}/>QTY เกินสต็อก lot นี้
            </div>
          )}
          <button className="btn btn-primary" style={{ width: '100%', justifyContent: 'center' }}
            disabled={lines.length === 0 || hasOver} onClick={confirm}>
            <Ic name="truck" size={14}/>ยืนยันจ่ายออก
          </button>
          <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 8, textAlign: 'center' }}>
            ตัด stock แบบ lot-precise · FEFO
          </div>
        </aside>
      </div>

      <ItemPicker open={pickerOpen} onClose={() => setPickerOpen(false)} onPick={addLine} requireStock/>
    </div>
  );
}

// ========= Stock Transfer =========
function PageTransfer() {
  const { state, transfer } = useStore();
  const store = useStore();
  const toast = useToast();
  const [sku, setSku] = useOS('');
  const [catFilter, setCatFilter] = useOS('all');
  const [lotKey, setLotKey] = useOS(''); // "locId||lot"
  const [toLoc, setToLoc] = useOS('');
  const [qty, setQty] = useOS(1);
  const txCats = ['all', ...[...new Set(state.items.map(i => i.category).filter(Boolean))].sort((a, b) => String(a).localeCompare(String(b), 'th'))];

  const item = state.items.find(i => i.sku === sku);

  // All lots for selected SKU (qty>0), sorted by Location then FEFO
  const lotsOf = (s) => (s || state).stock
    .filter(x => x.sku === sku && x.qty > 0)
    .sort((a, b) => {
      const locCmp = a.locId.localeCompare(b.locId, 'en', { numeric: true });
      if (locCmp !== 0) return locCmp;
      return (a.expiry || Infinity) - (b.expiry || Infinity);
    });

  const lots = sku ? lotsOf() : [];
  const parsedLot = lotKey ? { locId: lotKey.split('||')[0], lot: lotKey.split('||')[1] } : null;
  const selStock = parsedLot
    ? state.stock.find(x => x.sku === sku && x.locId === parsedLot.locId && x.lot === parsedLot.lot)
    : null;
  const fromAvail = selStock?.qty || 0;
  const fromLoc = parsedLot?.locId || '';
  const exSt = selStock ? expiryStatus(selStock.expiry) : null;

  const resetForm = () => { setSku(''); setLotKey(''); setToLoc(''); setQty(1); };

  const submit = () => {
    if (!sku || !lotKey || !toLoc || Number(qty) <= 0 || Number(qty) > fromAvail) return;
    if (fromLoc === toLoc) { toast.error('Location ปลายทางต้องไม่เหมือนต้นทาง'); return; }
    transfer(sku, Number(qty), fromLoc, toLoc, parsedLot.lot);
    fireConfetti();
    toast.success('โอนสำเร็จ', `${qty} units · LOT ${parsedLot.lot} · ${fromLoc} → ${toLoc}`);
    resetForm();
  };

  return (
    <div className="page-enter">
      <div className="page-header">
        <div>
          <h2 className="page-title">โอนระหว่าง Location <span className="muted mono" style={{fontSize:14, marginLeft:8}}>// STOCK TRANSFER</span></h2>
          <div className="page-subtitle">ย้ายสินค้าระหว่าง location · lot-precise · รองรับโอนข้าม Warehouse</div>
        </div>
      </div>

      <div className="grid-2" style={{ gridTemplateColumns: '1fr 1fr', gap: 18, alignItems: 'flex-start' }}>
        <div className="card tech">
          <div className="card-head"><div className="card-title">กรอกข้อมูลการโอน</div></div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {/* Category filter */}
            <div className="field">
              <label>หมวด · กรองสินค้า</label>
              <select className="select" value={catFilter} onChange={e => { setCatFilter(e.target.value); setSku(''); setLotKey(''); setToLoc(''); }}>
                {txCats.map(c => <option key={c} value={c}>{c === 'all' ? 'ทุกหมวด' : c}</option>)}
              </select>
            </div>
            {/* SKU */}
            <div className="field">
              <label>สินค้า · SKU</label>
              <select className="select" value={sku} onChange={e => { setSku(e.target.value); setLotKey(''); setToLoc(''); setQty(1); }}>
                <option value="">-- เลือกสินค้า --</option>
                {[...state.items].filter(i => catFilter === 'all' || i.category === catFilter).sort(cmpItem).map(i => {
                  const total = state.stock.filter(s => s.sku === i.sku && s.qty > 0).reduce((a,b)=>a+b.qty,0);
                  return <option key={i.sku} value={i.sku}>{i.sku} · {i.name_th} (คงเหลือ {total})</option>;
                })}
              </select>
            </div>

            {/* Lot picker — source */}
            {sku && (
              <div className="field">
                <label>ต้นทาง · Location + Lot <span className="mono" style={{color:'var(--accent)'}}>({lots.length} lots · FEFO)</span></label>
                <select className="select" value={lotKey} onChange={e => { setLotKey(e.target.value); setQty(1); }}>
                  <option value="">-- เลือก lot --</option>
                  {lots.map(s => {
                    const st = expiryStatus(s.expiry);
                    return (
                      <option key={`${s.locId}||${s.lot}`} value={`${s.locId}||${s.lot}`}>
                        {s.locId} · {s.lot}{s.expiry ? ` · EXP ${fmtDate(s.expiry)} (${st.label})` : ''} · คงเหลือ {s.qty}
                      </option>
                    );
                  })}
                </select>
              </div>
            )}

            {/* Selected lot info */}
            {selStock && (
              <div className="transfer-lot-info">
                <div className="row" style={{ justifyContent: 'space-between' }}>
                  <span className="mono" style={{ fontSize: 12, color: 'var(--accent)' }}>{selStock.lot}</span>
                  {selStock.expiry && <span className={`badge ${exSt.badge}`}>{exSt.cls === 'expired' ? '⚠ EXPIRED' : exSt.label}</span>}
                </div>
                <div className="grid-3" style={{ marginTop: 8, gap: 8 }}>
                  <div><div className="mono" style={{ fontSize: 9.5, color: 'var(--text-dim)' }}>MFG</div><div className="mono" style={{ fontSize: 12 }}>{fmtDate(selStock.mfgDate)}</div></div>
                  <div><div className="mono" style={{ fontSize: 9.5, color: 'var(--text-dim)' }}>EXP</div><div className="mono" style={{ fontSize: 12, color: exSt?.cls === 'expired' || exSt?.cls === 'crit' ? 'var(--danger)' : 'var(--text-primary)' }}>{fmtDate(selStock.expiry)}</div></div>
                  <div><div className="mono" style={{ fontSize: 9.5, color: 'var(--text-dim)' }}>AVAIL</div><div className="mono" style={{ fontSize: 12, color: 'var(--success)', fontWeight: 700 }}>{fromAvail} u</div></div>
                </div>
              </div>
            )}

            {/* Destination */}
            <div className="field">
              <label>ปลายทาง · Location</label>
              <select className="select" value={toLoc} onChange={e => setToLoc(e.target.value)} disabled={!lotKey}>
                <option value="">-- เลือก Location ปลายทาง --</option>
                {/* Group by warehouse — supports inter-WH transfer */}
                {state.warehouses.map(wh => {
                  const whLocs2 = state.locations.filter(l => l.wh === wh.id && l.id !== fromLoc).sort(cmpLoc);
                  if (!whLocs2.length) return null;
                  return (
                    <optgroup key={wh.id} label={`${wh.id} · ${wh.name}`}>
                      {whLocs2.map(l => {
                        const exist = state.stock.find(s => s.sku === sku && s.locId === l.id && s.lot === parsedLot?.lot);
                        return (
                          <option key={l.id} value={l.id}>
                            {l.id} · {l.zoneName}{exist ? ` (มีอยู่แล้ว ${exist.qty} u · same lot)` : ''}
                          </option>
                        );
                      })}
                    </optgroup>
                  );
                })}
              </select>
            </div>

            {/* Qty */}
            <div className="field">
              <label>จำนวนที่โอน (Available: {fromAvail})</label>
              <div className="row">
                <button className="btn btn-ghost" onClick={() => setQty(Math.max(1, Number(qty) - 1))}><Ic name="minus" size={12}/></button>
                <input className="input mono" style={{ textAlign: 'center', fontSize: 18 }} value={qty} onChange={e => setQty(e.target.value)}/>
                <button className="btn btn-ghost" onClick={() => setQty(Math.min(fromAvail, Number(qty) + 1))}><Ic name="plus" size={12}/></button>
                <button className="btn btn-ghost btn-sm" onClick={() => setQty(fromAvail)}>MAX</button>
              </div>
            </div>

            <button className="btn btn-primary"
              disabled={!sku || !lotKey || !toLoc || Number(qty) <= 0 || Number(qty) > fromAvail}
              onClick={submit}>
              <Ic name="transfer" size={14}/>ยืนยันการโอน
            </button>
          </div>
        </div>

        {/* Preview + recent */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          {/* Transfer preview */}
          <div className="card tech">
            <div className="card-head"><div className="card-title">ภาพรวมการโอน</div></div>
            <div style={{ padding: '16px 0' }}>
              <div className="row" style={{ justifyContent: 'space-between', alignItems: 'stretch' }}>
                <div style={{ flex: 1, textAlign: 'center', padding: '12px 14px', border: '1px dashed var(--border-strong)', borderRadius: 12 }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)', marginBottom: 6 }}>FROM</div>
                  <div className="mono" style={{ fontSize: 12, color: 'var(--warning)', wordBreak: 'break-all' }}>{fromLoc || '—'}</div>
                  {parsedLot && <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 4 }}>LOT: {parsedLot.lot}</div>}
                  {selStock?.expiry && <div style={{ marginTop: 6 }}><span className={`badge ${exSt?.badge}`}>{exSt?.label}</span></div>}
                </div>
                <div style={{ display: 'flex', alignItems: 'center', padding: '0 14px' }}>
                  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4 }}>
                    <Ic name="arrow-right" size={20} style={{ color: 'var(--accent)' }}/>
                    <span className="mono" style={{ fontSize: 16, color: 'var(--accent)', fontWeight: 700 }}>
                      {qty || 0} <span style={{ fontSize: 11 }}>u</span>
                    </span>
                  </div>
                </div>
                <div style={{ flex: 1, textAlign: 'center', padding: '12px 14px', border: '1px dashed var(--accent-dim)', borderRadius: 12, background: 'var(--accent-soft)' }}>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)', marginBottom: 6 }}>TO</div>
                  <div className="mono" style={{ fontSize: 12, color: 'var(--accent)', wordBreak: 'break-all' }}>{toLoc || '—'}</div>
                  {parsedLot && <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 4 }}>LOT: {parsedLot.lot}</div>}
                  <div className="mono" style={{ fontSize: 9.5, color: 'var(--success)', marginTop: 4 }}>lot จะแยกไว้ต่างหาก</div>
                </div>
              </div>

              {sku && item && (
                <div style={{ marginTop: 14, padding: 12, background: 'var(--bg-base)', borderRadius: 8, border: '1px solid var(--border)' }}>
                  <div className="row" style={{ justifyContent: 'space-between' }}>
                    <span className="mono" style={{ fontSize: 11, color: 'var(--accent)' }}>{sku}</span>
                    <span style={{ fontSize: 12 }}>{item.name_th}</span>
                    {item.shelfLife > 0 && <span className="mono" style={{ fontSize: 10, color: 'var(--text-muted)' }}>อายุ {fmtShelfLife(item.shelfLife)}</span>}
                  </div>
                </div>
              )}

              <div className="row" style={{ justifyContent: 'space-between', marginTop: 14, paddingTop: 12, borderTop: '1px dashed var(--border)', fontSize: 12 }}>
                <span style={{ color: 'var(--text-muted)' }}>ผู้ทำรายการ</span>
                <span style={{ color: 'var(--text-primary)' }}>{store.currentUser?.name || '—'}</span>
              </div>
            </div>
          </div>

          {/* Recent transfers */}
          <div className="card tech">
            <div className="card-head">
              <div className="card-title">การโอนล่าสุด</div>
              <span className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>RECENT_6</span>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {state.movements.filter(m => m.type === 'TRANSFER').slice(0, 6).map(m => {
                const fromLoc2 = state.locations.find(l => l.id === m.from);
                const toLoc2 = state.locations.find(l => l.id === m.to);
                const wh = state.warehouses.find(w => w.id === (fromLoc2?.wh || toLoc2?.wh));
                const mins = Math.floor((Date.now() - m.ts) / 60000);
                const timeStr = mins < 60 ? `${mins}m ago` : mins < 1440 ? `${Math.floor(mins/60)}h ago` : `${Math.floor(mins/1440)}d ago`;
                return (
                  <div key={m.id} className="transfer-log-item">
                    <div className="row" style={{ justifyContent: 'space-between' }}>
                      <div className="row" style={{ gap: 8 }}>
                        <span className="badge info"><Ic name="transfer" size={10}/>TR</span>
                        <span className="mono" style={{ fontSize: 12, color: 'var(--text-primary)', fontWeight: 600 }}>{m.sku}</span>
                        {m.lot && <span className="mono" style={{ fontSize: 10, color: 'var(--text-muted)' }}>· {m.lot}</span>}
                      </div>
                      <div className="row" style={{ gap: 8 }}>
                        <span className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>{timeStr}</span>
                        <span className="mono" style={{ color: 'var(--accent)', fontSize: 12, fontWeight: 700 }}>×{m.qty}</span>
                      </div>
                    </div>
                    <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 4 }}>
                      {wh ? `${wh.id} · ${wh.name}` : '—'}
                    </div>
                    <div className="row mono" style={{ marginTop: 4, gap: 6, fontSize: 11, alignItems: 'center', flexWrap: 'wrap' }}>
                      <span style={{ color: 'var(--text-secondary)', background: 'var(--bg-base)', padding: '2px 6px', borderRadius: 4, border: '1px solid var(--border)' }}>
                        <Ic name="pin" size={9} style={{ display: 'inline', marginRight: 3, color: 'var(--warning)' }}/>{m.from || '—'}
                      </span>
                      <Ic name="arrow-right" size={11} style={{ color: 'var(--accent)' }}/>
                      <span style={{ color: 'var(--text-primary)', background: 'var(--accent-soft)', padding: '2px 6px', borderRadius: 4, border: '1px solid rgba(34,211,238,0.25)' }}>
                        <Ic name="pin" size={9} style={{ display: 'inline', marginRight: 3, color: 'var(--accent)' }}/>{m.to || '—'}
                      </span>
                    </div>
                    {fromLoc2 && toLoc2 && (
                      <div className="mono" style={{ fontSize: 9.5, color: 'var(--text-dim)', marginTop: 3 }}>
                        {fromLoc2.zoneName} → {toLoc2.zoneName}
                      </div>
                    )}
                  </div>
                );
              })}
              {state.movements.filter(m => m.type === 'TRANSFER').length === 0 && (
                <div className="empty" style={{ padding: 16, fontSize: 12 }}>ยังไม่มีประวัติการโอน</div>
              )}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}


// ========= Stock Count =========
function PageCount() {
  const store = useStore();
  const { state, adjustCount } = store;
  const toast = useToast();
  const cwh = store.currentWarehouse();
  const whLocs = useOM(() => state.locations.filter(l => l.wh === cwh.id).sort(cmpLoc), [state.locations, cwh.id]);
  const itemAt = (sku) => state.items.find(i => i.sku === sku);
  const locAt = (id) => state.locations.find(l => l.id === id);
  // SKUs that have stock in the current warehouse (for By SKU mode)
  const whSkus = useOM(() => {
    const locIds = new Set(whLocs.map(l => l.id));
    return [...new Set(state.stock.filter(s => locIds.has(s.locId) && s.qty > 0).map(s => s.sku))]
      .map(sku => state.items.find(i => i.sku === sku) || { sku, name_th: sku })
      .sort(cmpItem);
  }, [state.stock, whLocs]);

  const [mode, setMode] = useOS('location'); // 'location' | 'sku'
  const [selectedLoc, setSelectedLoc] = useOS(() => whLocs[0]?.id || '');
  const [selectedSku, setSelectedSku] = useOS('');
  const [scans, setScans] = useOS({});      // key = "sku||locId||lot"
  const [active, setActive] = useOS(null);   // {sku, locId, lot} | null
  const [pad, setPad] = useOS('');

  const resetSession = () => { setScans({}); setActive(null); setPad(''); };

  // Reset selections when warehouse changes
  React.useEffect(() => {
    setSelectedLoc(state.locations.filter(l => l.wh === cwh.id).sort(cmpLoc)[0]?.id || '');
    setSelectedSku('');
    resetSession();
  }, [cwh.id]);
  // Default the SKU selector to the first available SKU when entering By SKU mode
  React.useEffect(() => {
    if (mode === 'sku' && !selectedSku && whSkus[0]) setSelectedSku(whSkus[0].sku);
  }, [mode, whSkus, selectedSku]);

  // Entries to count, by mode
  const entries = mode === 'location'
    ? state.stock.filter(s => s.locId === selectedLoc && s.qty > 0)
        .sort((a, b) => cmpItem(itemAt(a.sku) || { name_th: a.sku }, itemAt(b.sku) || { name_th: b.sku }) || (a.expiry || Infinity) - (b.expiry || Infinity))
    : state.stock.filter(s => s.sku === selectedSku && s.qty > 0 && whLocs.some(l => l.id === s.locId))
        .sort((a, b) => cmpLoc(locAt(a.locId) || {}, locAt(b.locId) || {}) || (a.expiry || Infinity) - (b.expiry || Infinity));

  const keyOf = (s) => `${s.sku}||${s.locId}||${s.lot}`;
  const counted = Object.keys(scans).length;
  const total = entries.length;

  const expected = active
    ? (entries.find(s => s.sku === active.sku && s.locId === active.locId && s.lot === active.lot)?.qty || 0)
    : 0;
  const variance = active ? Number(pad || 0) - expected : 0;

  const commit = () => {
    if (!active) return;
    const key = `${active.sku}||${active.locId}||${active.lot}`;
    setScans(prev => ({ ...prev, [key]: Number(pad || 0) }));
    adjustCount(active.sku, active.locId, Number(pad || 0), `Cycle count at ${active.locId}`, active.lot);
    setActive(null); setPad('');
    if (variance !== 0) toast.info('บันทึก variance', `${active.sku} LOT ${active.lot}: ${variance > 0 ? '+' : ''}${variance}`);
    else toast.success('นับตรงตามระบบ', `${active.sku} · LOT ${active.lot}`);
  };

  const finishSession = () => {
    fireConfetti();
    toast.success('Cycle count เสร็จสิ้น', `ตรวจครบ ${counted} รายการ`);
    setScans({});
  };

  return (
    <div className="page-enter">
      <div className="page-header">
        <div>
          <h2 className="page-title">นับสต็อก <span className="muted mono" style={{fontSize:14, marginLeft:8}}>// CYCLE COUNT</span></h2>
          <div className="page-subtitle">ตรวจนับสต็อกจริงเทียบกับระบบ พร้อมปรับยอด variance อัตโนมัติ</div>
        </div>
        <div className="row">
          <div className="segmented">
            <button className={mode === 'location' ? 'active' : ''} onClick={() => { setMode('location'); resetSession(); }}>By Location</button>
            <button className={mode === 'sku' ? 'active' : ''} onClick={() => { setMode('sku'); resetSession(); }}>By SKU</button>
          </div>
        </div>
      </div>

      <div className="grid-2" style={{ gridTemplateColumns: '1.2fr 1fr', gap: 18 }}>
        <div className="card tech">
          <div className="card-head">
            <div>
              <div className="card-title">{mode === 'location' ? 'รายการสินค้าที่ Location' : 'ตำแหน่งที่เก็บของ SKU'}</div>
              <div className="card-sub">{counted}/{total} COUNTED</div>
            </div>
            {mode === 'location' ? (
              <select className="select" style={{ width: 200, fontSize: 12 }} value={selectedLoc} onChange={e => { setSelectedLoc(e.target.value); resetSession(); }}>
                {whLocs.map(l => <option key={l.id} value={l.id}>{l.id} · {l.zoneName}</option>)}
              </select>
            ) : (
              <select className="select" style={{ width: 230, fontSize: 12 }} value={selectedSku} onChange={e => { setSelectedSku(e.target.value); resetSession(); }}>
                {whSkus.length === 0 && <option value="">— ไม่มีสินค้าในคลัง —</option>}
                {whSkus.map(it => <option key={it.sku} value={it.sku}>{it.sku} · {it.name_th}</option>)}
              </select>
            )}
          </div>

          <div style={{ display: 'flex', flexDirection: 'column', gap: 6, maxHeight: 460, overflowY: 'auto' }}>
            {entries.length === 0 && <div className="empty"><Ic name="box" size={28}/>{mode === 'location' ? 'Location นี้ยังไม่มีสินค้า' : 'SKU นี้ไม่มีสต็อกในคลัง'}</div>}
            {entries.map(s => {
              const it = itemAt(s.sku);
              const loc = locAt(s.locId);
              const key = keyOf(s);
              const cs = scans[key];
              const var2 = cs !== undefined ? cs - s.qty : null;
              const isActive = active?.sku === s.sku && active?.locId === s.locId && active?.lot === s.lot;
              return (
                <div key={key}
                  onClick={() => { setActive({ sku: s.sku, locId: s.locId, lot: s.lot }); setPad(String(cs ?? '')); }}
                  className="row"
                  style={{
                    padding: '10px 12px', borderRadius: 8,
                    border: `1px solid ${isActive ? 'var(--accent)' : 'var(--border)'}`,
                    background: cs !== undefined ? 'var(--success-soft)' : 'var(--bg-base)',
                    cursor: 'pointer', gap: 10,
                  }}>
                  <div className="thumb" style={{ width: 34, height: 34 }}><Ic name="package" size={14}/></div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    {mode === 'location' ? (
                      <>
                        <div style={{ fontSize: 13 }}>{it?.name_th || s.sku}</div>
                        <div className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>{s.sku} · LOT {s.lot}</div>
                      </>
                    ) : (
                      <>
                        <div className="mono" style={{ fontSize: 12.5, color: 'var(--accent)' }}><Ic name="pin" size={11} style={{ display: 'inline', marginRight: 4, opacity: 0.6 }}/>{s.locId}</div>
                        <div className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>{loc?.zoneName || ''} · LOT {s.lot}</div>
                      </>
                    )}
                    {s.expiry && (() => { const st = expiryStatus(s.expiry); return <span className={`badge ${st.badge}`} style={{fontSize:9.5}}>{st.label}</span>; })()}
                  </div>
                  <div className="mono" style={{ fontSize: 11, color: 'var(--text-muted)', textAlign: 'right' }}>
                    <div>SYS <span style={{ color: 'var(--text-primary)' }}>{s.qty}</span></div>
                    {cs !== undefined && <div style={{ color: var2 === 0 ? 'var(--success)' : var2 > 0 ? 'var(--info)' : 'var(--danger)' }}>CNT {cs} ({var2 > 0 ? '+' : ''}{var2})</div>}
                  </div>
                </div>
              );
            })}
          </div>

          {counted > 0 && (
            <button className="btn btn-success" style={{ width: '100%', marginTop: 14, justifyContent: 'center' }} onClick={finishSession}>
              <Ic name="check-circle" size={14}/>เสร็จสิ้น Session ({counted}/{total})
            </button>
          )}
        </div>

        <div className="card tech" style={{ position: 'sticky', top: 0 }}>
          <div className="card-head">
            <div className="card-title">นับด้วย Number Pad</div>
            {variance !== 0 && active && <span className={`badge ${variance > 0 ? 'info' : 'crit'}`}>VARIANCE {variance > 0 ? '+' : ''}{variance}</span>}
          </div>

          {active ? (
            <>
              <div style={{ padding: '8px 0 14px' }}>
                <div className="mono" style={{ fontSize: 11, color: 'var(--text-muted)' }}>{active.sku} · {active.locId} · LOT {active.lot}</div>
                <div style={{ fontSize: 16, marginTop: 2 }}>{itemAt(active.sku)?.name_th}</div>
                <div className="mono" style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 4 }}>SYSTEM QTY: <span style={{ color: 'var(--text-primary)' }}>{expected}</span></div>
              </div>

              <div style={{
                background: 'var(--bg-base)', border: '1px solid var(--border)',
                borderRadius: 10, padding: 18, marginBottom: 14, textAlign: 'right',
                fontFamily: 'var(--font-mono)', fontSize: 32, color: 'var(--accent)',
                minHeight: 64,
              }}>{pad || '0'}</div>

              <div className="numpad">
                {['7','8','9','4','5','6','1','2','3','C','0','⌫'].map(k => (
                  <button key={k} onClick={() => {
                    if (k === 'C') setPad('');
                    else if (k === '⌫') setPad(p => p.slice(0, -1));
                    else setPad(p => (p + k).slice(0, 6));
                  }}>{k}</button>
                ))}
              </div>

              <div className="grid-2" style={{ marginTop: 14 }}>
                <button className="btn btn-ghost" onClick={() => { setActive(null); setPad(''); }}>ยกเลิก</button>
                <button className="btn btn-primary" style={{ justifyContent: 'center' }} onClick={commit}><Ic name="check" size={14}/>บันทึก</button>
              </div>
            </>
          ) : (
            <div className="empty">
              <Ic name="count" size={32}/>
              <div>เลือกรายการสินค้าจากด้านซ้ายเพื่อเริ่มนับ</div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ========= Barcode Scanner =========
function PageScanner() {
  const { state } = useStore();
  const toast = useToast();
  const [scanned, setScanned] = useOS([]);
  const [mode, setMode] = useOS('IN');

  const simulate = () => {
    const item = state.items[Math.floor(Math.random() * state.items.length)];
    const time = new Date().toLocaleTimeString();
    setScanned(prev => [{ time, sku: item.sku, name: item.name_th, barcode: item.barcode, mode }, ...prev.slice(0, 11)]);
    toast.success(`สแกน: ${item.sku}`, item.name_th);
  };

  return (
    <div className="page-enter">
      <div className="page-header">
        <div>
          <h2 className="page-title">Barcode Scanner</h2>
          <div className="page-subtitle">โหมดสแกนแบบ continuous · เชื่อมต่อกับ Receipt / Issue / Count</div>
        </div>
        <div className="segmented">
          {['IN', 'OUT', 'COUNT', 'INFO'].map(m => (
            <button key={m} className={mode === m ? 'active' : ''} onClick={() => setMode(m)}>{m}</button>
          ))}
        </div>
      </div>

      <div className="grid-2" style={{ gridTemplateColumns: '1.2fr 1fr', gap: 18 }}>
        <div className="card tech">
          <div className="scanner-view">
            <div className="scan-bracket tr"/>
            <div className="scan-bracket bl"/>
            <div className="scan-line"/>
            <div style={{ position: 'absolute', top: 14, left: 16, color: 'var(--accent)', fontFamily: 'var(--font-mono)', fontSize: 11 }}>
              ● LIVE · MODE_{mode}
            </div>
            <div style={{ position: 'absolute', bottom: 14, right: 16, color: 'var(--text-muted)', fontFamily: 'var(--font-mono)', fontSize: 11 }}>
              READY · ALIGN_BARCODE_IN_FRAME
            </div>
          </div>

          <div className="row" style={{ marginTop: 16, gap: 10 }}>
            <input className="input mono" placeholder="หรือพิมพ์ barcode... (เช่น 8851234500011)" style={{ flex: 1 }}/>
            <button className="btn btn-primary" onClick={simulate}><Ic name="qr" size={14}/>จำลองการสแกน</button>
          </div>
          <div className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)', marginTop: 8 }}>
            // Continuous mode: ระบบจะอ่าน barcode อัตโนมัติเมื่ออยู่ในกรอบ
          </div>
        </div>

        <div className="card tech">
          <div className="card-head">
            <div className="card-title">Scan History</div>
            <span className="mono" style={{ fontSize: 11, color: 'var(--text-muted)' }}>{scanned.length} / 12</span>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6, maxHeight: 380, overflowY: 'auto' }}>
            {scanned.length === 0 && <div className="empty"><Ic name="qr" size={28}/>ยังไม่มีการสแกน</div>}
            {scanned.map((s, i) => (
              <div key={i} className="row" style={{ padding: '8px 10px', borderRadius: 8, background: 'var(--bg-base)', border: '1px solid var(--border)', gap: 10 }}>
                <span className={`badge ${s.mode === 'IN' ? 'ok' : s.mode === 'OUT' ? 'warn' : 'info'}`}>{s.mode}</span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{s.name}</div>
                  <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)' }}>{s.barcode}</div>
                </div>
                <span className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>{s.time}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// ========= Shared subcomponents =========
function SumRow({ label, value, highlight, small, mono }) {
  return (
    <div className="row" style={{ justifyContent: 'space-between' }}>
      <span style={{ fontSize: small ? 11 : 12, color: 'var(--text-muted)', fontFamily: small ? 'var(--font-mono)' : 'inherit', textTransform: small ? 'uppercase' : 'none', letterSpacing: small ? '0.06em' : 0 }}>{label}</span>
      <span style={{
        fontSize: highlight ? 20 : (small ? 11.5 : 13),
        fontFamily: (highlight || mono || small) ? 'var(--font-mono)' : 'inherit',
        fontWeight: highlight ? 700 : 500,
        color: highlight ? 'var(--accent)' : 'var(--text-primary)',
      }}>{value}</span>
    </div>
  );
}

function ItemPicker({ open, onClose, onPick, requireStock }) {
  const { state } = useStore();
  const [q, setQ] = useOS('');
  const [cat, setCat] = useOS('all');
  const cats = ['all', ...[...new Set(state.items.map(i => i.category).filter(Boolean))].sort((a, b) => String(a).localeCompare(String(b), 'th'))];
  const items = state.items.filter(i =>
    (cat === 'all' || i.category === cat) &&
    (!q || i.sku.toLowerCase().includes(q.toLowerCase()) ||
      (i.name_th || '').toLowerCase().includes(q.toLowerCase()) || (i.name || '').toLowerCase().includes(q.toLowerCase()) ||
      (i.barcode || '').includes(q))
  ).sort(cmpItem);
  return (
    <Modal open={open} onClose={onClose} title="เลือกสินค้า" width={620}>
      <div className="searchbar" style={{ marginBottom: 10, maxWidth: 'none', borderRadius: 8 }}>
        <Ic name="search" size={14}/>
        <input autoFocus placeholder="ค้นหา SKU, ชื่อ, barcode..." value={q} onChange={e => setQ(e.target.value)}/>
      </div>
      <div className="segmented" style={{ marginBottom: 12, flexWrap: 'wrap' }}>
        {cats.map(c => <button key={c} className={cat === c ? 'active' : ''} onClick={() => setCat(c)}>{c === 'all' ? 'ทุกหมวด' : c}</button>)}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6, maxHeight: 380, overflowY: 'auto' }}>
        {items.map(i => {
          const totalQty = state.stock.filter(s => s.sku === i.sku).reduce((a,b)=>a+b.qty,0);
          const disabled = requireStock && totalQty === 0;
          return (
            <div key={i.sku} onClick={() => !disabled && onPick(i)}
              className="row" style={{
                padding: 10, borderRadius: 8, gap: 12,
                border: '1px solid var(--border)', background: 'var(--bg-base)',
                cursor: disabled ? 'not-allowed' : 'pointer', opacity: disabled ? 0.4 : 1,
              }}>
              <div className="thumb" style={{ width: 36, height: 36 }}><Ic name="package" size={14}/></div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13 }}>{i.name_th}</div>
                <div className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>{i.sku} · {i.category} · ฿{i.unit_price}</div>
              </div>
              <span className={`badge ${totalQty === 0 ? 'crit' : totalQty < i.min ? 'warn' : 'ok'}`}>{totalQty} u</span>
            </div>
          );
        })}
      </div>
    </Modal>
  );
}

// ========= Generic List Picker (combobox w/ add+remove+rename) =========
function ListPicker({ value, onChange, items, onAdd, onDelete, onRename, placeholder, addLabel, deleteLabel, deleteConfirm, addTitle, addedMsg, removedMsg, renamedMsg }) {
  const toast = useToast();
  const [open, setOpen] = useOS(false);
  const [q, setQ] = useOS('');
  const [editingId, setEditingId] = useOS(null);
  const [editVal, setEditVal] = useOS('');
  const ref = React.useRef(null);

  React.useEffect(() => {
    const close = (e) => { if (ref.current && !ref.current.contains(e.target)) { setOpen(false); setEditingId(null); } };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, []);

  const list = items || [];
  const filtered = q ? list.filter(c => c.name.toLowerCase().includes(q.toLowerCase())) : list;
  const typedExists = q && list.find(c => c.name === q.trim());

  const handleAdd = () => {
    const name = q.trim();
    if (!name) return;
    if (typedExists) { onChange(name); setQ(''); setOpen(false); return; }
    onAdd(name);
    onChange(name);
    toast.success(addedMsg || 'เพิ่มแล้ว', name);
    setQ('');
    setOpen(false);
  };

  const handleDelete = (e, c) => {
    e.stopPropagation();
    if (!confirm((deleteConfirm || 'ลบ "{name}" ?').replace('{name}', c.name))) return;
    onDelete(c.id);
    if (value === c.name) {
      const next = list.find(x => x.id !== c.id);
      onChange(next?.name || '');
    }
    toast.info(removedMsg || 'ลบแล้ว', c.name);
  };

  const startEdit = (e, c) => {
    e.stopPropagation();
    setEditingId(c.id);
    setEditVal(c.name);
  };

  const saveEdit = (e, c) => {
    if (e) e.stopPropagation();
    const newName = editVal.trim();
    if (!newName) { setEditingId(null); return; }
    if (newName === c.name) { setEditingId(null); return; }
    // prevent duplicates
    if (list.find(x => x.id !== c.id && x.name === newName)) {
      toast.error('ชื่อซ้ำ', newName);
      return;
    }
    onRename && onRename(c.id, newName);
    if (value === c.name) onChange(newName);
    toast.success(renamedMsg || 'แก้ไขชื่อแล้ว', `${c.name} → ${newName}`);
    setEditingId(null);
  };

  const cancelEdit = (e) => { if (e) e.stopPropagation(); setEditingId(null); };

  return (
    <div className="combo" ref={ref}>
      <button type="button" className={`combo-trigger ${open ? 'open' : ''}`} onClick={() => setOpen(!open)}>
        <span className="combo-trigger-value">{value || <span style={{ color: 'var(--text-muted)' }}>{placeholder || '-- เลือก --'}</span>}</span>
        <Ic name="chevron-down" size={12}/>
      </button>
      {open && (
        <div className="combo-menu">
          <div className="combo-search">
            <Ic name="search" size={13}/>
            <input autoFocus placeholder={addTitle || 'ค้นหา หรือพิมพ์ชื่อใหม่...'} value={q}
              onChange={e => setQ(e.target.value)}
              onKeyDown={e => { if (e.key === 'Enter') handleAdd(); }}/>
          </div>
          <div className="combo-list">
            {filtered.length === 0 && !q && (
              <div className="combo-empty mono">ยังไม่มีรายการ · พิมพ์ชื่อเพื่อเพิ่ม</div>
            )}
            {filtered.map(c => {
              const isEditing = editingId === c.id;
              return (
                <div key={c.id} className={`combo-item ${value === c.name ? 'active' : ''} ${isEditing ? 'editing' : ''}`}
                  onClick={() => { if (!isEditing) { onChange(c.name); setOpen(false); setQ(''); } }}>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    {isEditing ? (
                      <input autoFocus className="combo-edit-input"
                        value={editVal} onClick={e => e.stopPropagation()}
                        onChange={e => setEditVal(e.target.value)}
                        onKeyDown={e => {
                          if (e.key === 'Enter') saveEdit(e, c);
                          else if (e.key === 'Escape') cancelEdit(e);
                        }}/>
                    ) : (
                      <>
                        <div style={{ fontSize: 13, color: 'var(--text-primary)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.name}</div>
                        <div className="mono" style={{ fontSize: 10, color: 'var(--text-muted)' }}>{c.id}</div>
                      </>
                    )}
                  </div>
                  {!isEditing && value === c.name && <Ic name="check" size={13} style={{ color: 'var(--accent)' }}/>}
                  {isEditing ? (
                    <>
                      <button className="combo-action" data-tip="บันทึก (Enter)" onClick={(e) => saveEdit(e, c)}>
                        <Ic name="check" size={12} style={{ color: 'var(--success)' }}/>
                      </button>
                      <button className="combo-action" data-tip="ยกเลิก (Esc)" onClick={cancelEdit}>
                        <Ic name="x" size={12}/>
                      </button>
                    </>
                  ) : (
                    <>
                      {onRename && (
                        <button className="combo-action edit" data-tip="แก้ไขชื่อ" onClick={(e) => startEdit(e, c)}>
                          <Ic name="edit" size={11}/>
                        </button>
                      )}
                      <button className="combo-action danger" data-tip={deleteLabel || 'ลบ'} onClick={(e) => handleDelete(e, c)}>
                        <Ic name="trash" size={11}/>
                      </button>
                    </>
                  )}
                </div>
              );
            })}
          </div>
          {q && !typedExists && (
            <div className="combo-add" onClick={handleAdd}>
              <Ic name="plus" size={13}/>
              <span>{addLabel || 'เพิ่ม'} "<b>{q}</b>"</span>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// Customer-specific wrapper
function CustomerPicker({ value, onChange }) {
  const store = useStore();
  return <ListPicker
    value={value} onChange={onChange}
    items={store.state.customers || []}
    onAdd={(name) => store.addCustomer(name)}
    onDelete={(id) => store.deleteCustomer(id)}
    onRename={(id, newName) => store.renameCustomer(id, newName)}
    placeholder="-- เลือกลูกค้า --"
    addLabel="เพิ่ม"
    addTitle="ค้นหา หรือพิมพ์ชื่อลูกค้าใหม่..."
    deleteLabel="ลบลูกค้านี้"
    deleteConfirm='ลบลูกค้า "{name}" ?'
    addedMsg="เพิ่มลูกค้าใหม่"
    removedMsg="ลบลูกค้าแล้ว"
    renamedMsg="แก้ไขชื่อลูกค้า"
  />;
}

// Supplier-specific wrapper
function SupplierPicker({ value, onChange }) {
  const store = useStore();
  return <ListPicker
    value={value} onChange={onChange}
    items={store.state.suppliers || []}
    onAdd={(name) => store.addSupplier(name)}
    onDelete={(id) => store.deleteSupplier(id)}
    onRename={(id, newName) => store.renameSupplier(id, newName)}
    placeholder="-- เลือกผู้จำหน่าย --"
    addLabel="เพิ่ม"
    addTitle="ค้นหา หรือพิมพ์ชื่อผู้จำหน่ายใหม่..."
    deleteLabel="ลบผู้จำหน่ายนี้"
    deleteConfirm='ลบผู้จำหน่าย "{name}" ?'
    addedMsg="เพิ่มผู้จำหน่ายใหม่"
    removedMsg="ลบผู้จำหน่ายแล้ว"
    renamedMsg="แก้ไขชื่อผู้จำหน่าย · อัปเดตสินค้าที่อ้างชื่อนี้ทั้งหมด"
  />;
}

// Category-specific wrapper — add/edit/delete product categories inline
function CategoryPicker({ value, onChange }) {
  const store = useStore();
  return <ListPicker
    value={value} onChange={onChange}
    items={store.state.categories || []}
    onAdd={(name) => store.addCategory(name)}
    onDelete={(id) => store.deleteCategory(id)}
    onRename={(id, newName) => store.renameCategory(id, newName)}
    placeholder="-- เลือกหมวด --"
    addLabel="เพิ่ม"
    addTitle="ค้นหา หรือพิมพ์ชื่อหมวดใหม่..."
    deleteLabel="ลบหมวดนี้"
    deleteConfirm='ลบหมวด "{name}" ?'
    addedMsg="เพิ่มหมวดใหม่"
    removedMsg="ลบหมวดแล้ว"
    renamedMsg="แก้ไขชื่อหมวด · อัปเดตสินค้าที่อ้างหมวดนี้ทั้งหมด"
  />;
}

Object.assign(window, { PageReceive, PageIssue, PageTransfer, PageCount, PageScanner, CustomerPicker, SupplierPicker, CategoryPicker, ListPicker });
