// Products — list + edit/create/delete via WooCommerce REST.
//
// Stock sync: pulls SuperFaktúra stock_items (cached 5 min), shows "Sklad SF"
// column with delta vs WC, and offers "⇄ Sync do WC" + "🔍 Porovnať SKU".
// Bulk delete uses a custom ConfirmModal (no browser confirm()).

// ── Custom confirm modal — replaces the ugly browser confirm()/alert() boxes ──
// Variants: 'danger' (red header, used for delete), 'info' (blue), 'warn' (amber).
function ConfirmModal({
  title,
  intro,
  details,
  children,
  confirmLabel = 'Potvrdiť',
  cancelLabel = 'Zrušiť',
  variant = 'info',
  busy = false,
  onCancel,
  onConfirm,
  width = 520,
}) {
  const palette = {
    danger: { accent:'var(--red-500, #dc2626)', bg:'#fef2f2', icon:'⚠️' },
    warn:   { accent:'var(--amber-500, #d97706)', bg:'#fffbeb', icon:'⚠️' },
    info:   { accent:'var(--navy-800, #0e2744)', bg:'#eff6ff', icon:'ℹ️' },
    success:{ accent:'var(--green-500, #059669)', bg:'#ecfdf5', icon:'✓' },
  }[variant] || { accent:'var(--navy-800)', bg:'#eff6ff', icon:'ℹ️' };

  return (
    <Modal
      title={title}
      onClose={busy ? () => {} : onCancel}
      width={width}
      footer={(
        <>
          <button className="btn" onClick={onCancel} disabled={busy}>{cancelLabel}</button>
          <button
            className="btn"
            style={{
              background: palette.accent, color:'#fff', borderColor: palette.accent,
              opacity: busy ? 0.6 : 1, minWidth: 140,
            }}
            disabled={busy}
            onClick={onConfirm}
          >
            {busy ? 'Pracujem…' : confirmLabel}
          </button>
        </>
      )}
    >
      <div style={{display:'flex', gap:14, alignItems:'flex-start'}}>
        <div style={{
          width:42, height:42, flex:'0 0 42px', borderRadius:'50%',
          background: palette.bg, color: palette.accent,
          display:'grid', placeItems:'center', fontSize:20, fontWeight:700,
        }}>{palette.icon}</div>
        <div style={{flex:1, minWidth:0}}>
          {intro && <div style={{fontSize:14, lineHeight:1.5, marginBottom: details || children ? 12 : 0}}>{intro}</div>}
          {details && (
            <div style={{
              background:'var(--ink-50, #f8fafc)', border:'1px solid var(--border)',
              borderRadius:8, padding:'10px 12px', fontSize:12.5, lineHeight:1.7,
            }}>{details}</div>
          )}
          {children}
        </div>
      </div>
    </Modal>
  );
}

function ProductThumb({ src, kind }) {
  if (src) {
    return <img src={src} alt="" style={{width:40, height:40, objectFit:'cover', borderRadius:6, border:'1px solid var(--border)'}}/>;
  }
  const bgs = {
    panel:    'repeating-linear-gradient(135deg, #1a3f6b 0 8px, #3a6da0 8px 16px)',
    inverter: 'linear-gradient(180deg, #cbd5e1, #94a3b8)',
    battery:  'linear-gradient(135deg, #0b1a2e, #23507f)',
    default:  'linear-gradient(135deg, #cbd5e1, #94a3b8)',
  };
  return <div style={{width:40, height:40, borderRadius:6, background:bgs[kind] || bgs.default}}/>;
}

function ProductEditModal({ productId = null, cats = [], onClose, onSaved, onCatsChanged, notify }) {
  const isNew = !productId;
  const [form, setForm] = React.useState(null);
  const [loading, setLoading] = React.useState(!isNew);
  const [busy, setBusy] = React.useState(null);
  const [catFilter, setCatFilter] = React.useState('');
  const [showNewCat, setShowNewCat] = React.useState(false);
  const [newCatName, setNewCatName] = React.useState('');
  const [newCatParent, setNewCatParent] = React.useState('');
  const [uploading, setUploading] = React.useState(false);
  const fileInputRef = React.useRef(null);

  React.useEffect(() => {
    if (isNew) {
      setForm({
        name: '', sku: '', status: 'publish',
        regular_price: '', sale_price: '',
        stock_status: 'instock', manage_stock: false, stock_quantity: '',
        short_description: '', description: '',
        voc_cena: '', nakupna_cena: '', min_quantity: '',
        pallet_quantity: '', pallet_price: '',
        category_ids: [],
        images: [],
      });
      return;
    }
    (async () => {
      setLoading(true);
      const r = await API.getProduct(productId);
      setLoading(false);
      if (r.ok) {
        const p = r.body.product;
        setForm({
          name: p.name || '',
          sku: p.sku || '',
          status: p.status || 'publish',
          regular_price: p.regular_price || '',
          sale_price: p.sale_price || '',
          stock_status: p.stock_status || 'instock',
          manage_stock: !!p.manage_stock,
          stock_quantity: p.stock_quantity == null ? '' : String(p.stock_quantity),
          short_description: p.short_description || '',
          description: p.description || '',
          voc_cena: p.voc_cena || '',
          nakupna_cena: p.nakupna_cena || '',
          min_quantity: p.min_quantity || '',
          pallet_quantity: p.pallet_quantity || '',
          pallet_price: p.pallet_price || '',
          category_ids: (p.categories || []).map(c => typeof c === 'object' ? c.id : null).filter(Boolean),
          images: (p.images || []).map(i => ({ id: i.id, src: i.src, alt: i.alt || '', name: i.name || '' })),
          permalink: p.permalink || '',
        });
      } else {
        notify('error', 'Nepodarilo sa načítať produkt.');
        onClose();
      }
    })();
    // eslint-disable-next-line
  }, [productId]);

  function set(k, v) { setForm(prev => ({ ...prev, [k]: v })); }

  function toggleCat(id) {
    const cur = form.category_ids || [];
    set('category_ids', cur.includes(id) ? cur.filter(x => x !== id) : [...cur, id]);
  }

  async function createCategory() {
    if (!newCatName.trim()) return;
    setBusy('cat');
    const r = await API.createProductCategory({
      name: newCatName.trim(),
      parent: newCatParent ? parseInt(newCatParent, 10) : 0,
    });
    setBusy(null);
    if (r.ok || r.status === 201) {
      const cat = r.body.category;
      onCatsChanged && onCatsChanged(cat);
      // auto-select the new one
      set('category_ids', [...(form.category_ids || []), cat.id]);
      setNewCatName('');
      setNewCatParent('');
      setShowNewCat(false);
      notify('success', 'Kategória vytvorená.');
    } else {
      notify('error', r.body.message || 'Nepodarilo sa vytvoriť kategóriu.');
    }
  }

  async function onFilesPicked(files) {
    if (!files || !files.length) return;
    setUploading(true);
    const newImages = [];
    for (const f of files) {
      const r = await API.uploadMedia(f);
      if (r.ok && r.body.ok) {
        newImages.push({ id: r.body.id, src: r.body.url, alt: '', name: f.name });
      } else {
        notify('error', `Upload ${f.name} zlyhal: ` + (r.body.message || r.body.error));
      }
    }
    setUploading(false);
    if (newImages.length) set('images', [...(form.images || []), ...newImages]);
    if (fileInputRef.current) fileInputRef.current.value = '';
  }

  function removeImage(idx) {
    const arr = [...(form.images || [])];
    arr.splice(idx, 1);
    set('images', arr);
  }

  function moveImage(idx, dir) {
    const arr = [...(form.images || [])];
    const target = idx + dir;
    if (target < 0 || target >= arr.length) return;
    [arr[idx], arr[target]] = [arr[target], arr[idx]];
    set('images', arr);
  }

  async function save() {
    setBusy('save');
    const payload = { ...form };
    if (payload.stock_quantity === '') payload.stock_quantity = null;
    const r = isNew ? await API.createProduct(payload) : await API.updateProduct(productId, payload);
    setBusy(null);
    if (r.ok || r.status === 201) {
      notify('success', isNew ? 'Produkt vytvorený.' : 'Uložené.');
      onSaved();
      onClose();
    } else {
      notify('error', r.body.message || r.body.error || 'Nepodarilo sa uložiť.');
    }
  }

  if (loading || !form) {
    return (
      <Modal title={isNew ? 'Nový produkt' : 'Upraviť produkt'} width={820} onClose={onClose}>
        <div className="muted" style={{padding:10}}>Načítavam…</div>
      </Modal>
    );
  }

  const filteredCats = cats.filter(c => !catFilter || c.name.toLowerCase().includes(catFilter.toLowerCase()));

  return (
    <Modal
      title={isNew ? 'Nový produkt' : `Upraviť produkt #${productId}`}
      width={860}
      onClose={onClose}
      footer={
        <>
          {!isNew && form.permalink && (
            <a className="btn" href={form.permalink} target="_blank" rel="noopener noreferrer"
              title="Otvoriť na e-shope v novom okne" style={{marginRight:'auto'}}>
              ↗ Náhľad na webe
            </a>
          )}
          <button className="btn" onClick={onClose} disabled={!!busy}>Zrušiť</button>
          <button className="btn btn-primary" onClick={save} disabled={!!busy || !form.name}>
            {busy === 'save' ? 'Ukladám…' : (isNew ? 'Vytvoriť' : 'Uložiť')}
          </button>
        </>
      }
    >
      <div style={{display:'grid', gridTemplateColumns:'1.4fr 1fr', gap:18}}>
        {/* ── Left column ───────────────────────────── */}
        <div className="vstack" style={{gap:12}}>
          <div className="field">
            <label>Názov produktu *</label>
            <input className="input" value={form.name} onChange={e => set('name', e.target.value)} autoFocus/>
          </div>

          <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:10}}>
            <div className="field">
              <label>SKU</label>
              <input className="input mono" value={form.sku} onChange={e => set('sku', e.target.value)}/>
            </div>
            <div className="field">
              <label>Stav</label>
              <select className="select" value={form.status} onChange={e => set('status', e.target.value)}>
                <option value="publish">Publikovaný</option>
                <option value="draft">Koncept</option>
                <option value="pending">Čaká na schválenie</option>
                <option value="private">Súkromný</option>
              </select>
            </div>
          </div>

          <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:10}}>
            <div className="field">
              <label>Bežná cena (€)</label>
              <input className="input" value={form.regular_price} onChange={e => set('regular_price', e.target.value)} placeholder="0.00" inputMode="decimal"/>
            </div>
            <div className="field">
              <label>Zľavnená cena (€)</label>
              <input className="input" value={form.sale_price} onChange={e => set('sale_price', e.target.value)} placeholder="—" inputMode="decimal"/>
            </div>
          </div>

          <div className="field">
            <label>Krátky popis</label>
            <textarea className="textarea" value={form.short_description} onChange={e => set('short_description', e.target.value)} rows={3} placeholder="Jeden-dva riadky zhrnutia pre vyhľadávanie a kartu produktu."/>
          </div>

          <div className="field">
            <label>Dlhý popis</label>
            <textarea className="textarea" value={form.description} onChange={e => set('description', e.target.value)} rows={8} placeholder="Plný HTML popis. Akceptuje <p>, <ul>, <strong>…"/>
            <div className="small muted" style={{marginTop:2}}>Môžete vkladať HTML (napr. <code>&lt;p&gt;</code>, <code>&lt;ul&gt;</code>). Pre vizuálny editor použite WordPress admin.</div>
          </div>

          {/* Obrázky */}
          <div className="card" style={{padding:12}}>
            <div className="hstack" style={{marginBottom:8}}>
              <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600, flex:1}}>Obrázky</div>
              <button
                type="button"
                className="btn btn-sm"
                onClick={() => fileInputRef.current && fileInputRef.current.click()}
                disabled={uploading}
              >
                {uploading ? 'Nahrávam…' : <><Ico.upload/>Pridať obrázok</>}
              </button>
              <input
                ref={fileInputRef}
                type="file"
                accept="image/jpeg,image/png,image/webp,image/gif"
                multiple
                style={{display:'none'}}
                onChange={e => onFilesPicked(Array.from(e.target.files || []))}
              />
            </div>
            {(form.images || []).length === 0 ? (
              <div className="small muted" style={{padding:'14px', textAlign:'center', border:'1px dashed var(--border-strong)', borderRadius:8}}>
                Žiadne obrázky. Prvý nahratý obrázok bude hlavný (náhľad).
              </div>
            ) : (
              <div style={{display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(90px, 1fr))', gap:8}}>
                {form.images.map((img, i) => (
                  <div key={img.id || img.src || i} style={{position:'relative', border:'1px solid var(--border)', borderRadius:8, overflow:'hidden', background:'#fff'}}>
                    <img src={img.src} alt={img.alt || ''} style={{width:'100%', height:90, objectFit:'cover', display:'block'}}/>
                    {i === 0 && <span className="chip amber" style={{position:'absolute', top:4, left:4, fontSize:9, padding:'1px 5px'}}>HLAVNÝ</span>}
                    <div style={{position:'absolute', top:4, right:4, display:'flex', gap:2}}>
                      {i > 0 && <button type="button" className="btn btn-xs" style={{padding:'0 4px', height:18, minWidth:18}} onClick={() => moveImage(i, -1)} title="Posunúť vľavo">←</button>}
                      {i < form.images.length - 1 && <button type="button" className="btn btn-xs" style={{padding:'0 4px', height:18, minWidth:18}} onClick={() => moveImage(i, 1)} title="Posunúť vpravo">→</button>}
                      <button type="button" className="btn btn-xs btn-danger" style={{padding:'0 4px', height:18, minWidth:18}} onClick={() => removeImage(i)} title="Odstrániť">×</button>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>

        {/* ── Right column ────────────────────────── */}
        <div className="vstack" style={{gap:12}}>
          {/* Kategórie */}
          <div className="card" style={{padding:12}}>
            <div className="hstack" style={{marginBottom:8}}>
              <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600, flex:1}}>Kategórie</div>
              <button type="button" className="btn btn-xs" onClick={() => setShowNewCat(v => !v)}>
                {showNewCat ? 'Zrušiť' : <><Ico.plus/>Nová</>}
              </button>
            </div>
            {showNewCat && (
              <div className="card" style={{padding:8, marginBottom:8, background:'var(--blue-50)'}}>
                <div className="field">
                  <label>Názov novej kategórie</label>
                  <input className="input" value={newCatName} onChange={e => setNewCatName(e.target.value)} autoFocus/>
                </div>
                <div className="field" style={{marginTop:6}}>
                  <label>Rodič</label>
                  <select className="select" value={newCatParent} onChange={e => setNewCatParent(e.target.value)}>
                    <option value="">— Bez rodiča —</option>
                    {cats.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
                  </select>
                </div>
                <button type="button" className="btn btn-sm btn-primary btn-block" style={{marginTop:8}} onClick={createCategory} disabled={busy === 'cat' || !newCatName.trim()}>
                  {busy === 'cat' ? 'Vytváram…' : 'Vytvoriť kategóriu'}
                </button>
              </div>
            )}
            <div className="field">
              <input className="input" placeholder="Filtrovať…" value={catFilter} onChange={e => setCatFilter(e.target.value)}/>
            </div>
            <div style={{maxHeight:200, overflow:'auto', border:'1px solid var(--border)', borderRadius:6, marginTop:6, padding:6, background:'#fff'}}>
              {filteredCats.length === 0 && <div className="small muted" style={{padding:10}}>Žiadne kategórie.</div>}
              {filteredCats.map(c => (
                <label key={c.id} className="checkbox" style={{display:'flex', padding:'3px 4px', borderRadius:4, cursor:'pointer'}}>
                  <input type="checkbox" checked={(form.category_ids || []).includes(c.id)} onChange={() => toggleCat(c.id)}/>
                  <span style={{flex:1}}>{c.name}</span>
                  <span className="small muted">({c.count})</span>
                </label>
              ))}
            </div>
            {(form.category_ids || []).length > 0 && (
              <div className="small muted" style={{marginTop:6}}>Vybrané: <b>{form.category_ids.length}</b></div>
            )}
          </div>

          {/* Sklad */}
          <div className="card" style={{padding:12, background:'var(--blue-50)'}}>
            <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600}}>Sklad</div>
            <div className="field" style={{marginTop:6}}>
              <label className="checkbox">
                <input type="checkbox" checked={!!form.manage_stock} onChange={e => set('manage_stock', e.target.checked)}/>
                <span>Spravovať sklad (kusy)</span>
              </label>
            </div>
            {form.manage_stock && (
              <div className="field">
                <label>Kusy</label>
                <input className="input" value={form.stock_quantity} onChange={e => set('stock_quantity', e.target.value)} inputMode="numeric"/>
              </div>
            )}
            <div className="field">
              <label>Stav skladu</label>
              <select className="select" value={form.stock_status} onChange={e => set('stock_status', e.target.value)}>
                <option value="instock">Skladom</option>
                <option value="outofstock">Vypredané</option>
                <option value="onbackorder">Na objednávku</option>
              </select>
            </div>
          </div>

          {/* DD Energy polia */}
          <div className="card" style={{padding:12, background:'#fff8e4'}}>
            <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600}}>DD Energy polia</div>
            <div className="field" style={{marginTop:6}}>
              <label>VOC (B2B) cena</label>
              <input className="input" value={form.voc_cena} onChange={e => set('voc_cena', e.target.value)} inputMode="decimal"/>
            </div>
            <div className="field">
              <label>Nákupná cena</label>
              <input className="input" value={form.nakupna_cena} onChange={e => set('nakupna_cena', e.target.value)} inputMode="decimal"/>
            </div>
            <div className="field">
              <label>Min. množstvo</label>
              <input className="input" value={form.min_quantity} onChange={e => set('min_quantity', e.target.value)} inputMode="numeric"/>
            </div>
            <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:6}}>
              <div className="field">
                <label>Ks v palete</label>
                <input className="input" value={form.pallet_quantity} onChange={e => set('pallet_quantity', e.target.value)} inputMode="numeric"/>
              </div>
              <div className="field">
                <label>Cena palety</label>
                <input className="input" value={form.pallet_price} onChange={e => set('pallet_price', e.target.value)} inputMode="decimal"/>
              </div>
            </div>
          </div>
        </div>
      </div>
    </Modal>
  );
}

