// Merchandising Portal — Hoka Road Runner
// Live carousels + rule engine + pin tray

function StepMerch({ state, setState }) {
  const products = window.PRODUCTS || [];
  const byId = React.useMemo(() => Object.fromEntries(products.map(p => [p.id, p])), [products]);
  const persona = window.PERSONAS.find(p => p.id === state.persona) || window.PERSONAS[0];

  // Rules
  const rules = (state.merchRules && state.merchRules.length)
    ? state.merchRules
    : [{ id: 1, type: 'boost', criteria: 'performance', strength: 0 }];
  const setRules = (updater) => setState(s => {
    const curr = (s.merchRules && s.merchRules.length) ? s.merchRules : [{ id: 1, type: 'boost', criteria: 'performance', strength: 0 }];
    return { ...s, merchRules: typeof updater === 'function' ? updater(curr) : updater };
  });
  const [nextRuleId, setNextRuleId] = React.useState(2);

  // Pins
  const pins = state.merchPins || {};
  const setPins = (updater) => setState(s => {
    const curr = s.merchPins || {};
    return { ...s, merchPins: typeof updater === 'function' ? updater(curr) : updater };
  });
  const [draggingId, setDraggingId] = React.useState(null);
  const [dragOverKey, setDragOverKey] = React.useState(null);

  // Hoka-specific criteria
  const CRITERIA = [
    { id: 'performance',  label: 'Performance',       test: p => p.cats.includes('performance') },
    { id: 'race-shoe',    label: 'Race shoes',         test: p => p.cats.includes('race-shoe') },
    { id: 'max-cushion',  label: 'Max cushion',        test: p => p.cats.includes('max-cushion') },
    { id: 'trail-shoe',   label: 'Trail shoes',        test: p => p.cats.includes('trail-shoe') },
    { id: 'stable',       label: 'Stability',          test: p => p.cats.includes('stable') },
    { id: 'plush',        label: 'Plush ride',         test: p => p.cats.includes('plush') },
    { id: 'new',          label: 'New arrivals',       test: p => p.isNew === true },
    { id: 'sale',         label: 'On sale',            test: p => p.sale === true },
    { id: 'bestseller',   label: 'Best sellers',       test: p => (p.reviews || 0) > 200 },
    { id: 'sock',         label: 'Socks',              test: p => p.cats.includes('sock') },
    { id: 'top',          label: 'Run tops',           test: p => p.cats.includes('top') },
    { id: 'under-50',     label: 'Under $50',          test: p => (p.price || 0) < 50 },
    { id: 'responsive',   label: 'Responsive',         test: p => p.cats.includes('responsive') },
    { id: 'recovery',     label: 'Recovery',           test: p => p.cats.includes('recovery') },
  ];
  const criteriaMap = Object.fromEntries(CRITERIA.map(c => [c.id, c]));

  // Apply rules
  const applyRules = React.useCallback((pool) => {
    return pool.map(p => {
      let score = 100;
      const effects = [];
      for (const rule of rules) {
        const crit = criteriaMap[rule.criteria];
        if (!crit || !crit.test(p) || rule.strength === 0) continue;
        if (rule.type === 'boost') { score += rule.strength; effects.push({ kind: 'boost', text: `${crit.label} +${rule.strength}` }); }
        else                       { score -= rule.strength; effects.push({ kind: 'bury',  text: `${crit.label} −${rule.strength}` }); }
      }
      return { p, score, effects };
    });
  }, [rules]);

  // Gender-filtered pools
  const gFilter = p => p.gender === persona.gender || p.gender === 'all';

  const shoePool     = products.filter(p => p.cats.includes('road-plp') && gFilter(p));
  const apparelPool  = products.filter(p => p.cats.some(c => ['top','bottom'].includes(c)) && gFilter(p));
  const sockAccPool  = products.filter(p => p.cats.some(c => ['sock','accessory'].includes(c)));
  const salePool     = products.filter(p => p.sale && gFilter(p));

  const buildCarousel = React.useCallback((pool, carouselId, slotCount = 6) => {
    const base = pool.map(p => ({ p, baseScore: window.scoreFor(p, persona, null) }))
      .sort((a, b) => b.baseScore - a.baseScore);
    const scored = applyRules(base.map(x => x.p)).map((r, i) => ({
      ...r, baseScore: base[i]?.baseScore || 0,
      finalScore: (base[i]?.baseScore || 0) * 10 + r.score,
    }));
    return rerankWithPins(scored, carouselId, pins, byId, slotCount);
  }, [persona, rules, pins, applyRules, byId]);

  const shoeRanked   = React.useMemo(() => buildCarousel(shoePool,    'shoe',    6), [buildCarousel, shoePool]);
  const apparelRanked= React.useMemo(() => buildCarousel(apparelPool, 'apparel', 6), [buildCarousel, apparelPool]);
  const sockRanked   = React.useMemo(() => buildCarousel(sockAccPool, 'sock',    6), [buildCarousel, sockAccPool]);
  const saleRanked   = React.useMemo(() => buildCarousel(salePool,    'sale',    6), [buildCarousel, salePool]);

  const addRule = () => { setRules(prev => [...prev, { id: nextRuleId, type: 'boost', criteria: 'performance', strength: 30 }]); setNextRuleId(n => n + 1); };
  const updateRule = (id, patch) => setRules(prev => prev.map(r => r.id === id ? { ...r, ...patch } : r));
  const deleteRule = (id) => setRules(prev => prev.filter(r => r.id !== id));

  const handleDragStart = id => e => { setDraggingId(id); e.dataTransfer.effectAllowed = 'move'; try { e.dataTransfer.setData('text/plain', id); } catch {} };
  const handleDragEnd   = () => { setDraggingId(null); setDragOverKey(null); };
  const handleSlotDragOver  = key => e => { e.preventDefault(); setDragOverKey(key); };
  const handleSlotDragLeave = () => setDragOverKey(null);
  const handleSlotDrop = key => e => {
    e.preventDefault();
    const id = draggingId || e.dataTransfer.getData('text/plain');
    if (!id) return;
    setPins(prev => { const next = { ...prev }; Object.keys(next).forEach(k => { if (next[k] === id) delete next[k]; }); next[key] = id; return next; });
    setDraggingId(null); setDragOverKey(null);
  };
  const clearPin = key => setPins(prev => { const n = { ...prev }; delete n[key]; return n; });
  const resetAll = () => { setRules([{ id: 1, type: 'boost', criteria: 'performance', strength: 0 }]); setNextRuleId(2); setPins({}); };

  // Pin tray — diverse product sample
  const trayIds = React.useMemo(() => {
    const ids = [];
    const buckets = ['race-shoe','max-cushion','trail-shoe','everyday-shoe','stable','top','bottom','sock','accessory','performance','new','sale'];
    const used = new Set();
    for (const b of buckets) {
      const m = products.filter(p => p.cats.includes(b) && !used.has(p.id)).slice(0, 2);
      m.forEach(p => { ids.push(p.id); used.add(p.id); });
    }
    for (const p of products) { if (ids.length >= 24) break; if (!used.has(p.id)) { ids.push(p.id); used.add(p.id); } }
    return ids.slice(0, 24);
  }, [products]);

  const renderCard = (item, carouselId, index) => {
    if (!item) return null;
    const slotKey = `${carouselId}-${index}`;
    const pinnedId = pins[slotKey];
    const displayItem = pinnedId ? { ...item, p: byId[pinnedId], pinned: true } : item;
    if (!displayItem?.p) return null;
    const isDragOver = dragOverKey === slotKey;
    return (
      <div
        key={slotKey}
        className={`merch-slot ${isDragOver ? 'is-drag-over' : ''} ${pinnedId ? 'is-pinned' : ''}`}
        onDragOver={handleSlotDragOver(slotKey)}
        onDragLeave={handleSlotDragLeave}
        onDrop={handleSlotDrop(slotKey)}
      >
        {pinnedId && (<><div className="merch-slot__pin-badge">📌 PINNED</div><button className="merch-slot__unpin" onClick={() => clearPin(slotKey)} title="Remove pin">×</button></>)}
        <div className="merch-slot__rank">#{index + 1}</div>
        <div className="merch-slot__img">
          <img src={displayItem.p.img} alt={displayItem.p.name} onError={e => { e.target.src = window.PRODUCT_FALLBACK; }} />
        </div>
        <div className="merch-slot__name">{displayItem.p.name}</div>
        <div className="merch-slot__price">${displayItem.p.price.toFixed(0)}</div>
        <ScoreBar product={displayItem.p} persona={persona} effects={displayItem.effects} />
      </div>
    );
  };

  return (
    <div className="merch-root">
      <a href="https://portal.demo.malachyte.com/" target="_blank" rel="noopener noreferrer" className="merch-portal-cta merch-portal-cta--top">
        <div className="merch-portal-cta__bg" aria-hidden="true">
          <span className="merch-portal-cta__oval merch-portal-cta__oval--1" />
          <span className="merch-portal-cta__oval merch-portal-cta__oval--2" />
        </div>
        <img src="assets/malachyte-logo-gradient.png" alt="Malachyte" className="merch-portal-cta__logo" />
        <div className="merch-portal-cta__title">Open the full HOKA merchandising portal</div>
        <span className="merch-portal-cta__arrow">↗</span>
      </a>

      <div className="merch-layout">
        <div className="merch-preview">
          <Carousel title="Road Running Shoes" subtitle={`Gender-matched · ranked for ${persona.userId}`}>
            {shoeRanked.slice(0, 6).map((item, i) => renderCard(item, 'shoe', i))}
          </Carousel>
          <Carousel title="Run Apparel" subtitle="Tops + bottoms · persona-ranked">
            {apparelRanked.slice(0, 6).map((item, i) => renderCard(item, 'apparel', i))}
          </Carousel>
          <Carousel title="Socks & Accessories" subtitle="Complementary gear · affinity-ranked">
            {sockRanked.slice(0, 6).map((item, i) => renderCard(item, 'sock', i))}
          </Carousel>
          <Carousel title="Sale" subtitle="Marked down · rule engine applied">
            {saleRanked.slice(0, 6).map((item, i) => renderCard(item, 'sale', i))}
          </Carousel>
        </div>

        <div className="merch-panel">
          <div className="merch-panel__head">
            <div className="merch-panel__brand">
              <img src="assets/malachyte-symbol-gradient.png" alt="" className="merch-panel__logo" />
              <div>
                <div className="merch-panel__eyebrow">MALACHYTE</div>
                <div className="merch-panel__title">Merchandising Controls</div>
              </div>
            </div>
            <button className="merch-reset" onClick={resetAll}>↻ Reset</button>
          </div>

          <div className="merch-persona-row">
            <div className="merch-persona-row__text">
              <div className="merch-persona-row__lbl">ACTIVE VISITOR</div>
              <div className="merch-persona-row__name">{persona.userId} · {persona.chips[0]}</div>
            </div>
          </div>

          <div className="merch-rules">
            <div className="merch-rules__head">
              <span>Boost / Bury rules</span>
              <span className="merch-rules__hint">Layered on persona vector</span>
            </div>
            {rules.map(rule => (
              <RuleRow key={rule.id} rule={rule} criteria={CRITERIA} onUpdate={patch => updateRule(rule.id, patch)} onDelete={() => deleteRule(rule.id)} canDelete={rules.length > 1} />
            ))}
            <button className="merch-add-rule" onClick={addRule}>+ Add rule</button>
          </div>

          <div className="merch-pin-tray">
            <div className="merch-pin-tray__head">
              <div className="merch-pin-tray__title">Pin products to slots</div>
              <div className="merch-pin-tray__sub">Drag any product onto any carousel slot</div>
            </div>
            <div className="merch-pin-grid">
              {trayIds.map(id => {
                const p = byId[id];
                if (!p) return null;
                const isPinned = Object.values(pins).includes(id);
                return (
                  <div key={id} className={`merch-pin-prod ${isPinned ? 'is-pinned' : ''} ${draggingId === id ? 'is-dragging' : ''}`}
                    draggable={!isPinned} onDragStart={handleDragStart(id)} onDragEnd={handleDragEnd}
                    title={isPinned ? `${p.name} already pinned` : `Drag to pin: ${p.name}`}>
                    <img src={p.img} alt={p.name} onError={e => { e.target.src = window.PRODUCT_FALLBACK; }} />
                    {isPinned && <span className="merch-pin-prod__mark">📌</span>}
                  </div>
                );
              })}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function rerankWithPins(scored, carouselId, pins, byId, slotCount) {
  const sorted = [...scored].sort((a, b) => (b.finalScore ?? b.score) - (a.finalScore ?? a.score));
  const carouselPins = {};
  Object.keys(pins).forEach(k => {
    if (k.startsWith(carouselId + '-')) carouselPins[parseInt(k.split('-')[1], 10)] = pins[k];
  });
  const pinnedIds = new Set(Object.values(carouselPins));
  const nonPinned = sorted.filter(s => !pinnedIds.has(s.p.id));
  const size = Math.max(slotCount, ...Object.keys(carouselPins).map(i => parseInt(i, 10) + 1));
  const result = new Array(size).fill(null);
  Object.entries(carouselPins).forEach(([idx, id]) => {
    const i = parseInt(idx, 10);
    result[i] = sorted.find(s => s.p.id === id) || { p: byId[id], score: 100, finalScore: 100, baseScore: 0, effects: [] };
  });
  let ni = 0;
  for (let i = 0; i < result.length; i++) { if (!result[i] && ni < nonPinned.length) result[i] = nonPinned[ni++]; }
  return result.filter(Boolean);
}

function Carousel({ title, subtitle, children }) {
  return (
    <div className="merch-carousel">
      <div className="merch-carousel__head">
        <h3 className="merch-carousel__title">{title}</h3>
        <div className="merch-carousel__sub">{subtitle}</div>
      </div>
      <div className="merch-carousel__track">{children}</div>
    </div>
  );
}

function ScoreBar({ product, persona, effects }) {
  if (!product) return null;
  const score = window.relevanceScore(product, persona, null);
  return (
    <div className="merch-score">
      <div className="merch-score__val">
        <span className="merch-score__dot" />
        Score · {score.toFixed(2)}
      </div>
      {effects && effects.length > 0 && (
        <div className="merch-score__effects">
          {effects.map((e, i) => (
            <div key={i} className={`merch-effect merch-effect--${e.kind}`}>{e.text}</div>
          ))}
        </div>
      )}
    </div>
  );
}

function RuleRow({ rule, criteria, onUpdate, onDelete, canDelete }) {
  return (
    <div className={`merch-rule merch-rule--${rule.type}`}>
      <div className="merch-rule__row">
        <select className="merch-rule__type" value={rule.type} onChange={e => onUpdate({ type: e.target.value })}>
          <option value="boost">Boost</option>
          <option value="bury">Bury</option>
        </select>
        <select className="merch-rule__crit" value={rule.criteria} onChange={e => onUpdate({ criteria: e.target.value })}>
          {criteria.map(c => <option key={c.id} value={c.id}>{c.label}</option>)}
        </select>
        <button className="merch-rule__delete" onClick={onDelete} disabled={!canDelete} title="Remove">×</button>
      </div>
      <div className="merch-rule__slider-wrap">
        <input type="range" min={0} max={200} step={5} value={rule.strength}
          onChange={e => onUpdate({ strength: Number(e.target.value) })} className="merch-rule__slider" />
        <div className="merch-rule__strength">{rule.strength}</div>
      </div>
    </div>
  );
}

Object.assign(window, { StepMerch });
