// screen-products.jsx — Product Pool (Stage-1 approval). CRITICAL, dense, fast.
const { useState: useStateP, useEffect: useEffectP, useMemo, useRef: useRefP } = React;

const SORTS = [
  { value: 'score', label: 'Điểm cao' },
  { value: 'created', label: 'Mới nhất' },
  { value: 'price', label: 'Giá thấp' },
];

function ProductsScreen({ layout }) {
  const app = useApp();
  const [q, setQ] = useStateP('');
  const [statusFilter, setStatusFilter] = useStateP('active'); // 'active' (pending+eligible) | 'all' | 'pending' | 'eligible' | 'invalid' | 'skipped' | 'archived' | 'has-posts' | 'never-posted'
  const [brands, setBrands] = useStateP([]); // empty = all
  const [minScore, setMinScore] = useStateP(0);
  const [minCoupon, setMinCoupon] = useStateP(0);
  const [watchOnly, setWatchOnly] = useStateP(false);
  const [confidence, setConfidence] = useStateP('all');
  const [maxVnd, setMaxVnd] = useStateP(0); // 0 = no cap
  const [sort, setSort] = useStateP('score');
  const [sel, setSel] = useStateP(new Set());
  const [open, setOpen] = useStateP(null);   // product in drawer
  const [cursor, setCursor] = useStateP(0);   // keyboard cursor
  const data = app.products;
  const setData = app.setProducts;
  const [advancedOpen, setAdvancedOpen] = useStateP(false);
  const [activePreset, setActivePreset] = useStateP(null);
  const activeFilterCount = (brands.length > 0 ? 1 : 0) + (minScore > 0 ? 1 : 0) + (minCoupon > 0 ? 1 : 0) + (confidence !== 'all' ? 1 : 0) + (watchOnly ? 1 : 0);
  const containerRef = useRefP(null);
  const justAddedRef = useRefP(null);
  useEffectP(() => {
    if (app.newProductId && justAddedRef.current) {
      justAddedRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' });
    }
  }, [app.newProductId]);

  const filtered = useMemo(() => {
    let r = data.filter(p => {
      if (statusFilter === 'has-posts') { if (postCountFor(p.id) === 0) return false; }
      else if (statusFilter === 'never-posted') { if (postedCountFor(p.id) > 0) return false; }
      else if (statusFilter === 'active') { if (!['pending', 'eligible'].includes(p.status)) return false; }
      else if (statusFilter !== 'all') { if (p.status !== statusFilter) return false; }
      if (brands.length && !brands.includes(p.brand)) return false;
      if (p.score < minScore) return false;
      if (minCoupon > 0 && (p.couponPercent || 0) < minCoupon) return false;
      if (watchOnly && !p.watchlistMatch) return false;
      if (confidence !== 'all' && (p.confidence || 'medium') !== confidence) return false;
      if (maxVnd > 0 && (p.priceVnd || p.vnd) > maxVnd) return false;
      if (q) {
        const hay = (p.titleVn + ' ' + p.titleJp + ' ' + p.sku + ' ' + p.url).toLowerCase();
        if (!hay.includes(q.toLowerCase())) return false;
      }
      return true;
    });
    r = [...r].sort((a, b) => {
      if (sort === 'score') return (b.score ?? -1) - (a.score ?? -1);
      if (sort === 'price') return (a.priceVnd || a.vnd) - (b.priceVnd || b.vnd);
      return 0;
    });
    return r;
  }, [data, statusFilter, brands, minScore, minCoupon, watchOnly, confidence, maxVnd, q, sort]);

  // Counts per status — for badge in dropdown
  const statusCounts = useMemo(() => {
    const c = { all: data.length, active: 0, pending: 0, eligible: 0, invalid: 0, skipped: 0, archived: 0, 'has-posts': 0, 'never-posted': 0 };
    data.forEach(p => {
      c[p.status] = (c[p.status] || 0) + 1;
      if (['pending', 'eligible'].includes(p.status)) c.active++;
      if (postCountFor(p.id) > 0) c['has-posts']++;
      if (postedCountFor(p.id) === 0) c['never-posted']++;
    });
    return c;
  }, [data]);

  const applyPreset = (preset) => {
    setActivePreset(preset.id);
    const Q = preset.query;
    setQ(''); setStatusFilter('active'); setBrands([]);
    setMinScore(Q.minScore || 0);
    setMinCoupon(Q.minCouponPercent || 0);
    setWatchOnly(!!Q.watchlistOnly);
    setConfidence(Q.confidence || 'all');
    setMaxVnd(Q.maxPriceVnd || 0);
    app.toast && app.toast('Đã áp dụng preset "' + preset.name + '"', preset.icon, preset.color);
  };

  // keyboard nav
  useEffectP(() => {
    const h = (e) => {
      if (open || app.modalOpen) return;
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
      const max = filtered.length - 1;
      if (e.key === 'j') { e.preventDefault(); setCursor(c => Math.min(max, c + 1)); }
      else if (e.key === 'k') { e.preventDefault(); setCursor(c => Math.max(0, c - 1)); }
      else if (e.key === 'a' && filtered[cursor]) { approve(filtered[cursor]); }
      else if (e.key === 's' && filtered[cursor]) { skip(filtered[cursor]); }
      else if (e.key === 'Enter' && filtered[cursor]) { setOpen(filtered[cursor]); }
    };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, [filtered, cursor, open, app.modalOpen]);

  // Product becomes eligible. Post creation happens in Content hub (WF03).
  const approve = (p) => {
    setData(d => d.map(x => x.id === p.id ? { ...x, status: 'eligible' } : x));
    app.toast(`Đã duyệt "${p.titleVn.slice(0, 24)}…", sẵn sàng tạo bài`, 'check', 'var(--green)');
  };
  const skip = (p) => {
    setData(d => d.map(x => x.id === p.id ? { ...x, status: 'skipped' } : x));
    app.toast('Đã bỏ qua sản phẩm', 'skip', 'var(--text-3)');
  };
  // Approve (if still pending) then jump into Compose wizard with this/these products pre-selected.
  const goCompose = (ids) => {
    const idList = Array.isArray(ids) ? ids : [ids];
    setData(d => d.map(x => idList.includes(x.id) && x.status === 'pending' ? { ...x, status: 'eligible' } : x));
    app.go('compose', idList);
  };
  const bulkApprove = () => { sel.forEach(id => { const p = data.find(x => x.id === id); if (p) approve(p); }); setSel(new Set()); };
  const toggleSel = (id) => setSel(s => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const toggleBrand = (b) => setBrands(a => a.includes(b) ? a.filter(x => x !== b) : [...a, b]);

  const reset = () => {
    setQ(''); setStatusFilter('all'); setBrands([]); setMinScore(0);
    setMinCoupon(0); setWatchOnly(false); setConfidence('all'); setMaxVnd(0);
    setActivePreset(null);
  };

  const FilterBar = (
    <div className="card" style={{ padding: 12, marginBottom: 14 }}>
      {/* Compact default row: Preset · Search · Status · Sort · Filter */}
      <div className="row-wrap" style={{ gap: 8, alignItems: 'center' }}>
        <select className="input" style={{ width: 'auto', height: 34, padding: '0 28px 0 10px', minWidth: 140, fontSize: 13 }}
                value={activePreset || ''}
                onChange={e => {
                  const id = e.target.value;
                  if (!id) { setActivePreset(null); return; }
                  const p = FILTER_PRESETS.find(x => x.id === id);
                  if (p) applyPreset(p);
                }}>
          <option value="">Preset…</option>
          {FILTER_PRESETS.map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
        </select>
        <div className="input-search" style={{ flex: 1, minWidth: 180 }}>
          <Icon name="search" size={16} />
          <input className="input" placeholder="Tìm sản phẩm, SKU, URL…" value={q} onChange={e => setQ(e.target.value)} />
        </div>
        <select className="input" style={{ width: 'auto', height: 34, padding: '0 28px 0 10px', minWidth: 190, fontSize: 13 }}
                value={statusFilter} onChange={e => setStatusFilter(e.target.value)}>
          <option value="active">Đang xử lý ({statusCounts.active || 0})</option>
          <option value="all">Tất cả ({statusCounts.all})</option>
          <option value="pending">Chờ duyệt ({statusCounts.pending || 0})</option>
          <option value="eligible">Đã duyệt, sẵn sàng đăng ({statusCounts.eligible || 0})</option>
          <option value="invalid">Không hợp lệ ({statusCounts.invalid || 0})</option>
          <option value="skipped">Đã bỏ qua ({statusCounts.skipped || 0})</option>
          <option value="archived">Lưu trữ ({statusCounts.archived || 0})</option>
          <option disabled>──────────</option>
          <option value="has-posts">Đã có bài viết ({statusCounts['has-posts']})</option>
          <option value="never-posted">Chưa từng đăng ({statusCounts['never-posted']})</option>
        </select>
        <select className="input" style={{ width: 'auto', height: 34, padding: '0 28px 0 10px', minWidth: 120, fontSize: 13 }}
                value={sort} onChange={e => setSort(e.target.value)}>
          {SORTS.map(s => <option key={s.value} value={s.value}>{s.label}</option>)}
        </select>
        <Button variant={advancedOpen ? 'primary' : 'default'} size="sm" icon="filter"
                onClick={() => setAdvancedOpen(v => !v)}>
          Filter{activeFilterCount > 0 ? ` (${activeFilterCount})` : ''}
        </Button>
      </div>

      {/* Expandable advanced panel */}
      {advancedOpen && (
        <div style={{ marginTop: 12, paddingTop: 12, borderTop: '1px solid var(--border)' }}>
          <div className="row-wrap" style={{ gap: 6, marginBottom: 10, alignItems: 'center' }}>
            <span className="t-2xs strong dimmer" style={{ marginRight: 2, minWidth: 60 }}>BRAND</span>
            {BRANDS.filter(b => b.enabled !== false && !b.disabledReason).map(b => (
              <button key={b.key} className={'badge ' + (brands.includes(b.key) ? 'badge-accent' : 'badge-brand')}
                      style={{ height: 26, cursor: 'pointer' }} onClick={() => toggleBrand(b.key)}>
                <BrandLogo brand={b} size={16} />{b.name}
              </button>
            ))}
          </div>
          <div className="row-wrap" style={{ gap: 12, marginBottom: 10, alignItems: 'center' }}>
            <span className="t-2xs strong dimmer" style={{ minWidth: 60 }}>ĐIỂM ≥ <span className="mono" style={{ color: 'var(--text)' }}>{minScore}</span></span>
            <input type="range" min="0" max="100" step="5" value={minScore} onChange={e => setMinScore(+e.target.value)}
                   style={{ width: 140, accentColor: 'var(--accent)' }} />
            <div style={{ width: 1, height: 22, background: 'var(--border)' }}></div>
            <span className="t-2xs strong dimmer">COUPON ≥ <span className="mono" style={{ color: 'var(--text)' }}>{minCoupon}%</span></span>
            <input type="range" min="0" max="50" step="5" value={minCoupon} onChange={e => setMinCoupon(+e.target.value)}
                   style={{ width: 120, accentColor: 'var(--accent)' }} />
          </div>
          <div className="row-wrap" style={{ gap: 10, alignItems: 'center' }}>
            <span className="t-2xs strong dimmer" style={{ minWidth: 60 }}>CONFIDENCE</span>
            <Seg value={confidence} options={[{ value: 'all', label: 'All' }, { value: 'high', label: 'High' }, { value: 'medium', label: 'Med' }, { value: 'low', label: 'Low' }]} onChange={setConfidence} />
            <div style={{ width: 1, height: 22, background: 'var(--border)' }}></div>
            <button className={'badge ' + (watchOnly ? 'badge-accent' : 'badge-neutral')} style={{ cursor: 'pointer' }} onClick={() => setWatchOnly(v => !v)}>
              <Icon name="star" size={12} style={{ color: watchOnly ? 'var(--accent-text)' : 'var(--yellow)' }} />
              Watchlist only
            </button>
            <div style={{ flex: 1 }}></div>
            <Button variant="ghost" size="sm" icon="x" onClick={reset}>Reset</Button>
            <Button variant="primary" size="sm" icon="check" onClick={() => setAdvancedOpen(false)}>Áp dụng</Button>
          </div>
        </div>
      )}
    </div>
  );

  const isCards = layout === 'cards';

  return (
    <div className="page-pad wide" ref={containerRef}>
      <div className="between" style={{ marginBottom: 14 }}>
        <div>
          <div className="t-h1">Product Pool</div>
          <div className="t-sm dim">{filtered.length} sản phẩm · Stage-1: quyết định có đáng đăng không</div>
        </div>
        <div className="row gap-sm desktop-only t-xs dimmer">
          <span>Phím tắt:</span><span className="kbd">J</span><span className="kbd">K</span> di chuyển<span className="kbd">A</span> duyệt<span className="kbd">S</span> bỏ qua
        </div>
      </div>

      {FilterBar}

      {/* bulk bar */}
      {sel.size > 0 && (
        <div className="card" style={{ padding: '10px 14px', marginBottom: 12, display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap', borderColor: 'var(--accent)', background: 'var(--accent-soft)' }}>
          <span className="strong t-sm">Đã chọn {sel.size}</span>
          <div className="topbar-spacer"></div>
          <Button variant="default" size="sm" icon="check" onClick={bulkApprove}>Duyệt riêng từng bài</Button>
          <Button variant="primary" size="sm" icon="sparkle" onClick={() => { goCompose([...sel]); setSel(new Set()); }}>
            {sel.size >= 2 ? 'Tạo 1 bài cho ' + sel.size + ' SP' : 'Tạo bài AI'}
          </Button>
          <Button variant="ghost" size="sm" icon="skip" onClick={() => { sel.forEach(id => { const p = data.find(x => x.id === id); if (p) skip(p); }); setSel(new Set()); }}>Bỏ qua</Button>
          <Button variant="ghost" size="sm" onClick={() => setSel(new Set())}>Hủy chọn</Button>
        </div>
      )}

      {filtered.length === 0 ? (
        (statusFilter !== 'all' || brands.length || q || minScore) ?
          <Empty icon="search" title="Không có sản phẩm phù hợp filter" desc="Thử nới lỏng điều kiện lọc để xem thêm sản phẩm." cta="Reset filter" onCta={reset} /> :
          <Empty icon="package" title="Chưa có sản phẩm nào" desc="Kho sẽ tự đầy khi hệ thống thu thập từ các trang sale Nhật, hoặc bạn dán URL thủ công." cta="Thêm sản phẩm đầu tiên" onCta={app.openAdd} />
      ) : isCards ? (
        <CardGrid items={filtered} cursor={cursor} sel={sel} onSel={toggleSel} onOpen={setOpen} approve={approve} skip={skip} newProductId={app.newProductId} justAddedRef={justAddedRef} />
      ) : (
        <div className="card desktop-only" style={{ overflow: 'hidden' }}>
          <table className="tbl">
            <thead>
              <tr>
                <th style={{ width: 36 }}><Checkbox on={sel.size === filtered.length && filtered.length > 0} onChange={(v) => setSel(v ? new Set(filtered.map(p => p.id)) : new Set())} /></th>
                <th>Sản phẩm</th>
                <th style={{ width: 130 }}>Giá VND</th>
                <th style={{ width: 60 }}>Điểm</th>
                <th style={{ width: 130 }}>Trạng thái</th>
                <th style={{ width: 90 }} title="Số bài đã đăng / tổng số bài (gồm nháp, chờ duyệt, đặt lịch)">Bài đăng</th>
                <th style={{ width: 110 }}>Nguồn</th>
                <th style={{ width: 150, textAlign: 'right' }}>Tác vụ</th>
              </tr>
            </thead>
            <tbody>
              {filtered.map((p, i) => (
                <ProductRow key={p.id} p={p} i={i} active={i === cursor} selected={sel.has(p.id)}
                            onSel={() => toggleSel(p.id)} onOpen={() => { setCursor(i); setOpen(p); }}
                            approve={approve} skip={skip} setCursor={() => setCursor(i)}
                            isNew={app.newProductId === p.id} newRef={app.newProductId === p.id ? justAddedRef : null} />
              ))}
            </tbody>
          </table>
        </div>
      )}

      {/* mobile cards (always) */}
      {!isCards && filtered.length > 0 && (
        <div className="mobile-only">
          <CardGrid items={filtered} cursor={-1} sel={sel} onSel={toggleSel} onOpen={setOpen} approve={approve} skip={skip} mobile newProductId={app.newProductId} justAddedRef={justAddedRef} />
        </div>
      )}

      {open && <ProductDrawer p={open} onClose={() => setOpen(null)} approve={(p) => { approve(p); setOpen(null); }} skip={(p) => { skip(p); setOpen(null); }} goCompose={() => { setOpen(null); goCompose(open.id); }} />}
    </div>
  );
}

function ProductRow({ p, i, active, selected, onSel, onOpen, approve, skip, setCursor, isNew, newRef }) {
  const b = brandOf(p.brand);
  const confTone = p.confidence === 'high' ? 'var(--green)' : p.confidence === 'low' ? 'var(--red)' : 'var(--yellow)';
  return (
    <tr ref={newRef} className={`${selected ? 'selected' : ''}${isNew ? ' card--just-added' : ''}`} style={active ? { boxShadow: 'inset 3px 0 0 var(--accent)', background: 'var(--surface)' } : {}}
        onClick={onOpen} onMouseEnter={setCursor}>
      <td onClick={e => e.stopPropagation()}><Checkbox on={selected} onChange={onSel} /></td>
      <td>
        <div className="row" style={{ gap: 12 }}>
          <Placeholder label="" brand={b} ratio="3/4" style={{ width: 42, height: 56, borderRadius: 7 }} />
          <div style={{ minWidth: 0, maxWidth: 380 }}>
            <div className="row gap-sm" style={{ marginBottom: 3 }}>
              <Badge variant="brand">{b.name}</Badge>
              {p.kind === 'manual' && <Badge variant="neutral" icon="edit">Nhập tay</Badge>}
              <span className="t-2xs dimmer mono clip-1">{p.sku}</span>
              <span title={'Data confidence: ' + (p.confidence || 'medium')} style={{ width: 7, height: 7, borderRadius: '50%', background: confTone }}></span>
              {p.watchlistMatch && <Icon name="star" size={12} style={{ color: 'var(--yellow)' }} title={'Watchlist: ' + p.watchlistMatch.keyword} />}
            </div>
            <div className="t-sm strong clip-1">{p.titleVn}</div>
            <div className="t-2xs dimmer clip-1" style={{ fontStyle: 'italic' }}>{p.titleJp}</div>
          </div>
        </div>
      </td>
      <td>
        <div className="t-sm strong mono">{fmtVND(p.priceVnd || p.vnd)}</div>
        <div className="row gap-sm" style={{ marginTop: 2, flexWrap: 'wrap' }}>
          {p.disc > 0 && <span className="badge badge-red" style={{ height: 17, padding: '0 5px' }}>-{p.disc}%</span>}
          {p.couponPercent > 0 && <span className="badge badge-yellow" style={{ height: 17, padding: '0 5px' }} title={p.couponText}>coupon {p.couponPercent}%</span>}
          {p.vndOld && <span className="t-2xs dimmer mono" style={{ textDecoration: 'line-through' }}>{fmtVND(p.vndOld)}</span>}
        </div>
      </td>
      <td>{p.score == null
        ? <span className="score score-na" title="Chưa có điểm">—</span>
        : <Score value={p.score} />}</td>
      <td><StatusPill status={p.status} /></td>
      <td><PostCountCell pid={p.id} /></td>
      <td>
        <div className="row gap-sm dimmer t-xs">
          <Icon name={SOURCE_ICON[p.source] || 'globe'} size={14} />
          <span>{p.created}</span>
        </div>
      </td>
      <td onClick={e => e.stopPropagation()}>
        <div className="row gap-sm" style={{ justifyContent: 'flex-end' }}>
          {p.status === 'pending' ? (
            <>
              <Button variant="default" size="sm" icon="check" onClick={() => approve(p)} title="Duyệt (A)">Duyệt</Button>
              <Button variant="ghost" size="sm" icon="skip" onClick={() => skip(p)} title="Bỏ qua (S)" />
            </>
          ) : p.status === 'eligible' ? (
            <Button variant="ghost" size="sm" icon="sparkle" onClick={onOpen}>Tạo bài</Button>
          ) : (
            <Button variant="ghost" size="sm" icon="eye" onClick={onOpen}>Xem</Button>
          )}
        </div>
      </td>
    </tr>
  );
}

function PostCountCell({ pid }) {
  const posted = postedCountFor(pid);
  const total = postCountFor(pid);
  if (total === 0) return <span className="t-2xs dimmer">—</span>;
  return (
    <div className="row gap-sm" title={posted + ' đã đăng, ' + (total - posted) + ' đang trong pipeline'}>
      <span className="t-sm mono strong" style={{ color: posted > 0 ? 'var(--green)' : 'var(--text-2)' }}>{posted}</span>
      <span className="t-xs dimmer mono">/ {total}</span>
    </div>
  );
}

function CardGrid({ items, cursor, sel, onSel, onOpen, approve, skip, mobile, newProductId, justAddedRef }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: mobile ? '1fr' : 'repeat(auto-fill, minmax(220px, 1fr))', gap: 12 }}>
      {items.map((p, i) => {
        const b = brandOf(p.brand);
        return (
          <div key={p.id} ref={newProductId === p.id ? justAddedRef : null} className={`card${newProductId === p.id ? ' card--just-added' : ''}`} style={{ overflow: 'hidden', cursor: 'pointer', display: 'flex', flexDirection: mobile ? 'row' : 'column', boxShadow: i === cursor ? '0 0 0 2px var(--accent)' : undefined, position: 'relative' }} onClick={() => onOpen(p)}>
            {p.watchlistMatch && (
              <div style={{ position: 'absolute', top: 8, right: 8, zIndex: 2, background: 'var(--yellow-soft)', color: 'var(--yellow)', borderRadius: '50%', width: 24, height: 24, display: 'grid', placeItems: 'center' }} title={'Watchlist · ' + p.watchlistMatch.keyword}>
                <Icon name="star" size={12} />
              </div>
            )}
            <Placeholder label={p.label} brand={b} ratio={mobile ? '3/4' : '4/3'} big style={mobile ? { width: 96, minWidth: 96, borderRadius: 0 } : { borderRadius: 0 }} />
            <div style={{ padding: 12, flex: 1, minWidth: 0 }}>
              <div className="between" style={{ marginBottom: 6 }}>
                <div className="row gap-sm">
                  <Badge variant="brand">{b.name}</Badge>
                  {p.kind === 'manual' && <Badge variant="neutral" icon="edit">Nhập tay</Badge>}
                </div>
                {p.score == null
                  ? <span className="score score-na" title="Chưa có điểm">—</span>
                  : <Score value={p.score} />}
              </div>
              <div className="t-sm strong clip-2" style={{ minHeight: mobile ? 0 : 38 }}>{p.titleVn}</div>
              <div className="row gap-sm" style={{ margin: '8px 0', flexWrap: 'wrap' }}>
                <span className="t-sm strong mono">{fmtVND(p.priceVnd || p.vnd)}</span>
                {p.disc > 0 && <span className="badge badge-red" style={{ height: 17 }}>-{p.disc}%</span>}
                {p.couponPercent > 0 && <span className="badge badge-yellow" style={{ height: 17 }} title={p.couponText}>{p.couponPercent}% coupon</span>}
                {postCountFor(p.id) > 0 && (
                  <span className="badge badge-blue" style={{ height: 17 }} title={postedCountFor(p.id) + ' đã đăng / ' + postCountFor(p.id) + ' tổng'}>
                    <Icon name="send" size={10} /> {postedCountFor(p.id)}/{postCountFor(p.id)}
                  </span>
                )}
              </div>
              {p.status === 'pending' ? (
                <div className="row gap-sm">
                  <Button variant="default" size="sm" icon="check" className="btn-block" onClick={(e) => { e.stopPropagation(); approve(p); }}>Duyệt</Button>
                  <Button variant="ghost" size="sm" icon="skip" onClick={(e) => { e.stopPropagation(); skip(p); }} />
                </div>
              ) : <StatusPill status={p.status} />}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function ProductDrawer({ p, onClose, approve, skip, goCompose }) {
  const b = brandOf(p.brand);
  const [img, setImg] = useStateP(0);
  const bd = p.scoreBreakdown || {};
  const vbd = p.vndBreakdown || {};
  const confTone = p.confidence === 'high' ? 'var(--green)' : p.confidence === 'low' ? 'var(--red)' : 'var(--yellow)';
  return (
    <Drawer title={p.titleVn} sub={`${b.name} · ${p.sku}`} onClose={onClose}
      foot={p.status === 'pending' ? (<>
        <Button variant="primary" icon="sparkle" className="btn-block" onClick={() => goCompose()}>Duyệt + Tạo bài AI</Button>
        <Button variant="default" icon="skip" onClick={() => skip(p)}>Bỏ qua</Button>
      </>) : p.status === 'eligible' ? (<>
        <Button variant="primary" icon="sparkle" className="btn-block" onClick={() => goCompose()}>Tạo bài AI từ sản phẩm</Button>
        <Button variant="ghost" icon="archive" onClick={onClose}>Đóng</Button>
      </>) : (<>
        <Button variant="primary" icon="eye" className="btn-block" onClick={onClose}>Đóng</Button>
      </>)}>
      <Placeholder label={p.label} brand={b} ratio="4/3" big style={{ marginBottom: 8 }} />
      <div className="row gap-sm" style={{ marginBottom: 16 }}>
        {[0, 1, 2].map(n => <Placeholder key={n} label="" brand={b} ratio="1" style={{ width: 54, height: 54, cursor: 'pointer', outline: img === n ? '2px solid var(--accent)' : 'none' }} onClick={() => setImg(n)} />)}
      </div>

      <div className="row" style={{ gap: 10, marginBottom: 8, flexWrap: 'wrap' }}>
        <div className="t-display mono" style={{ fontSize: 26 }}>{fmtVND(p.priceVnd || p.vnd)}</div>
        {p.disc > 0 && <Badge variant="red">-{p.disc}%</Badge>}
        {p.couponPercent > 0 && <Badge variant="yellow" icon="tag">coupon {p.couponPercent}%</Badge>}
        {p.watchlistMatch && <Badge variant="accent" icon="star">watchlist</Badge>}
        {p.kind === 'manual' && <Badge variant="neutral" icon="edit">Nhập tay</Badge>}
        <div className="topbar-spacer"></div>
        {p.score == null
          ? <span className="score score-na" title="Chưa có điểm">—</span>
          : <Score value={p.score} />}
      </div>
      {p.validityReason && (
        <div className="banner banner-warn" style={{ marginBottom: 12 }}>
          <Icon name="alert" size={16} style={{ color: 'var(--red)' }} />
          <span className="t-xs">Sản phẩm chưa đạt điều kiện đăng: <span className="strong">{p.validityReason}</span></span>
        </div>
      )}

      {/* ============ VND breakdown ============ */}
      <div className="card-pad panel" style={{ marginBottom: 14 }}>
        <div className="t-2xs strong dimmer" style={{ marginBottom: 8 }}>CƠ CẤU GIÁ VND</div>
        <div className="col" style={{ gap: 5 }}>
          <PriceLine label={p.couponPercent > 0 ? 'Sau coupon (¥)' : 'Giá Nhật (¥)'} value={fmtJPY(p.effectivePrice || p.jpy)} />
          {p.couponPercent > 0 && <PriceLine label="Coupon trừ đi" value={'–' + fmtJPY(p.jpy - p.effectivePrice)} tone="green" small />}
          <PriceLine label={'× tỉ giá ' + FX} value={fmtVND((vbd.product || (p.effectivePrice || p.jpy) * FX))} />
          {vbd.ship > 0 && <PriceLine label={'+ Ship ' + (p.weightKg || 0.5) + 'kg'} value={'+ ' + fmtVND(vbd.ship)} small />}
          {vbd.margin > 0 && <PriceLine label="+ Margin shop" value={'+ ' + fmtVND(vbd.margin)} small />}
          <div style={{ borderTop: '1px dashed var(--border-2)', marginTop: 4, paddingTop: 6 }}>
            <PriceLine label="Khách Việt phải trả" value={fmtVND(p.priceVnd || p.vnd)} strong />
          </div>
        </div>
      </div>

      {/* ============ Score breakdown ============ */}
      <div className="card-pad panel" style={{ marginBottom: 14 }}>
        <div className="between" style={{ marginBottom: 8 }}>
          <div className="t-2xs strong dimmer">DEAL SCORE BREAKDOWN</div>
          {p.score == null
            ? <span className="score score-na" title="Chưa có điểm">—</span>
            : <Score value={p.score} />}
        </div>
        <ScoreBar label="Brand quality"        value={bd.brand || 0}         max={20} color="var(--accent)" />
        <ScoreBar label="Discount %"           value={bd.discount || 0}      max={30} color="var(--red)"    note={bd.discountLabel} />
        <ScoreBar label="Coupon"               value={bd.coupon || 0}        max={20} color="var(--yellow)" note={p.couponPercent ? p.couponPercent + '% × ' + (SCORING_CONFIG.couponMultiplier) : null} />
        <ScoreBar label="Giá VND friendly"     value={bd.priceFriendly || 0} max={20} color="var(--blue)"   note={bd.priceFriendlyLabel} />
        <ScoreBar label="Watchlist match"      value={bd.watchlist || 0}     max={15} color="var(--yellow)" note={p.watchlistMatch ? p.watchlistMatch.keyword : null} />
        <ScoreBar label="Size availability"    value={bd.size || 0}          max={5}  color="var(--green)"  note={(p.sizeAvail || 0) + '/' + (p.sizeTotal || 0) + ' còn'} />
        <ScoreBar label="Data confidence"      value={bd.confidence || 0}    max={10} color="var(--green)"  note={p.confidence} />
      </div>

      {/* ============ Data confidence ============ */}
      <div className="card-pad panel" style={{ marginBottom: 14 }}>
        <div className="between" style={{ marginBottom: 8 }}>
          <div className="t-2xs strong dimmer">ĐỘ TIN CẬY DỮ LIỆU</div>
          <Badge variant={p.confidence === 'high' ? 'green' : p.confidence === 'low' ? 'red' : 'yellow'} icon={p.confidence === 'high' ? 'check' : p.confidence === 'low' ? 'alert' : 'eye'}>
            {(p.confidence || 'medium').toUpperCase()}
          </Badge>
        </div>
        {p.missingFields && p.missingFields.length > 0 ? (
          <div>
            <div className="t-xs dim" style={{ marginBottom: 6 }}>Thiếu field:</div>
            <div className="row gap-sm" style={{ flexWrap: 'wrap' }}>
              {p.missingFields.map(f => <Badge key={f} variant="red">{f}</Badge>)}
            </div>
            <div className="t-2xs dimmer" style={{ marginTop: 8 }}>Caption AI có thể generic vì thiếu thông tin. Admin nên re-scrape hoặc nhập thủ công.</div>
          </div>
        ) : (
          <div className="t-xs" style={{ color: confTone }}>
            <Icon name="check" size={12} /> Đầy đủ field bắt buộc + nice-to-have.
          </div>
        )}
      </div>

      <InfoRow label="Tên tiếng Nhật" value={p.titleJp} mono />
      <InfoRow label="Mã sản phẩm" value={p.productCode || p.sku} mono />
      <InfoRow label="Category" value={p.category || '—'} />
      <InfoRow label="Material" value={p.material || '—'} />
      <InfoRow label="Color" value={p.color || '—'} />
      <InfoRow label="Size" value={p.sizes.join(' · ') + ' (còn ' + (p.sizeAvail || 0) + '/' + (p.sizeTotal || 0) + ')'} />
      <InfoRow label="Cân nặng ước tính" value={(p.weightKg || 0.5) + ' kg (dùng tính phí ship)'} />
      <InfoRow label="Crawl lúc" value={p.crawledAt ? new Date(p.crawledAt).toLocaleString('vi-VN') : '—'} mono />
      <InfoRow label="URL gốc" value={<a className="row gap-sm" style={{ color: 'var(--accent)' }} href={'https://' + p.url} target="_blank" rel="noopener noreferrer">{p.url}<Icon name="external" size={13} /></a>} />

      <div className="t-eyebrow" style={{ marginTop: 16, marginBottom: 6 }}>Mô tả (đã dịch)</div>
      <p className="t-sm dim" style={{ lineHeight: 1.6 }}>{p.desc}</p>

      <ProductPostHistory pid={p.id} />

      <div className="divider"></div>
      <div className="row gap-sm">
        <Button variant="ghost" size="sm" icon="edit">Sửa bản dịch</Button>
        <Button variant="ghost" size="sm" icon="refresh">Re-scrape</Button>
        <Button variant="ghost" size="sm" icon="history">Log scrape</Button>
      </div>
    </Drawer>
  );
}

function ProductPostHistory({ pid }) {
  const app = useApp();
  const posts = postsForProduct(pid);
  if (!posts.length) return null;
  return (
    <div className="card-pad panel" style={{ marginTop: 16 }}>
      <div className="between" style={{ marginBottom: 8 }}>
        <div className="t-2xs strong dimmer">BÀI VIẾT TỪ SẢN PHẨM NÀY · {posts.length}</div>
        <Badge variant="green" icon="send">{postedCountFor(pid)} đã đăng</Badge>
      </div>
      <div className="col" style={{ gap: 6 }}>
        {posts.map(post => {
          const s = POST_STATUS[post.status] || { label: post.status, cls: 'badge-neutral' };
          return (
            <button key={post.id} className="row between" onClick={() => app.go('review', pid)}
                    style={{ width: '100%', padding: '8px 10px', background: 'var(--bg-2)', borderRadius: 'var(--r-sm)', textAlign: 'left', cursor: 'pointer' }}>
              <div className="row gap-sm" style={{ minWidth: 0 }}>
                <Icon name={post.format === 'carousel' ? 'gallery' : post.format === 'composite' ? 'sparkle' : 'send'} size={14} />
                <span className="t-xs mono dimmer">{post.id}</span>
                <span className="t-xs">{post.format === 'single' ? '1 SP' : post.productIds.length + ' SP'}</span>
              </div>
              <div className="row gap-sm">
                <span className={'badge ' + s.cls} style={{ height: 18 }}>{s.label}</span>
                {post.publishedAt && <span className="t-2xs dimmer">{new Date(post.publishedAt).toLocaleDateString('vi-VN')}</span>}
              </div>
            </button>
          );
        })}
      </div>
    </div>
  );
}

function PriceLine({ label, value, tone, small, strong }) {
  return (
    <div className="between">
      <span className={'t-' + (small ? '2xs dim' : 'xs') + (strong ? ' strong' : '')}>{label}</span>
      <span className={'mono ' + (small ? 't-2xs' : 't-sm') + (strong ? ' strong' : '')} style={tone ? { color: 'var(--' + tone + ')' } : {}}>{value}</span>
    </div>
  );
}

function ScoreBar({ label, value, max, color, note }) {
  const pct = max > 0 ? Math.min(100, Math.round((value / max) * 100)) : 0;
  return (
    <div style={{ marginBottom: 8 }}>
      <div className="between" style={{ marginBottom: 3 }}>
        <span className="t-2xs strong">{label}{note && <span className="dimmer" style={{ fontWeight: 400, marginLeft: 4 }}>· {note}</span>}</span>
        <span className="t-2xs mono strong" style={{ color }}>+{value}<span className="dimmer" style={{ fontWeight: 400 }}>/{max}</span></span>
      </div>
      <div style={{ height: 5, background: 'var(--bg-2)', borderRadius: 3, overflow: 'hidden' }}>
        <div style={{ width: pct + '%', height: '100%', background: color, transition: 'width .25s' }}></div>
      </div>
    </div>
  );
}

function InfoRow({ label, value, mono }) {
  return (
    <div className="between" style={{ padding: '8px 0', borderBottom: '1px solid var(--border)', gap: 16, alignItems: 'flex-start' }}>
      <span className="t-sm dimmer" style={{ minWidth: 120 }}>{label}</span>
      <span className={'t-sm strong ' + (mono ? 'mono' : '')} style={{ textAlign: 'right', wordBreak: 'break-word' }}>{value}</span>
    </div>
  );
}

Object.assign(window, { ProductsScreen });