function Products() {
  const [data, setData] = React.useState(null);
  const [cats, setCats] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [search, setSearch] = React.useState('');
  const [category, setCategory] = React.useState('');
  const [stockFilter, setStockFilter] = React.useState('');
  const [page, setPage] = React.useState(1);
  const [editingId, setEditingId] = React.useState(null);   // number = edit, 'new' = create, null = closed
  const [aiWizard, setAiWizard] = React.useState(false);
  const [toast, setToast] = React.useState(null);
  const [busyId, setBusyId] = React.useState(null);

  // SuperFaktúra stock map (sku → { qty, available, unit_price, name, sf_id }); null if not connected.
  const [sfMap, setSfMap] = React.useState(null);
  const [sfAge, setSfAge] = React.useState(null);   // seconds since last fetch
  const [sfLoading, setSfLoading] = React.useState(false);

  // Bulk selection (set of WC product ids)
  const [selected, setSelected] = React.useState(() => new Set());

  // Modal states — replaces browser confirm()/alert()
  const [confirmDelete, setConfirmDelete] = React.useState(null);  // { ids: number[], items: [{id,name,sku}] }
  const [deleteForce, setDeleteForce]     = React.useState(false); // trash vs. permanent
  const [deleteBusy, setDeleteBusy]       = React.useState(false);
  const [syncPreview, setSyncPreview]     = React.useState(null);  // backend response
  const [syncBusy, setSyncBusy]           = React.useState(false);
  const [syncResult, setSyncResult]       = React.useState(null);
  const [skuCompare, setSkuCompare]       = React.useState(null);  // null | 'loading' | response

  // If we land on /#/products?id=123 (e.g. from AI "otvor produkt ..."),
  // open the editor immediately — don't wait for the product list to finish loading.
  React.useEffect(() => {
    const readId = () => {
      const q = window.location.hash.split('?')[1] || '';
      const id = new URLSearchParams(q).get('id');
      if (id && /^\d+$/.test(id)) setEditingId(Number(id));
    };
    readId();
    window.addEventListener('hashchange', readId);
    return () => window.removeEventListener('hashchange', readId);
  }, []);
  // When the editor closes, strip ?id= so a stale param doesn't re-open it.
  React.useEffect(() => {
    if (editingId === null) {
      const hash = window.location.hash;
      if (hash.startsWith('#/products?') && hash.includes('id=')) {
        history.replaceState(null, '', '#/products');
      }
    }
  }, [editingId]);

  const canEdit = window.hasPerm ? window.hasPerm('products.edit') : false;
  const canCreate = window.hasPerm ? window.hasPerm('products.create') : false;
  const canDelete = window.hasPerm ? window.hasPerm('products.delete') : false;

  async function reload() {
    setLoading(true);
    const r = await API.listProducts({
      search, category, stock_status: stockFilter, page, per_page: 25,
    });
    setLoading(false);
    if (r.status === 503 && r.body.error === 'woocommerce_not_configured') { setError('not_configured'); return; }
    if (!r.ok) { setError(r.body.message || 'Chyba.'); return; }
    setError(null);
    setData(r.body);
  }

  React.useEffect(() => {
    (async () => {
      const r = await API.listProductCategories();
      if (r.ok) setCats(r.body.categories || []);
    })();
    // Pull SuperFaktúra stock map once on mount (cached 5 min on backend).
    // Silently skip if not configured (503).
    loadSfMap(false);
  }, []);

  // Reset selection when the visible page/filter changes — otherwise checkboxes
  // referenced rows that are no longer on screen.
  React.useEffect(() => { setSelected(new Set()); }, [page, category, stockFilter, search]);

  async function loadSfMap(force) {
    setSfLoading(true);
    const r = await API.sfStockMap(force);
    setSfLoading(false);
    if (r.status === 503) { setSfMap(null); return; }
    if (r.ok && r.body.ok) {
      // Backend already normalized keys (lowercase, _ → -). Use them as-is.
      setSfMap(r.body.map || {});
      setSfAge(r.body.age_sec);
    }
  }

  // Normalize SKU for tolerant lookup (matches backend skuKey()).
  function skuKey(s) { return String(s || '').trim().toLowerCase().replace(/_/g, '-'); }

  // Open sync dialog — pulls preview, then ConfirmModal shows the diff.
  async function openSyncDialog() {
    setSyncBusy(true);
    const prev = await API.sfSyncPreview();
    setSyncBusy(false);
    if (!prev.ok || !prev.body.ok) {
      setToast({ kind: 'error', text: prev.body?.message || 'Preview SuperFaktúry zlyhal.' });
      return;
    }
    setSyncPreview(prev.body);
  }

  async function runSync() {
    setSyncBusy(true);
    const r = await API.sfSyncRun(false);
    setSyncBusy(false);
    if (!r.ok || !r.body.ok) {
      setSyncPreview(null);
      setToast({ kind: 'error', text: r.body?.message || 'Sync zlyhal.' });
      return;
    }
    setSyncPreview(null);
    setSyncResult(r.body);
    await Promise.all([reload(), loadSfMap(true)]);
  }

  // Open SKU compare modal — async load (can take a few seconds for large catalogs).
  async function openSkuCompare() {
    setSkuCompare('loading');
    const r = await API.sfSkuCompare();
    if (!r.ok || !r.body.ok) {
      setSkuCompare(null);
      setToast({ kind: 'error', text: r.body?.message || 'Porovnanie SKU zlyhalo.' });
      return;
    }
    setSkuCompare(r.body);
  }

  // Selection helpers
  function toggleOne(id) {
    setSelected(prev => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id); else next.add(id);
      return next;
    });
  }
  function toggleAllOnPage() {
    setSelected(prev => {
      const next = new Set(prev);
      const onPage = (data?.products || []).map(p => p.id);
      const allSelected = onPage.every(id => next.has(id));
      if (allSelected) onPage.forEach(id => next.delete(id));
      else             onPage.forEach(id => next.add(id));
      return next;
    });
  }
  function clearSelection() { setSelected(new Set()); }

  React.useEffect(() => { reload(); /* eslint-disable-next-line */ }, [category, stockFilter, page]);

  React.useEffect(() => {
    const id = setTimeout(() => { setPage(1); reload(); }, 350);
    return () => clearTimeout(id);
    // eslint-disable-next-line
  }, [search]);

  // Open the delete confirm modal — for a single product or for current selection.
  function askDeleteOne(p) {
    setDeleteForce(false);
    setConfirmDelete({
      ids: [p.id],
      items: [{ id: p.id, name: p.name, sku: p.sku }],
    });
  }
  function askDeleteSelected() {
    const products = data?.products || [];
    const items = products
      .filter(p => selected.has(p.id))
      .map(p => ({ id: p.id, name: p.name, sku: p.sku }));
    if (items.length === 0) return;
    setDeleteForce(false);
    setConfirmDelete({ ids: items.map(i => i.id), items });
  }

  async function runDelete() {
    if (!confirmDelete) return;
    const { ids } = confirmDelete;
    setDeleteBusy(true);
    let response;
    if (ids.length === 1) {
      setBusyId(ids[0]);
      const r = await API.deleteProduct(ids[0], deleteForce);
      setBusyId(null);
      response = { ok: r.ok, summary: { deleted: r.ok ? 1 : 0, failed: r.ok ? 0 : 1, total: 1 }, error: !r.ok ? (r.body?.message || r.body?.error) : null };
    } else {
      const r = await API.bulkDeleteProducts(ids, deleteForce);
      response = { ok: r.ok && r.body.ok, summary: r.body?.summary || {}, results: r.body?.results || [], error: !r.ok ? (r.body?.message) : null };
    }
    setDeleteBusy(false);
    setConfirmDelete(null);

    if (response.ok) {
      const s = response.summary || {};
      const okN = s.deleted ?? 1;
      const failN = s.failed ?? 0;
      setToast({
        kind: failN > 0 ? 'error' : 'success',
        text: failN > 0
          ? `Zmazaných ${okN}, zlyhalo ${failN}.`
          : (okN === 1 ? (deleteForce ? 'Produkt trvalo zmazaný.' : 'Produkt v koši.')
                       : (deleteForce ? `${okN} produktov trvalo zmazaných.` : `${okN} produktov presunutých do koša.`)),
      });
      clearSelection();
      reload();
    } else {
      setToast({ kind: 'error', text: 'Nepodarilo sa zmazať: ' + (response.error || 'neznáma chyba') });
    }
  }

  if (error === 'not_configured') {
    return (
      <AppShell active="products" crumbs={['ERP','Produkty']}>
        <div className="page-head"><div><h1>Produkty</h1></div></div>
        <NotConnected/>
      </AppShell>
    );
  }

  const products = data?.products || [];
  const total = data?.total || 0;
  const totalPages = data?.totalPages || 1;

  return (
    <AppShell active="products" crumbs={['ERP','Produkty']}>
      {toast && <Toast kind={toast.kind} onClose={() => setToast(null)}>{toast.text}</Toast>}
      {editingId !== null && (
        <ProductEditModal
          productId={editingId === 'new' ? null : editingId}
          cats={cats}
          onClose={() => setEditingId(null)}
          onSaved={reload}
          onCatsChanged={(newCat) => setCats(prev => [...prev, newCat].sort((a,b) => a.name.localeCompare(b.name)))}
          notify={(kind, text) => setToast({ kind, text })}
        />
      )}

      <div className="page-head">
        <div>
          <h1>Produkty</h1>
          <p>{total} produktov · WooCommerce sync</p>
        </div>
        <div className="page-head-actions">
          <button className="btn" onClick={reload}><Ico.refresh/>Obnoviť</button>
          {sfMap !== null && (
            <>
              <button className="btn" onClick={() => loadSfMap(true)} disabled={sfLoading}
                title={sfAge != null ? `SuperFaktúra dáta · pred ${sfAge}s. Kliknite pre nový pull.` : 'Načítať aktuálny stav zo SuperFaktúry'}>
                {sfLoading ? '⏳ SF…' : '📊 Sklad SF' + (sfAge != null ? ` (${sfAge < 60 ? sfAge + 's' : Math.round(sfAge/60) + 'm'})` : '')}
              </button>
              {canEdit && (
                <button className="btn" onClick={openSyncDialog} disabled={sfLoading || syncBusy}
                  title="Aktualizuje WC stock_quantity podľa SuperFaktúry pre všetky matching SKU">
                  ⇄ Sync do WC
                </button>
              )}
              <button className="btn" onClick={openSkuCompare} disabled={skuCompare === 'loading'}
                title="Porovnaj SKU na webe so SKU v SuperFaktúre">
                🔍 Porovnať SKU
              </button>
            </>
          )}
          {canCreate && (
            <button className="btn" onClick={() => setAiWizard(true)} title="Vytvor produkt s AI z datasheetu alebo briefu">
              ✨ AI generátor
            </button>
          )}
          {canCreate && <button className="btn btn-primary" onClick={() => setEditingId('new')}><Ico.plus/>Nový produkt</button>}
        </div>
      </div>

      {/* Selection bar — visible when 1+ products checked */}
      {selected.size > 0 && (
        <div style={{
          display:'flex', alignItems:'center', gap:10, padding:'10px 14px',
          background:'var(--navy-50, #eff6ff)', border:'1px solid var(--navy-200, #bfdbfe)',
          borderRadius:8, marginBottom:10, fontSize:13,
        }}>
          <Ico.check/>
          <b>Vybrané: {selected.size}</b>
          <span className="muted" style={{marginLeft:6}}>
            {(data?.products || []).filter(p => selected.has(p.id)).slice(0, 3).map(p => p.sku || p.name).join(', ')}
            {selected.size > 3 ? `, +${selected.size - 3}` : ''}
          </span>
          <div style={{marginLeft:'auto', display:'flex', gap:6}}>
            <button className="btn btn-xs" onClick={clearSelection}>Zrušiť výber</button>
            {canDelete && (
              <button className="btn btn-xs btn-danger" onClick={askDeleteSelected}>
                🗑 Zmazať {selected.size} produktov
              </button>
            )}
          </div>
        </div>
      )}
      {aiWizard && (
        <AIProductWizard
          onClose={() => setAiWizard(false)}
          onCreated={() => reload()}
          notify={(kind, text) => setToast({ kind, text })}
        />
      )}

      <div className="filters">
        <div style={{position:'relative', flex:1, maxWidth:300}}>
          <Ico.search style={{position:'absolute', left:10, top:9, color:'var(--ink-400)'}}/>
          <input className="input" placeholder="SKU, názov…" style={{paddingLeft:30, width:'100%'}} value={search} onChange={e => setSearch(e.target.value)}/>
        </div>
        <select className="select" value={category} onChange={e => { setCategory(e.target.value); setPage(1); }}>
          <option value="">Všetky kategórie</option>
          {cats.map(c => <option key={c.id} value={c.id}>{c.name} ({c.count})</option>)}
        </select>
        <select className="select" value={stockFilter} onChange={e => { setStockFilter(e.target.value); setPage(1); }}>
          <option value="">Všetky sklady</option>
          <option value="instock">Skladom</option>
          <option value="outofstock">Vypredané</option>
          <option value="onbackorder">Na objednávku</option>
        </select>
      </div>

      <div className="card" style={{overflow:'hidden'}}>
        {loading && <div style={{padding:20}} className="muted">Načítavam…</div>}
        {!loading && (
          <div style={{overflow:'auto'}}>
            <table className="tbl">
              <thead><tr>
                {canDelete && (
                  <th style={{width:36, textAlign:'center'}}>
                    <input
                      type="checkbox"
                      title="Označiť všetky na strane"
                      checked={products.length > 0 && products.every(p => selected.has(p.id))}
                      ref={el => {
                        if (!el) return;
                        const someOnPage = products.some(p => selected.has(p.id));
                        const allOnPage  = products.length > 0 && products.every(p => selected.has(p.id));
                        el.indeterminate = someOnPage && !allOnPage;
                      }}
                      onChange={toggleAllOnPage}
                    />
                  </th>
                )}
                <th></th><th>SKU</th><th>Názov</th><th>Kategória</th>
                <th style={{textAlign:'right'}}>Cena</th><th style={{textAlign:'right'}}>VOC (B2B)</th>
                <th style={{textAlign:'right'}}>Sklad WC</th>
                {sfMap && <th style={{textAlign:'right'}} title={sfAge != null ? `SF dáta · pred ${sfAge}s` : 'SuperFaktúra'}>Sklad SF</th>}
                <th>Stav</th>
                <th style={{textAlign:'right'}}>Akcie</th>
              </tr></thead>
              <tbody>
                {products.length === 0 && (
                  <tr><td colSpan={(canDelete ? 1 : 0) + (sfMap ? 10 : 9)} style={{textAlign:'center', padding:30, color:'var(--ink-500)'}}>Žiadne produkty.</td></tr>
                )}
                {products.map(p => {
                  const stockChip =
                    p.stock_status === 'instock' ? <span className="chip green dot">Skladom</span> :
                    p.stock_status === 'outofstock' ? <span className="chip red dot">Vypredané</span> :
                    <span className="chip amber dot">Na obj.</span>;
                  // SF stock lookup with tolerant SKU key (handles _ ↔ -)
                  const sf = (sfMap && p.sku) ? sfMap[skuKey(p.sku)] : null;
                  const wcQ = p.stock_quantity;
                  const sfQ = sf ? sf.available : null;
                  // Diff classification: synced / behind / ahead / unknown
                  let sfTone = 'muted', sfTitle = '';
                  if (sfQ != null && wcQ != null) {
                    if (sfQ === wcQ)         { sfTone = 'green';  sfTitle = 'WC zhoduje so SuperFaktúrou'; }
                    else if (sfQ > wcQ)      { sfTone = 'amber';  sfTitle = `SF má o ${sfQ - wcQ} ks viac — sync zdvihne WC sklad`; }
                    else                     { sfTone = 'red';    sfTitle = `SF má o ${wcQ - sfQ} ks menej — sync zníži WC sklad`; }
                  }
                  const isChecked = selected.has(p.id);
                  return (
                    <tr key={p.id} style={busyId === p.id ? { opacity: 0.5 } : (isChecked ? { background:'var(--navy-50, #eff6ff)' } : {})}>
                      {canDelete && (
                        <td style={{textAlign:'center'}}>
                          <input type="checkbox" checked={isChecked} onChange={() => toggleOne(p.id)}/>
                        </td>
                      )}
                      <td><ProductThumb src={p.image}/></td>
                      <td className="mono small">{p.sku || '—'}</td>
                      <td>
                        <div style={{fontWeight:500}}>{p.name}</div>
                        {p.min_quantity && p.min_quantity > 1 && <div className="small muted">min. {p.min_quantity} ks</div>}
                      </td>
                      <td className="small">{(p.categories || []).slice(0, 2).map(c => (c && c.name) || c).join(', ')}</td>
                      <td style={{textAlign:'right', fontWeight:600}}>{p.price ? formatCurrency(parseFloat(p.price)) : '—'}</td>
                      <td style={{textAlign:'right'}} className="small">{p.voc_cena ? formatCurrency(parseFloat(p.voc_cena)) : '—'}</td>
                      <td style={{textAlign:'right'}}>{p.stock_quantity != null ? p.stock_quantity + ' ks' : '—'}</td>
                      {sfMap && (
                        <td style={{textAlign:'right'}} className="small" title={sfTitle}>
                          {sfQ != null ? (
                            <span className={`chip ${sfTone} dot`} style={{minWidth:50, justifyContent:'flex-end'}}>
                              {sfQ} ks
                              {wcQ != null && sfQ !== wcQ && (
                                <span style={{marginLeft:4, opacity:0.8, fontWeight:400}}>
                                  ({sfQ > wcQ ? '+' : ''}{sfQ - wcQ})
                                </span>
                              )}
                            </span>
                          ) : (
                            <span className="muted" title="SKU nie je v SuperFaktúre">—</span>
                          )}
                        </td>
                      )}
                      <td>{stockChip}</td>
                      <td style={{textAlign:'right', whiteSpace:'nowrap'}}>
                        {p.permalink && (
                          <a className="btn btn-xs" href={p.permalink} target="_blank" rel="noopener noreferrer"
                            title={p.status === 'publish' ? 'Otvoriť produkt na e-shope' : 'Náhľad (' + p.status + ')'}
                            style={{marginRight:4}}>
                            ↗ Náhľad
                          </a>
                        )}
                        {canEdit && <button className="btn btn-xs" onClick={() => setEditingId(p.id)} title="Upraviť">Upraviť</button>}
                        {canDelete && <button className="btn btn-xs btn-danger" style={{marginLeft:4}} onClick={() => askDeleteOne(p)} disabled={busyId === p.id} title="Zmazať"><Ico.x/></button>}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
        {totalPages > 1 && (
          <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', padding:'10px 14px', borderTop:'1px solid var(--border)', fontSize:12}}>
            <span className="muted">Strana {page} z {totalPages} · {total} záznamov</span>
            <div className="hstack">
              <button className="btn btn-xs" disabled={page <= 1} onClick={() => setPage(p => Math.max(1, p - 1))}>← Prev</button>
              <button className="btn btn-xs" disabled={page >= totalPages} onClick={() => setPage(p => Math.min(totalPages, p + 1))}>Next →</button>
            </div>
          </div>
        )}
      </div>

      {/* ── Delete confirm modal ── */}
      {confirmDelete && (
        <ConfirmModal
          title={confirmDelete.ids.length === 1 ? 'Zmazať produkt?' : `Zmazať ${confirmDelete.ids.length} produktov?`}
          variant="danger"
          confirmLabel={
            confirmDelete.ids.length === 1
              ? (deleteForce ? 'Trvalo zmazať' : 'Presunúť do koša')
              : (deleteForce ? `Trvalo zmazať ${confirmDelete.ids.length}` : `Presunúť ${confirmDelete.ids.length} do koša`)
          }
          cancelLabel="Zrušiť"
          busy={deleteBusy}
          onCancel={() => { if (!deleteBusy) setConfirmDelete(null); }}
          onConfirm={runDelete}
          intro={
            confirmDelete.ids.length === 1
              ? <>Naozaj zmazať produkt <b>{confirmDelete.items[0]?.name}</b>?</>
              : <>Naozaj zmazať <b>{confirmDelete.ids.length}</b> produktov?</>
          }
          details={
            <div>
              <div style={{maxHeight:160, overflow:'auto'}}>
                {confirmDelete.items.slice(0, 12).map(it => (
                  <div key={it.id} style={{display:'flex', justifyContent:'space-between', gap:10, padding:'2px 0'}}>
                    <span className="mono small" style={{color:'var(--ink-500)', minWidth:160}}>{it.sku || '— bez SKU —'}</span>
                    <span style={{flex:1, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{it.name}</span>
                  </div>
                ))}
                {confirmDelete.items.length > 12 && (
                  <div className="muted small" style={{paddingTop:6}}>… a ďalších {confirmDelete.items.length - 12}</div>
                )}
              </div>
              <div style={{marginTop:10, paddingTop:10, borderTop:'1px solid var(--border)'}}>
                <label style={{display:'flex', alignItems:'center', gap:8, fontSize:13, cursor:'pointer'}}>
                  <input type="checkbox" checked={deleteForce} onChange={e => setDeleteForce(e.target.checked)} disabled={deleteBusy}/>
                  <span><b>Trvalo zmazať</b> <span className="muted">(bez koša — nedá sa obnoviť)</span></span>
                </label>
              </div>
            </div>
          }
        />
      )}

      {/* ── Sync preview confirm modal ── */}
      {syncPreview && (() => {
        const { summary, matches } = syncPreview;
        return (
          <ConfirmModal
            title="Synchronizovať sklad zo SuperFaktúry?"
            variant="info"
            confirmLabel={summary.will_update > 0 ? `Synchronizovať ${summary.will_update} produktov` : 'Nič na sync'}
            cancelLabel="Zrušiť"
            busy={syncBusy}
            width={620}
            onCancel={() => { if (!syncBusy) setSyncPreview(null); }}
            onConfirm={summary.will_update > 0 ? runSync : () => setSyncPreview(null)}
            intro={
              summary.will_update > 0
                ? <>SuperFaktúra obsahuje aktuálne stavy pre <b>{summary.sf_items}</b> položiek. Na WooCommerce sa prepíše <b>stock_quantity</b> + <b>stock_status</b> pre matching SKU.</>
                : <>Všetko je zosynchronizované — žiadne zmeny nie sú potrebné.</>
            }
            details={
              <div>
                <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:6, fontSize:13}}>
                  <div>📊 SF položiek:</div><div style={{textAlign:'right', fontWeight:600}}>{summary.sf_items}</div>
                  <div>🛒 WC produktov so SKU:</div><div style={{textAlign:'right', fontWeight:600}}>{summary.wc_products_with_sku}</div>
                  <div style={{color:'var(--navy-800)'}}>⇄ Bude aktualizovaných:</div><div style={{textAlign:'right', fontWeight:700, color:'var(--navy-800)'}}>{summary.will_update}</div>
                  <div>✓ Už zosync.:</div><div style={{textAlign:'right'}}>{summary.unchanged}</div>
                  <div className="muted">? Bez WC partnera (len v SF):</div><div style={{textAlign:'right'}} className="muted">{summary.unmatched_in_wc}</div>
                  <div className="muted">? SF položky bez SKU:</div><div style={{textAlign:'right'}} className="muted">{summary.sku_missing_in_sf}</div>
                </div>
                {matches && matches.length > 0 && (
                  <div style={{marginTop:12, paddingTop:10, borderTop:'1px solid var(--border)'}}>
                    <div className="small" style={{fontWeight:600, marginBottom:6}}>Príklady zmien:</div>
                    <div style={{maxHeight:200, overflow:'auto', fontSize:12.5, lineHeight:1.7}}>
                      {matches.slice(0, 12).map(m => (
                        <div key={m.wc_id} style={{display:'flex', justifyContent:'space-between', gap:10}}>
                          <span className="mono" style={{color:'var(--ink-500)', minWidth:200}}>{m.sku}</span>
                          <span style={{flex:1, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}}>{m.name}</span>
                          <span style={{whiteSpace:'nowrap', fontWeight:600}}>
                            {m.wc_old_qty ?? '—'} → <span style={{color:'var(--navy-800)'}}>{m.new_qty}</span> ks
                          </span>
                        </div>
                      ))}
                      {matches.length > 12 && <div className="muted small" style={{paddingTop:6}}>… a ďalších {matches.length - 12}</div>}
                    </div>
                  </div>
                )}
              </div>
            }
          />
        );
      })()}

      {/* ── Sync result modal ── */}
      {syncResult && (
        <ConfirmModal
          title="Synchronizácia hotová"
          variant={syncResult.summary.failed ? 'warn' : 'success'}
          confirmLabel="Zatvoriť"
          cancelLabel=""
          onCancel={() => setSyncResult(null)}
          onConfirm={() => setSyncResult(null)}
          intro={
            <>
              Aktualizovaných: <b>{syncResult.summary.updated}</b> produktov.
              {syncResult.summary.failed > 0 && <> Zlyhalo: <b style={{color:'var(--red-500)'}}>{syncResult.summary.failed}</b>.</>}
            </>
          }
          details={
            syncResult.failures && syncResult.failures.length > 0 ? (
              <div>
                <div className="small" style={{fontWeight:600, marginBottom:6}}>Zlyhania:</div>
                <div style={{maxHeight:200, overflow:'auto', fontSize:12, lineHeight:1.7}}>
                  {syncResult.failures.map(f => (
                    <div key={f.wc_id}><span className="mono">{f.sku}</span> — {f.error || `HTTP ${f.http}`}</div>
                  ))}
                </div>
              </div>
            ) : null
          }
        />
      )}

      {/* ── SKU compare modal ── */}
      {skuCompare === 'loading' && (
        <Modal title="Porovnávam SKU…" width={400} onClose={() => setSkuCompare(null)}
          footer={<button className="btn" onClick={() => setSkuCompare(null)}>Zavrieť</button>}>
          <div style={{padding:'20px 0', textAlign:'center'}}>
            <div className="spin" style={{fontSize:32, display:'inline-block'}}>⟳</div>
            <div className="muted" style={{marginTop:10}}>Načítavam dáta zo SuperFaktúry a WooCommerce…</div>
          </div>
          <style>{`@keyframes spin{to{transform:rotate(360deg)}} .spin{animation:spin 1.2s linear infinite}`}</style>
        </Modal>
      )}
      {skuCompare && skuCompare !== 'loading' && (
        <SkuCompareModal data={skuCompare} onClose={() => setSkuCompare(null)} onOpenProduct={(id) => { setSkuCompare(null); setEditingId(id); }}/>
      )}
    </AppShell>
  );
}

// ═════════════════════════════════════════════════════════════════════════════
// SkuCompareModal — three tabs (Iba na webe / Iba v SF / V oboch) for sanity-checking
// the SKU mapping between WooCommerce and SuperFaktúra. The "both" tab also surfaces
// quantity drift so the user can spot which SKUs need a sync run.
// ═════════════════════════════════════════════════════════════════════════════
function SkuCompareModal({ data: initialData, onClose, onOpenProduct }) {
  // Local copy so we can splice suggestions as the user applies them.
  const [data, setData]   = React.useState(initialData);
  const [tab, setTab]     = React.useState(
    (initialData?.summary?.suggestions || 0) > 0 ? 'suggestions' : 'only_web'
  );
  const [q, setQ]         = React.useState('');
  const [applyingId, setApplyingId] = React.useState(null);   // wc_id during PATCH
  const [applyToast, setApplyToast] = React.useState(null);   // {kind,text} inside modal
  const summary = data.summary || {};

  React.useEffect(() => {
    if (!applyToast) return;
    const id = setTimeout(() => setApplyToast(null), 4000);
    return () => clearTimeout(id);
  }, [applyToast]);

  const tabs = [
    { id: 'suggestions', label: '✨ Návrhy zhôd', count: summary.suggestions, tone: 'navy',  desc: 'Páry nájdené podľa podobnosti názvu — pre WC produkty bez SKU alebo s SKU ktoré v SF chýba. Kliknutím "Použiť SF SKU" zapíšeš SF SKU do WC produktu.' },
    { id: 'only_web',    label: 'Iba na webe',    count: summary.only_web,    tone: 'amber', desc: 'SKU je vo WooCommerce, ale v SuperFaktúre chýba — pridajte stock item v SF.' },
    { id: 'only_sf',     label: 'Iba v SF',       count: summary.only_sf,     tone: 'red',   desc: 'SKU je v SuperFaktúre, ale na webe žiadny produkt s týmto SKU nie je — pridajte produkt do WC alebo opravte SKU.' },
    { id: 'both',        label: 'V oboch',        count: summary.both,        tone: 'green', desc: `Spárované SKU. V sklade súhlasí ${summary.in_sync}, líši sa ${summary.qty_drift}.` },
  ];

  async function applySuggestion(s) {
    setApplyingId(s.wc_id);
    const r = await API.updateProduct(s.wc_id, { sku: s.sf_sku });
    setApplyingId(null);
    if (!r.ok) {
      setApplyToast({ kind: 'error', text: 'Nepodarilo sa nastaviť SKU: ' + (r.body?.message || r.body?.error || `HTTP ${r.status}`) });
      return;
    }
    // Optimistic update — remove this suggestion + decrement counters; also
    // remove the WC item from only_web (if present) and the SF item from only_sf.
    setData(prev => {
      const suggestions = (prev.suggestions || []).filter(x => x.wc_id !== s.wc_id);
      const only_web    = (prev.only_web    || []).filter(x => x.wc_id !== s.wc_id);
      const only_sf     = (prev.only_sf     || []).filter(x => x.sf_id !== s.sf_id);
      const wc_without_sku = (prev.wc_without_sku || []).filter(x => x.wc_id !== s.wc_id);
      const summary2 = {
        ...prev.summary,
        suggestions: suggestions.length,
        only_web:    only_web.length,
        only_sf:     only_sf.length,
      };
      return { ...prev, suggestions, only_web, only_sf, wc_without_sku, summary: summary2 };
    });
    setApplyToast({ kind: 'success', text: `SKU "${s.sf_sku}" nastavené na WC produkt.` });
  }

  const rows = (() => {
    const arr = data[tab] || [];
    if (!q.trim()) return arr;
    const needle = q.trim().toLowerCase();
    return arr.filter(r => {
      const hay = `${r.sku || ''} ${r.wc_sku || ''} ${r.sf_sku || ''} ${r.name || ''} ${r.name_wc || ''} ${r.name_sf || ''} ${r.wc_name || ''} ${r.sf_name || ''}`.toLowerCase();
      return hay.includes(needle);
    });
  })();

  function exportCsv() {
    const arr = data[tab] || [];
    let header, lines;
    if (tab === 'only_web') {
      header = ['SKU', 'Názov (WC)', 'Sklad WC', 'Cena WC', 'VOC'];
      lines = arr.map(r => [r.sku, r.name, r.wc_qty ?? '', r.wc_price ?? '', r.wc_voc ?? '']);
    } else if (tab === 'only_sf') {
      header = ['SKU', 'Názov (SF)', 'Sklad SF', 'Cena SF'];
      lines = arr.map(r => [r.sku, r.name, r.sf_qty ?? '', r.sf_unit_price ?? '']);
    } else if (tab === 'suggestions') {
      header = ['Zhoda %', 'WC ID', 'WC SKU (staré)', 'Názov (WC)', 'SF SKU (návrh)', 'Názov (SF)', 'Sklad SF'];
      lines = arr.map(r => [r.similarity, r.wc_id, r.wc_sku ?? '', r.wc_name, r.sf_sku, r.sf_name, r.sf_qty ?? '']);
    } else {
      header = ['SKU', 'Názov (WC)', 'Sklad WC', 'Sklad SF', 'Rozdiel', 'Cena WC', 'VOC', 'Cena SF', 'V sync?'];
      lines = arr.map(r => [r.sku, r.name_wc, r.wc_qty ?? '', r.sf_qty ?? '', r.qty_diff ?? '', r.wc_price ?? '', r.wc_voc ?? '', r.sf_unit_price ?? '', r.in_sync ? 'áno' : 'nie']);
    }
    const csv = [header, ...lines].map(row => row.map(v => {
      const s = String(v == null ? '' : v);
      return /[",;\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
    }).join(';')).join('\n');
    const blob = new Blob(['﻿' + csv], { type: 'text/csv;charset=utf-8' });
    const url  = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = `sku-compare-${tab}-${new Date().toISOString().slice(0,10)}.csv`;
    document.body.appendChild(a); a.click(); a.remove();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
  }

  return (
    <Modal
      title="Porovnanie SKU: Web vs SuperFaktúra"
      width={900}
      onClose={onClose}
      footer={(
        <>
          <button className="btn" onClick={exportCsv} title="Stiahnuť aktuálnu kartu ako CSV">⬇ Export CSV</button>
          <button className="btn" onClick={onClose}>Zavrieť</button>
        </>
      )}
    >
      {/* Summary strip */}
      <div style={{display:'grid', gridTemplateColumns:'repeat(4, 1fr)', gap:8, marginBottom:14}}>
        <SkuStat label="WC produktov" value={summary.wc_with_sku} sub={`${summary.wc_total} celkom`}/>
        <SkuStat label="SF položiek" value={summary.sf_with_sku} sub={`${summary.sf_total} celkom`}/>
        <SkuStat label="Spárovaných" value={summary.both} sub={`${summary.in_sync} v sync, ${summary.qty_drift} drift`} tone="green"/>
        <SkuStat label="Bez páru" value={(summary.only_web || 0) + (summary.only_sf || 0)} sub={`${summary.only_web} web · ${summary.only_sf} SF`} tone="amber"/>
      </div>

      {/* Tabs */}
      <div style={{display:'flex', gap:6, marginBottom:10, borderBottom:'1px solid var(--border)'}}>
        {tabs.map(t => (
          <button
            key={t.id}
            className="btn btn-sm"
            onClick={() => setTab(t.id)}
            style={{
              borderRadius:'8px 8px 0 0',
              background: tab === t.id ? 'var(--navy-800)' : 'transparent',
              color:      tab === t.id ? '#fff' : 'var(--ink-900)',
              borderColor: tab === t.id ? 'var(--navy-800)' : 'transparent',
              borderBottomColor: tab === t.id ? 'var(--navy-800)' : 'transparent',
              fontWeight: tab === t.id ? 600 : 400,
              marginBottom: -1,
            }}
          >
            {t.label} <span style={{
              marginLeft:6, fontSize:11, padding:'1px 6px', borderRadius:10,
              background: tab === t.id ? 'rgba(255,255,255,0.2)' : `var(--${t.tone}-100, #f3f4f6)`,
              color: tab === t.id ? '#fff' : `var(--${t.tone}-700, #374151)`,
            }}>{t.count || 0}</span>
          </button>
        ))}
      </div>

      <div className="muted small" style={{marginBottom:10}}>
        {tabs.find(t => t.id === tab)?.desc}
      </div>

      <div style={{marginBottom:10}}>
        <input
          className="input"
          placeholder="🔍 Filter podľa SKU alebo názvu…"
          value={q}
          onChange={e => setQ(e.target.value)}
          style={{width:'100%'}}
        />
      </div>

      {/* In-modal toast for SKU apply feedback */}
      {applyToast && (
        <div style={{
          marginBottom:10, padding:'8px 12px', borderRadius:6, fontSize:13, fontWeight:500,
          background: applyToast.kind === 'error' ? 'var(--red-50, #fef2f2)'   : 'var(--green-50, #ecfdf5)',
          color:      applyToast.kind === 'error' ? 'var(--red-700, #b91c1c)'  : 'var(--green-700, #047857)',
          border: '1px solid ' + (applyToast.kind === 'error' ? 'var(--red-200, #fecaca)' : 'var(--green-200, #a7f3d0)'),
        }}>
          {applyToast.kind === 'error' ? '✕ ' : '✓ '}{applyToast.text}
        </div>
      )}

      <div style={{maxHeight:380, overflow:'auto', border:'1px solid var(--border)', borderRadius:8}}>
        {rows.length === 0 ? (
          <div style={{padding:30, textAlign:'center', color:'var(--ink-500)'}}>
            {q ? 'Žiadny výsledok pre tento filter.' : (tab === 'suggestions' ? 'Žiadne návrhy nad prahom podobnosti 35 %.' : 'Nič tu nie je — všetko je OK.')}
          </div>
        ) : tab === 'suggestions' ? (
          <div style={{display:'flex', flexDirection:'column', gap:8, padding:8}}>
            {rows.map(s => {
              const tone = s.similarity >= 70 ? '#047857' : s.similarity >= 50 ? '#b45309' : '#6b7280';
              const isApplying = applyingId === s.wc_id;
              return (
                <div key={s.wc_id} style={{
                  border:'1px solid var(--border)', borderRadius:8, background:'#fff',
                  opacity: isApplying ? 0.6 : 1,
                }}>
                  <div style={{
                    display:'flex', alignItems:'center', gap:8, padding:'6px 10px',
                    borderBottom:'1px solid var(--border)', background:'var(--ink-50, #f8fafc)',
                    fontSize:12, borderRadius:'8px 8px 0 0',
                  }}>
                    <span style={{
                      padding:'2px 8px', borderRadius:10, background: tone, color:'#fff',
                      fontWeight:700, fontSize:11,
                    }}>{s.similarity}% zhoda</span>
                    <span className="muted">Návrh spárovania podľa názvu produktu</span>
                  </div>
                  <div style={{display:'grid', gridTemplateColumns:'1fr auto 1fr', alignItems:'center', gap:10, padding:'10px 12px'}}>
                    {/* WC side */}
                    <div style={{minWidth:0}}>
                      <div className="small muted" style={{textTransform:'uppercase', letterSpacing:0.5, fontSize:10, marginBottom:2}}>🛒 WooCommerce</div>
                      <div className="mono small" style={{color: s.wc_sku ? 'var(--ink-900)' : 'var(--amber-700, #92400e)'}}>
                        {s.wc_sku || '— bez SKU —'}
                      </div>
                      <div style={{fontSize:13, fontWeight:500, marginTop:2, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}} title={s.wc_name}>
                        {s.wc_name}
                      </div>
                      <div className="small muted" style={{marginTop:2}}>
                        Sklad: {s.wc_qty ?? '—'} ks
                        <a onClick={() => onOpenProduct(s.wc_id)} style={{marginLeft:8, color:'var(--navy-700)', cursor:'pointer'}}>Otvoriť ↗</a>
                      </div>
                    </div>
                    {/* Arrow */}
                    <div style={{fontSize:22, color: tone, fontWeight:700}}>→</div>
                    {/* SF side */}
                    <div style={{minWidth:0}}>
                      <div className="small muted" style={{textTransform:'uppercase', letterSpacing:0.5, fontSize:10, marginBottom:2}}>📊 SuperFaktúra</div>
                      <div className="mono small" style={{color:'var(--green-700, #047857)', fontWeight:600}}>{s.sf_sku}</div>
                      <div style={{fontSize:13, fontWeight:500, marginTop:2, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}} title={s.sf_name}>
                        {s.sf_name}
                      </div>
                      <div className="small muted" style={{marginTop:2}}>
                        Sklad: {s.sf_qty ?? '—'} ks{s.sf_unit_price != null ? ` · ${s.sf_unit_price.toFixed(2)} €` : ''}
                      </div>
                    </div>
                  </div>
                  <div style={{
                    display:'flex', justifyContent:'flex-end', gap:6, padding:'8px 12px',
                    borderTop:'1px solid var(--border)', background:'var(--ink-50, #f8fafc)',
                    borderRadius:'0 0 8px 8px',
                  }}>
                    <button className="btn btn-xs" onClick={() => onOpenProduct(s.wc_id)} disabled={isApplying}>Upraviť WC ručne</button>
                    <button
                      className="btn btn-xs"
                      style={{background:'var(--navy-800)', color:'#fff', borderColor:'var(--navy-800)'}}
                      disabled={isApplying}
                      onClick={() => applySuggestion(s)}
                      title={`Zapíše SKU "${s.sf_sku}" do WC produktu ID ${s.wc_id}`}
                    >
                      {isApplying ? 'Ukladám…' : `✓ Použiť SF SKU "${s.sf_sku}"`}
                    </button>
                  </div>
                </div>
              );
            })}
          </div>
        ) : (
          <table className="tbl" style={{margin:0}}>
            {tab === 'only_web' && (
              <>
                <thead><tr>
                  <th>SKU</th><th>Názov (WC)</th>
                  <th style={{textAlign:'right'}}>Sklad WC</th>
                  <th style={{textAlign:'right'}}>Cena</th>
                  <th style={{textAlign:'right'}}>VOC</th>
                  <th></th>
                </tr></thead>
                <tbody>
                  {rows.map(r => (
                    <tr key={r.wc_id}>
                      <td className="mono small">{r.sku}</td>
                      <td className="small">{r.name}</td>
                      <td style={{textAlign:'right'}} className="small">{r.wc_qty ?? '—'}</td>
                      <td style={{textAlign:'right'}} className="small">{r.wc_price ?? '—'}</td>
                      <td style={{textAlign:'right'}} className="small">{r.wc_voc ?? '—'}</td>
                      <td style={{textAlign:'right'}}>
                        <button className="btn btn-xs" onClick={() => onOpenProduct(r.wc_id)}>Otvoriť</button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </>
            )}
            {tab === 'only_sf' && (
              <>
                <thead><tr>
                  <th>SKU</th><th>Názov (SF)</th>
                  <th style={{textAlign:'right'}}>Sklad SF</th>
                  <th style={{textAlign:'right'}}>Cena SF</th>
                </tr></thead>
                <tbody>
                  {rows.map(r => (
                    <tr key={r.sf_id}>
                      <td className="mono small">{r.sku}</td>
                      <td className="small">{r.name}</td>
                      <td style={{textAlign:'right'}} className="small">{r.sf_qty ?? '—'}</td>
                      <td style={{textAlign:'right'}} className="small">{r.sf_unit_price != null ? r.sf_unit_price.toFixed(2) + ' €' : '—'}</td>
                    </tr>
                  ))}
                </tbody>
              </>
            )}
            {tab === 'both' && (
              <>
                <thead><tr>
                  <th>SKU</th><th>Názov</th>
                  <th style={{textAlign:'right'}}>WC</th>
                  <th style={{textAlign:'right'}}>SF</th>
                  <th style={{textAlign:'right'}}>Δ</th>
                  <th style={{textAlign:'right'}}>Cena WC</th>
                  <th style={{textAlign:'right'}}>VOC</th>
                  <th style={{textAlign:'right'}}>Cena SF</th>
                  <th></th>
                </tr></thead>
                <tbody>
                  {rows.map(r => (
                    <tr key={r.wc_id} style={r.in_sync ? {} : { background: 'var(--amber-50, #fffbeb)' }}>
                      <td className="mono small">{r.sku}</td>
                      <td className="small">{r.name_wc}</td>
                      <td style={{textAlign:'right'}} className="small">{r.wc_qty ?? '—'}</td>
                      <td style={{textAlign:'right'}} className="small">{r.sf_qty ?? '—'}</td>
                      <td style={{textAlign:'right', fontWeight:600, color: r.qty_diff === 0 ? 'var(--ink-500)' : (r.qty_diff > 0 ? 'var(--amber-700, #92400e)' : 'var(--red-600, #b91c1c)')}}>
                        {r.qty_diff > 0 ? '+' : ''}{r.qty_diff}
                      </td>
                      <td style={{textAlign:'right'}} className="small">{r.wc_price != null ? r.wc_price.toFixed(2) : '—'}</td>
                      <td style={{textAlign:'right'}} className="small">{r.wc_voc   != null ? r.wc_voc.toFixed(2)   : '—'}</td>
                      <td style={{textAlign:'right'}} className="small">{r.sf_unit_price != null ? r.sf_unit_price.toFixed(2) : '—'}</td>
                      <td style={{textAlign:'right'}}>
                        <button className="btn btn-xs" onClick={() => onOpenProduct(r.wc_id)}>Otvoriť</button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </>
            )}
          </table>
        )}
      </div>

      {/* Footer hint about WC products without SKU — these never get matched */}
      {data.wc_without_sku && data.wc_without_sku.length > 0 && (
        <div style={{marginTop:10, padding:'8px 10px', background:'var(--amber-50, #fffbeb)', border:'1px solid var(--amber-200, #fde68a)', borderRadius:6, fontSize:12}}>
          ⚠️ <b>{data.wc_without_sku.length}</b> WC produktov nemá vyplnené SKU — bez SKU sa nedajú porovnať. Doplňte SKU v editore produktu.
        </div>
      )}
    </Modal>
  );
}

function SkuStat({ label, value, sub, tone = 'navy' }) {
  return (
    <div style={{
      padding:'10px 12px', background:'var(--ink-50, #f8fafc)',
      border:'1px solid var(--border)', borderRadius:8,
    }}>
      <div className="small muted">{label}</div>
      <div style={{fontSize:22, fontWeight:700, color: `var(--${tone}-800, #0e2744)`, lineHeight:1.2}}>{value || 0}</div>
      <div className="small muted" style={{fontSize:11}}>{sub}</div>
    </div>
  );
}

// ═════════════════════════════════════════════════════════════════════════════
// Progress log — live rotating list of human-readable steps for long-running
// AI operations. Shows currently-running step, ✓ for completed, and elapsed time.
// Steps rotate on a timer (rotateMs) — last step "sticks" until the parent
// stops the timer by removing the component.
// ═════════════════════════════════════════════════════════════════════════════
function ProgressLog({ steps, rotateMs = 3000, title = 'Pracujem…' }) {
  const [idx, setIdx] = React.useState(0);
  const [elapsedSec, setElapsedSec] = React.useState(0);

  React.useEffect(() => {
    const t0 = Date.now();
    const elap = setInterval(() => setElapsedSec(Math.floor((Date.now() - t0) / 1000)), 1000);
    const rot  = setInterval(() => setIdx(i => Math.min(i + 1, steps.length - 1)), rotateMs);
    return () => { clearInterval(elap); clearInterval(rot); };
  }, [rotateMs, steps.length]);

  return (
    <div className="card" style={{padding:16, background:'var(--blue-50)', border:'1px solid var(--border)'}}>
      <div className="hstack" style={{marginBottom:10}}>
        <b style={{fontSize:13}}>{title}</b>
        <span className="small muted" style={{marginLeft:'auto'}}>{elapsedSec}s</span>
      </div>
      <div style={{display:'flex', flexDirection:'column', gap:6}}>
        {steps.map((s, i) => {
          const done = i < idx;
          const active = i === idx;
          return (
            <div key={i} style={{
              display:'flex', alignItems:'center', gap:8,
              fontSize: active ? 13 : 12,
              color: active ? 'var(--ink-900, #0f172a)' : (done ? 'var(--ink-500, #6b7280)' : 'var(--ink-300, #d1d5db)'),
              fontWeight: active ? 600 : 400,
              opacity: done || active ? 1 : 0.5,
              transition: 'all 0.3s',
            }}>
              <span style={{width:18, textAlign:'center'}}>
                {done ? '✓' : (active ? <span className="spin">⟳</span> : '○')}
              </span>
              <span>{s}</span>
            </div>
          );
        })}
      </div>
      <style>{`@keyframes spin{to{transform:rotate(360deg)}} .spin{display:inline-block; animation:spin 1.2s linear infinite}`}</style>
    </div>
  );
}

// Realistic phase scripts for each AI operation
const PHASES_EXTRACT_PDF = [
  '📄 Čítam datasheet PDF',
  '🏷️ Identifikujem značku a typový kód',
  '⚡ Extrahujem elektrické parametre (Voc, Vmp, Imp, Isc)',
  '⚖️ Extrahujem rozmery, hmotnosť, rám',
  '🌡️ Prekladám hodnoty do slovenčiny (EN/CZ → SK diakritika)',
  '🛡️ Zisťujem záruku na produkt a výkon',
  '✓ Štruktúrujem výsledok',
];

const PHASES_DRAFT_COPY = [
  '🏷️ Generujem názov produktu podľa konvencie (Brand Model – vlastnosti – účinnosť)',
  '🔗 Skladám URL slug',
  '📝 Píšem krátky popis (3 paragrafy)',
  '🎯 Skladám SEO titulok (max 60 znakov)',
  '📋 Píšem meta description (max 160 znakov)',
  '🔑 Vyberám focus keyword',
  '⭐ Generujem 4-5 hlavných výhod s ✓ ikonami',
  '📄 Píšem dlhý popis s dde-* template (stat boxy, porovnanie, degradácia)',
  '❓ Pripravujem 3 FAQ otázky',
  '🖼️ Generujem alt-texty obrázkov',
  '🏷️ Navrhujem kategórie, tagy a SKU',
  '✓ Finalizujem JSON',
];

const PHASES_CREATE = [
  '🖼️ Nahrávam obrázky na WordPress',
  '🔎 Vyhľadávam kategóriu vo WooCommerce',
  '🔧 Pridávam atribúty do tabu "Špecifikácia"',
  '🏷️ Zapisujem Rank Math SEO meta (title, desc, focus keyword)',
  '🌐 Pridávam Open Graph (Facebook, Twitter)',
  '💾 Posielam produkt do WooCommerce',
  '✓ Overujem výsledok',
];

// ═════════════════════════════════════════════════════════════════════════════
// AI Product Wizard — 4 steps: PDF/brief → review extraction → review SEO copy → create
// ═════════════════════════════════════════════════════════════════════════════
function AIProductWizard({ onClose, onCreated, notify }) {
  const [step, setStep] = React.useState(1);    // 1=brief/upload, 2=extraction, 3=draft, 4=done
  const [busy, setBusy] = React.useState(null);

  // Inputs (step 1)
  const [pdfFile,     setPdfFile]     = React.useState(null);
  const [pdfUrl,      setPdfUrl]      = React.useState('');
  const [productName, setProductName] = React.useState('');
  const [targetModel, setTargetModel] = React.useState('');
  const [regularPrice, setRegularPrice] = React.useState('');
  const [vocCena,     setVocCena]     = React.useState('');
  const [nakupnaCena, setNakupnaCena] = React.useState('');
  const [stockQty,    setStockQty]    = React.useState('');
  const [imageFiles,  setImageFiles]  = React.useState([]);   // File[]
  const [imageMedia,  setImageMedia]  = React.useState([]);   // [{id, url}] from WP media after upload
  const [statusChoice, setStatusChoice] = React.useState('draft');

  // Manual-mode features (step 1b — used when no PDF)
  const [features, setFeatures] = React.useState(['', '', '']);
  const [useCase,  setUseCase]  = React.useState('');
  const [brand,    setBrand]    = React.useState('');

  // Step 2 — extraction
  const [extraction, setExtraction] = React.useState(null);

  // Step 3 — draft (SEO copy)
  const [draft, setDraft] = React.useState(null);

  // Step 4 — created product
  const [created, setCreated] = React.useState(null);

  async function uploadImagesIfNeeded() {
    if (!imageFiles.length || imageMedia.length === imageFiles.length) return imageMedia;
    setBusy('images');
    // Upload all in parallel — WP media endpoint handles concurrent uploads fine
    // and on slow connections this saves N×2s for N images.
    const results = await Promise.all(imageFiles.map(async f => {
      const r = await API.uploadMedia(f);
      if (r.ok && r.body.id) return { id: r.body.id, url: r.body.url, name: f.name };
      notify('error', `Upload ${f.name} zlyhal.`);
      return null;
    }));
    const ok = results.filter(Boolean);
    setImageMedia(ok);
    setBusy(null);
    return ok;
  }

  async function gotoStep2() {
    if (!productName.trim()) { notify('error', 'Zadajte názov produktu.'); return; }
    if (!pdfFile && !pdfUrl.trim() && features.filter(Boolean).length === 0) {
      notify('error', 'Pošlite PDF datasheet alebo vyplňte aspoň 1 vlastnosť.');
      return;
    }
    setBusy('extract');
    // (A) PDF path → call ai-extract-pdf
    if (pdfFile || pdfUrl.trim()) {
      const r = await API.aiExtractPdf({
        file: pdfFile, pdf_url: pdfUrl.trim() || undefined,
        target_model: targetModel.trim() || undefined,
      });
      setBusy(null);
      if (!r.ok || !r.body.extraction) {
        notify('error', r.body.message || 'Extrakcia z PDF zlyhala.');
        return;
      }
      setExtraction(r.body.extraction);
      setStep(2);
      return;
    }
    // (B) Manual brief — fabricate a minimal extraction-like object for step 2
    setExtraction({
      product_type: 'unknown',
      manufacturer: brand || null,
      model_name: null,
      attributes: features.filter(Boolean).map((f, i) => ({
        slug: 'feature_' + i, label: 'Vlastnosť ' + (i+1), section: 'basic',
        value: f, source_hint: 'manuálne zadanie', confidence: null, unknown: true,
      })),
      notes: useCase || null,
    });
    setBusy(null);
    setStep(2);
  }

  async function gotoStep3() {
    // Upload images first (own progress phase), then switch to draft phase.
    const imgs = await uploadImagesIfNeeded();   // [{id, url, name}]
    setBusy('draft');
    const r = await API.aiDraftProduct({
      name: productName,
      brand: brand || extraction?.manufacturer,
      model_full: extraction?.model_name,
      product_type: extraction?.product_type,
      attributes: extraction?.attributes || [],
      features: features.filter(Boolean),
      use_case: useCase,
      image_names: imgs.map(i => i.name || i.url),
    });
    setBusy(null);
    if (!r.ok || !r.body.draft) {
      notify('error', r.body.message || 'Generovanie SEO copy zlyhalo.');
      return;
    }
    setDraft(r.body.draft);
    setStep(3);
  }

  function updateDraftField(path, value) {
    setDraft(prev => {
      const next = JSON.parse(JSON.stringify(prev));
      const parts = path.split('.');
      let cur = next;
      for (let i = 0; i < parts.length - 1; i++) cur = cur[parts[i]] = cur[parts[i]] || {};
      cur[parts[parts.length - 1]] = value;
      return next;
    });
  }

  async function doCreate() {
    // Image upload runs first with its own progress, then WC create.
    const imgs = await uploadImagesIfNeeded();
    setBusy('create');
    const r = await API.aiCreateProduct({
      name: draft.name || productName,
      brand: brand || extraction?.manufacturer,
      regular_price: regularPrice || undefined,
      voc_cena: vocCena || undefined,
      nakupna_cena: nakupnaCena || undefined,
      stock_quantity: stockQty ? Number(stockQty) : undefined,
      // Send media IDs so WC skips sideload (much faster than re-downloading URLs)
      image_ids: imgs.map(i => i.id),
      image_urls: imgs.map(i => i.url),  // fallback if id resolution fails
      datasheet_url: pdfUrl.trim() || undefined,
      target_model: targetModel.trim() || undefined,
      status: statusChoice,
      extraction,    // pre-extracted — backend skips re-extract
      draft,         // user-edited — backend skips re-generate
    });
    setBusy(null);
    if (!r.ok || !r.body.product) {
      notify('error', r.body.message || 'Vytvorenie produktu zlyhalo.');
      return;
    }
    setCreated(r.body);
    setStep(4);
    onCreated && onCreated(r.body.product);
  }

  // ─── Render ───
  const stepLabels = ['Brief', 'Atribúty', 'SEO copy', 'Hotovo'];

  return (
    <Modal
      title="✨ AI generátor produktu"
      width={920}
      onClose={onClose}
      footer={
        <>
          <button className="btn" onClick={onClose} disabled={!!busy}>Zavrieť</button>
          {step === 1 && !busy && (
            <button className="btn btn-primary" onClick={gotoStep2} disabled={!productName.trim()}>
              Pokračovať →
            </button>
          )}
          {step === 2 && !busy && (
            <>
              <button className="btn" onClick={() => setStep(1)}>← Späť</button>
              <button className="btn btn-primary" onClick={gotoStep3}>Generovať SEO →</button>
            </>
          )}
          {step === 3 && !busy && (
            <>
              <button className="btn" onClick={() => setStep(2)}>← Späť</button>
              <button className="btn btn-primary" onClick={doCreate}>
                {`Vytvoriť ako ${statusChoice}`}
              </button>
            </>
          )}
        </>
      }
    >
      {/* Stepper */}
      <div style={{display:'flex', gap:8, marginBottom:16, padding:'8px 10px', background:'var(--blue-50)', borderRadius:6}}>
        {stepLabels.map((lbl, i) => (
          <div key={i} style={{
            flex:1, textAlign:'center', padding:'6px 8px', borderRadius:4,
            background: step === i+1 ? 'var(--navy-700)' : (step > i+1 ? 'var(--green-100, #d1fae5)' : 'transparent'),
            color:      step === i+1 ? '#fff' : (step > i+1 ? 'var(--green-700, #065f46)' : 'var(--ink-500)'),
            fontWeight: step === i+1 ? 600 : 500,
            fontSize:12,
          }}>
            {step > i+1 ? '✓ ' : `${i+1}. `}{lbl}
          </div>
        ))}
      </div>

      {/* Live progress log — replaces step content while a long AI op runs */}
      {busy === 'extract' && (
        <ProgressLog title="Analyzujem datasheet…" steps={PHASES_EXTRACT_PDF} rotateMs={2800}/>
      )}
      {busy === 'draft' && (
        <ProgressLog title="Generujem SEO copy a popis…" steps={PHASES_DRAFT_COPY} rotateMs={3500}/>
      )}
      {busy === 'create' && (
        <ProgressLog title="Vytváram produkt vo WooCommerce…" steps={PHASES_CREATE} rotateMs={2200}/>
      )}
      {busy === 'images' && (
        <ProgressLog title="Nahrávam obrázky…" steps={imageFiles.map((f,i)=>`📤 Nahrávam ${f.name} (${i+1}/${imageFiles.length})`)} rotateMs={1500}/>
      )}

      {step === 1 && !busy && (
        <div className="vstack" style={{gap:14}}>
          <div className="field">
            <label>Názov produktu *</label>
            <input className="input" value={productName} onChange={e => setProductName(e.target.value)}
              placeholder="napr. AIKO Solar A540-MCE60Dw — 540W panel" autoFocus/>
          </div>

          <div className="card" style={{padding:12, background:'#f0f9ff', border:'1px solid #7dd3fc'}}>
            <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600, marginBottom:8}}>📄 DATASHEET (najlepší zdroj dát)</div>
            <div className="field">
              <label>PDF súbor</label>
              <input type="file" accept="application/pdf" onChange={e => setPdfFile(e.target.files?.[0] || null)}/>
              {pdfFile && <div className="small muted" style={{marginTop:4}}>📄 {pdfFile.name} · {(pdfFile.size/1024/1024).toFixed(2)} MB</div>}
            </div>
            <div className="field" style={{marginTop:6}}>
              <label>Alebo URL existujúceho PDF (na WP)</label>
              <input className="input" value={pdfUrl} onChange={e => setPdfUrl(e.target.value)}
                placeholder="https://ddenergy.sk/wp-content/uploads/..."/>
            </div>
            <div className="field" style={{marginTop:6}}>
              <label>Variant modelu (ak datasheet pokrýva viacero) <span className="small muted">— napr. A540 pri PDF AIKO 540/545/550</span></label>
              <input className="input" value={targetModel} onChange={e => setTargetModel(e.target.value)} placeholder="A540"/>
            </div>
          </div>

          <details style={{padding:'8px 12px', background:'#fefce8', border:'1px solid #fde047', borderRadius:6}}>
            <summary style={{cursor:'pointer', fontWeight:600, fontSize:13}}>Alebo zadajte brief manuálne (ak nemáte PDF)</summary>
            <div className="vstack" style={{gap:8, marginTop:10}}>
              <div className="field">
                <label>Značka</label>
                <input className="input" value={brand} onChange={e => setBrand(e.target.value)} placeholder="AIKO / Huawei / GoodWe…"/>
              </div>
              <div className="field">
                <label>Typické použitie</label>
                <input className="input" value={useCase} onChange={e => setUseCase(e.target.value)} placeholder="Rodinné domy do 6 kWp"/>
              </div>
              <div className="field">
                <label>Kľúčové vlastnosti (3-8 odrážok)</label>
                {features.map((f, i) => (
                  <input key={i} className="input" style={{marginBottom:4}}
                    value={f} onChange={e => { const nf = [...features]; nf[i] = e.target.value; setFeatures(nf); }}
                    placeholder={'Vlastnosť ' + (i+1)}/>
                ))}
                <button type="button" className="btn btn-xs" onClick={() => setFeatures([...features, ''])}>+ Pridať</button>
              </div>
            </div>
          </details>

          <div className="card" style={{padding:12, background:'#fff8e4'}}>
            <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600, marginBottom:8}}>💰 CENY a SKLAD</div>
            <div style={{display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:8}}>
              <div className="field"><label>Bežná cena €</label><input className="input" value={regularPrice} onChange={e => setRegularPrice(e.target.value)} inputMode="decimal"/></div>
              <div className="field"><label>VOC (B2B) €</label><input className="input" value={vocCena} onChange={e => setVocCena(e.target.value)} inputMode="decimal"/></div>
              <div className="field"><label>Nákupná €</label><input className="input" value={nakupnaCena} onChange={e => setNakupnaCena(e.target.value)} inputMode="decimal"/></div>
            </div>
            <div className="field" style={{marginTop:6}}>
              <label>Sklad (ks) <span className="small muted">— prázdne = bez správy skladu</span></label>
              <input className="input" value={stockQty} onChange={e => setStockQty(e.target.value)} inputMode="numeric"/>
            </div>
          </div>

          <div className="card" style={{padding:12}}>
            <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600, marginBottom:8}}>🖼️ OBRÁZKY (voliteľné)</div>
            <input type="file" accept="image/*" multiple onChange={e => setImageFiles(Array.from(e.target.files || []))}/>
            {imageFiles.length > 0 && (
              <div className="small muted" style={{marginTop:4}}>{imageFiles.length} obrázkov pripravených. AI vygeneruje alt-texty.</div>
            )}
          </div>

          <div className="field">
            <label>Status pri vytvorení</label>
            <select className="select" value={statusChoice} onChange={e => setStatusChoice(e.target.value)}>
              <option value="draft">Koncept (odporúčam — skontrolovať a publikovať ručne)</option>
              <option value="pending">Čaká na schválenie</option>
              <option value="publish">Publikovať hneď (LIVE)</option>
            </select>
          </div>
        </div>
      )}

      {step === 2 && extraction && !busy && (
        <div className="vstack" style={{gap:12}}>
          <div className="card" style={{padding:12}}>
            <div className="hstack" style={{gap:14}}>
              <div><b>Typ:</b> {extraction.product_type}</div>
              <div><b>Výrobca:</b> {extraction.manufacturer || '—'}</div>
              <div><b>Model:</b> {extraction.model_name || '—'}</div>
              <div className="small muted" style={{marginLeft:'auto'}}>{extraction.attributes.length} atribútov</div>
            </div>
          </div>
          {extraction.notes && (
            <div className="card" style={{padding:'8px 12px', background:'#fefce8', fontSize:12}}>
              <b>Poznámky AI:</b> {extraction.notes}
            </div>
          )}
          <div className="card" style={{padding:0, overflow:'hidden'}}>
            <table className="tbl">
              <thead><tr><th>Sekcia</th><th>Atribút</th><th>Hodnota</th><th>Zdroj (PDF)</th><th style={{textAlign:'right'}}>Istota</th></tr></thead>
              <tbody>
                {extraction.attributes.map((a, i) => (
                  <tr key={i} style={a.unknown ? { background:'#fef3c7' } : {}}>
                    <td className="small">{a.section}</td>
                    <td><b>{a.label}</b>{a.unknown && <span className="small muted"> (neštandard)</span>}</td>
                    <td>
                      <input className="input" style={{fontSize:13}}
                        value={a.value}
                        onChange={e => {
                          const next = { ...extraction, attributes: [...extraction.attributes] };
                          next.attributes[i] = { ...a, value: e.target.value };
                          setExtraction(next);
                        }}/>
                    </td>
                    <td className="small muted" style={{fontStyle:'italic', maxWidth:240, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap'}} title={a.source_hint || ''}>
                      {a.source_hint || '—'}
                    </td>
                    <td className="small" style={{textAlign:'right'}}>
                      {a.confidence != null ? Math.round(a.confidence * 100) + ' %' : '—'}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <div className="small muted">Tip: hodnoty môžete priamo editovať. SEO copy v ďalšom kroku použije tieto upravené hodnoty.</div>
        </div>
      )}

      {step === 3 && draft && !busy && (
        <div className="vstack" style={{gap:12}}>
          <div className="field">
            <label>Názov produktu <span className="small muted">(konvencia: Brand Model – vlastnosti – účinnosť X,Y %)</span></label>
            <input className="input" value={draft.name || ''} onChange={e => updateDraftField('name', e.target.value)}/>
          </div>
          <div style={{display:'grid', gridTemplateColumns:'1.5fr 1fr', gap:8}}>
            <div className="field">
              <label>URL slug</label>
              <input className="input mono" value={draft.slug || ''} onChange={e => updateDraftField('slug', e.target.value)}/>
            </div>
            <div className="field">
              <label>SKU <span className="small muted">(DDE-KAT-BRAND-MODEL)</span></label>
              <input className="input mono" value={draft.sku_suggestion || ''} onChange={e => updateDraftField('sku_suggestion', e.target.value)} placeholder="DDE-PAN-AIKO-A540DW"/>
            </div>
          </div>
          <div className="card" style={{padding:12, background:'#f0f9ff'}}>
            <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600, marginBottom:8}}>🔍 SEO (Rank Math)</div>
            <div className="field">
              <label>SEO titulok <span className="small muted">({(draft.seo?.title || '').length}/60)</span></label>
              <input className="input" value={draft.seo?.title || ''} onChange={e => updateDraftField('seo.title', e.target.value)}/>
            </div>
            <div className="field">
              <label>Meta description <span className="small muted">({(draft.seo?.description || '').length}/160)</span></label>
              <textarea className="textarea" rows={2} value={draft.seo?.description || ''} onChange={e => updateDraftField('seo.description', e.target.value)}/>
            </div>
            <div className="field">
              <label>Focus keyword</label>
              <input className="input" value={draft.seo?.focus_keyword || ''} onChange={e => updateDraftField('seo.focus_keyword', e.target.value)}/>
            </div>
            <details>
              <summary style={{cursor:'pointer', fontSize:12, fontWeight:600}}>Facebook + Twitter (Open Graph)</summary>
              <div className="vstack" style={{gap:6, marginTop:8}}>
                <div className="field"><label>Facebook title</label><input className="input" value={draft.seo?.facebook_title || ''} onChange={e => updateDraftField('seo.facebook_title', e.target.value)}/></div>
                <div className="field"><label>Facebook description</label><textarea className="textarea" rows={2} value={draft.seo?.facebook_description || ''} onChange={e => updateDraftField('seo.facebook_description', e.target.value)}/></div>
                <div className="field"><label>Twitter title</label><input className="input" value={draft.seo?.twitter_title || ''} onChange={e => updateDraftField('seo.twitter_title', e.target.value)}/></div>
                <div className="field"><label>Twitter description</label><textarea className="textarea" rows={2} value={draft.seo?.twitter_description || ''} onChange={e => updateDraftField('seo.twitter_description', e.target.value)}/></div>
              </div>
            </details>
          </div>
          <div className="field">
            <label>Krátky popis (pod cenou) <span className="small muted">({(draft.short_description || '').length} zn.)</span></label>
            <textarea className="textarea" rows={3} value={draft.short_description || ''} onChange={e => updateDraftField('short_description', e.target.value)}/>
          </div>
          <div className="field">
            <label>Dlhý popis HTML <span className="small muted">({(draft.description || '').length} zn., s inline brand-style CSS)</span></label>
            <textarea className="textarea mono" rows={10} style={{fontSize:11}} value={draft.description || ''} onChange={e => updateDraftField('description', e.target.value)}/>
          </div>
          {Array.isArray(draft.image_alts) && draft.image_alts.length > 0 && (
            <div className="card" style={{padding:12}}>
              <div className="small muted" style={{textTransform:'uppercase', letterSpacing:'0.08em', fontWeight:600, marginBottom:6}}>🖼️ Alt-texty obrázkov</div>
              {draft.image_alts.map((alt, i) => (
                <div key={i} className="field" style={{marginBottom:4}}>
                  <label className="small">Obrázok {i+1}</label>
                  <input className="input" value={alt} onChange={e => {
                    const next = [...draft.image_alts]; next[i] = e.target.value;
                    updateDraftField('image_alts', next);
                  }}/>
                </div>
              ))}
            </div>
          )}
          {Array.isArray(draft.suggested_categories) && (
            <div className="small muted">
              <b>Navrhovaná kategória:</b> {draft.suggested_categories.join(', ')} ·
              <b> Tagy:</b> {(draft.suggested_tags || []).join(', ')}
            </div>
          )}
        </div>
      )}

      {step === 4 && created && !busy && (
        <div className="vstack" style={{gap:14, textAlign:'center', padding:'20px 10px'}}>
          <div style={{fontSize:48}}>✅</div>
          <h3>Produkt vytvorený</h3>
          <div className="card" style={{padding:14, textAlign:'left'}}>
            <div><b>ID:</b> {created.product.id}</div>
            <div><b>SKU:</b> {created.product.sku} {created.sku_generated && <span className="small muted">(auto-vygenerované)</span>}</div>
            <div><b>Status:</b> {created.product.status}</div>
            <div><b>Kategória:</b> {created.category_resolved} {created.category_id ? `(#${created.category_id})` : '(nenájdená)'}</div>
            <div><b>Atribúty:</b> {created.attributes_added} celkovo
              {created.attributes_breakdown && (
                <span className="small">
                  {' · '}
                  <span style={{color:'var(--green-700, #065f46)'}}>{created.attributes_breakdown.taxonomy} vo filtri (Layered Nav)</span>
                  {' · '}
                  <span className="muted">{created.attributes_breakdown.custom} iba v Špecifikácia tabe</span>
                </span>
              )}
            </div>
            {Array.isArray(created.attributes_mapping) && created.attributes_mapping.some(m => m.kind === 'custom') && (
              <details style={{marginTop:8, padding:'6px 10px', background:'#fef3c7', borderRadius:4}}>
                <summary style={{cursor:'pointer', fontSize:12, fontWeight:600}}>
                  ⚠️ {created.attributes_mapping.filter(m => m.kind === 'custom').length} atribútov sa nezobrazí v sidebar filtri
                </summary>
                <div className="small" style={{marginTop:6, lineHeight:1.5}}>
                  Nasledujúce atribúty nemajú globálny pa_* taxonómiu vo WooCommerce:
                  <ul style={{margin:'4px 0 4px 18px'}}>
                    {created.attributes_mapping.filter(m => m.kind === 'custom').map((m, i) => (
                      <li key={i}><b>{m.label}</b>: {m.value}</li>
                    ))}
                  </ul>
                  Ak ich chcete vidieť vo filtri, vytvorte ich vo WP admine: <code>Produkty → Atribúty → Pridať</code>.
                </div>
              </details>
            )}
          </div>
          <div className="hstack" style={{gap:8, justifyContent:'center'}}>
            <a className="btn btn-primary" href={created.edit_url_erp} onClick={onClose}>Otvoriť v ERP</a>
            <a className="btn" href={created.edit_url_wp} target="_blank" rel="noopener">WP admin ↗</a>
            {created.product.permalink && <a className="btn" href={created.product.permalink} target="_blank" rel="noopener">Náhľad na webe ↗</a>}
          </div>
        </div>
      )}
    </Modal>
  );
}

Object.assign(window, { Products, ProductThumb, AIProductWizard });
