// Step 5 — Merchandising Portal (GreenPan / Cookware Co)
// Shows the SAME four carousels as the personalized homepage,
// with a floating rules panel: Boost / Bury + criteria dropdown + slider.
// Pin mode lets you drag any product into any slot across all carousels.
//
// Rules act on cookware categories (Tucci, premium, best-seller, ceramic, etc.)
// and ranking is anchored to the active persona vector.

function StepMerch({ state, setState, mode }) {
  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 state — persisted at session level =====
  const rules = state.merchRules && state.merchRules.length
    ? state.merchRules
    : [{ id: 1, type: 'boost', criteria: 'best-seller', strength: 0 }];
  const setRules = (updater) => {
    setState(s => {
      const curr = s.merchRules && s.merchRules.length
        ? s.merchRules
        : [{ id: 1, type: 'boost', criteria: 'best-seller', strength: 0 }];
      const next = typeof updater === 'function' ? updater(curr) : updater;
      return { ...s, merchRules: next };
    });
  };
  const [nextRuleId, setNextRuleId] = React.useState(() => {
    const max = Math.max(0, ...(state.merchRules || []).map(r => r.id));
    return max + 1;
  });

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

  // ===== Criteria definitions =====
  const CRITERIA = [
    { id: 'best-seller', label: 'Best Sellers',     test: (p) => p.cats.includes('best-seller') },
    { id: 'new',         label: 'New Arrivals',     test: (p) => p.cats.includes('new') },
    { id: 'trending',    label: 'Trending Now',     test: (p) => p.cats.includes('trending') },
    { id: 'sale',        label: 'On Sale',          test: (p) => p.cats.includes('sale') },
    { id: 'tucci',       label: 'Tucci Collection', test: (p) => p.cats.includes('tucci') || p.cats.includes('stanley-tucci') },
    { id: 'bobby-flay',  label: 'Bobby Flay line',  test: (p) => p.cats.includes('bobby-flay') },
    { id: 'ceramic',     label: 'Ceramic (PFAS-free)', test: (p) => p.cats.includes('ceramic') },
    { id: 'stainless',   label: 'Stainless Steel',  test: (p) => p.cats.includes('stainless') },
    { id: 'premium',     label: 'Premium tier',     test: (p) => p.cats.includes('premium') },
    { id: 'value',       label: 'Value tier',       test: (p) => p.cats.includes('value') },
    { id: 'blue',        label: 'Blue colorway',    test: (p) => p.cats.includes('blue') },
    { id: 'cream',       label: 'Cream / Neutral',  test: (p) => p.cats.includes('cream') || p.cats.includes('neutral') },
    { id: 'wellness',    label: 'Wellness (PFAS-free messaging)', test: (p) => p.cats.includes('wellness') },
    { id: 'price-500',   label: 'Price ≥ $500',     test: (p) => (p.price || 0) >= 500 },
  ];
  const criteriaMap = Object.fromEntries(CRITERIA.map(c => [c.id, c]));

  // ===== Apply rules: boost/bury a candidate list =====
  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)) continue;
        if (rule.strength === 0) continue;
        if (rule.type === 'boost') {
          score += rule.strength;
          effects.push({ kind: 'boost', text: `${crit.label} +${rule.strength}` });
        } else if (rule.type === 'bury') {
          score -= rule.strength;
          effects.push({ kind: 'bury', text: `${crit.label} −${rule.strength}` });
        }
      }
      return { p, score, effects };
    });
  }, [rules]);

  // ===== Pools (mirror StepHome) =====
  const cookwarePool = products.filter(p =>
    p.cats.includes('cookware-set') || p.cats.includes('frypan') || p.cats.includes('frypan-set')
  );
  const electricsPool = products.filter(p => p.cats.includes('electric'));
  const bakewarePool = products.filter(p =>
    p.cats.includes('bakeware-set') || p.cats.includes('ovenware-set')
  );
  const cutleryPool = products.filter(p =>
    p.cats.includes('knife-block') || p.cats.includes('steak-knife') ||
    p.cats.includes('utensil-set') || p.cats.includes('pan-protector')
  );

  // ===== Carousel rankings: persona-anchored base + rule layer =====
  const buildCarousel = React.useCallback((pool, carouselId, slotCount = 6) => {
    // Base = persona score (matches StepHome's rankProducts ordering)
    const base = pool.map(p => ({
      p,
      baseScore: window.scoreFor(p, persona, null),
    })).sort((a, b) => b.baseScore - a.baseScore);

    // Layer rule adjustments. Base weight is large enough that the persona
    // ordering still dominates unless a rule is pushed hard.
    const scored = applyRules(base.map(x => x.p)).map((r, i) => ({
      ...r,
      baseScore: base[i] ? 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 cookwareRanked   = React.useMemo(() => buildCarousel(cookwarePool,  'cookware',  6), [buildCarousel, cookwarePool]);
  const electricsRanked  = React.useMemo(() => buildCarousel(electricsPool, 'electrics', 6), [buildCarousel, electricsPool]);
  const bakewareRanked   = React.useMemo(() => buildCarousel(bakewarePool,  'bakeware',  4), [buildCarousel, bakewarePool]);
  const cutleryRanked    = React.useMemo(() => buildCarousel(cutleryPool,   'cutlery',   6), [buildCarousel, cutleryPool]);

  // ===== Rule manipulation =====
  const addRule = () => {
    setRules(prev => [...prev, { id: nextRuleId, type: 'boost', criteria: 'best-seller', 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));

  // ===== Pin manipulation =====
  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 };
      for (const k of Object.keys(next)) 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: 'best-seller', strength: 0 }]);
    setNextRuleId(2);
    setPins({});
  };

  // ===== Pin tray: hand-picked products spanning categories =====
  const trayIds = React.useMemo(() => {
    const ids = [];
    const buckets = ['cookware-set', 'frypan-set', 'frypan', 'ice-cream-maker', 'pizza-oven', 'slow-cooker', 'air-fryer', 'blender', 'bakeware-set', 'ovenware-set', 'knife-block', 'steak-knife', 'utensil-set'];
    const used = new Set();
    for (const b of buckets) {
      const matching = products.filter(p => p.cats.includes(b) && !used.has(p.id)).slice(0, 3);
      for (const p of matching) { 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]);

  // ===== Card renderer (with pin drop zone) =====
  const renderCard = (item, carouselId, index) => {
    const slotKey = `${carouselId}-${index}`;
    const pinnedId = pins[slotKey];
    const displayItem = pinnedId
      ? { ...item, p: byId[pinnedId], pinned: true, effects: item.effects || [] }
      : item;
    const isDragOver = dragOverKey === slotKey;
    if (!displayItem.p) return null;

    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(2)}</div>

        <ScoreBar
          product={displayItem.p}
          persona={persona}
          effects={displayItem.effects}
        />
      </div>
    );
  };

  return (
    <div className="merch-root">
      <div className="merch-layout">
        {/* ============ MAIN — preview ============ */}
        <div className="merch-preview">
          <Carousel
            title="Cookware"
            subtitle={`Persona vector + rule engine · ranked for ${persona.name.split(',')[0]}`}
          >
            {cookwareRanked.slice(0, 6).map((item, i) => renderCard(item, 'cookware', i))}
          </Carousel>

          <Carousel
            title="Electrics"
            subtitle="Appliance affinity + rule engine"
          >
            {electricsRanked.slice(0, 6).map((item, i) => renderCard(item, 'electrics', i))}
          </Carousel>

          <Carousel
            title="Bakeware"
            subtitle="Color story + rule engine"
          >
            {bakewareRanked.slice(0, 4).map((item, i) => renderCard(item, 'bakeware', i))}
          </Carousel>

          <Carousel
            title="Cutlery & Tools"
            subtitle="Bundle propensity + rule engine"
          >
            {cutleryRanked.slice(0, 6).map((item, i) => renderCard(item, 'cutlery', i))}
          </Carousel>
        </div>

        {/* ============ RULES PANEL (sticky right) ============ */}
        <div className="merch-panel">
          <div className="merch-panel__head">
            <div className="merch-panel__brand">
              <img src="assets/malachyte-symbol-gradient.png" alt="Malachyte" 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>

          {/* Rules list */}
          <div className="merch-rules">
            <div className="merch-rules__head">
              <span>Boost / Bury rules</span>
              <span className="merch-rules__hint">Layered on top of 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>

          {/* Pin tray */}
          <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 slot in any carousel</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 ${p.name} to pin`}
                  >
                    <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>
  );
}

// ============================================================================
// Helpers
// ============================================================================

function rerankWithPins(scored, carouselId, pins, byId, slotCount) {
  const sorted = [...scored].sort((a, b) => (b.finalScore ?? b.score) - (a.finalScore ?? a.score));
  // Pins for this carousel
  const carouselPins = {};
  Object.keys(pins).forEach(k => {
    if (k.startsWith(carouselId + '-')) {
      const idx = parseInt(k.split('-')[1], 10);
      carouselPins[idx] = 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);

  // Place pinned
  Object.entries(carouselPins).forEach(([idx, id]) => {
    const i = parseInt(idx, 10);
    const existing = sorted.find(s => s.p.id === id);
    result[i] = existing || { p: byId[id], score: 100, finalScore: 100, baseScore: 0, effects: [] };
  });
  // Fill gaps
  let ni = 0;
  for (let i = 0; i < result.length; i++) {
    if (result[i]) continue;
    if (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={canDelete ? 'Remove rule' : 'Keep at least one rule'}
        >×</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 });
