// ── Cookbook Roulette ─────────────────────────────────────────────────────
// Spin the wheel to pick tonight's dinner.
// Filters are local to this page. Default: Quick & Easy on, everything else off.

(function () {
  const { useState, useEffect, useRef, useMemo } = React;

  // ── Spec color tokens (match .roulette-view CSS vars) ────────────────────
  const RLT = {
    paper:   '#f6efe3',   // even slices
    stone:   '#c9b99e',   // odd slices — warm stone
    ink:     '#23180f',
    bg:      '#fbf6ee',
    gold:    '#c9922a',
  };

  // Default filter state — Q&E on, everything else off
  const DEFAULTS = { qe: true, fav: false, meal: '', meat: '' };

  // ── Fisher-Yates sample up to 12 ─────────────────────────────────────────
  function sample12(arr) {
    if (!arr.length) return [];
    const copy = [...arr];
    for (let i = copy.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [copy[i], copy[j]] = [copy[j], copy[i]];
    }
    return copy.slice(0, 12);
  }

  // ── Wheel math ────────────────────────────────────────────────────────────
  //
  // Segments start from the top (SVG -90°). After the wheel rotates R degrees
  // clockwise, the pointer (fixed at top) shows whatever was at SVG angle
  // (270° - R) in the original layout.
  //
  // To land winner w under the pointer:
  //   R ≡ (360 − (w + 0.5) × segAngle)  (mod 360)
  //
  function calcTargetRotation(prevR, winnerIdx, n) {
    const seg    = 360 / n;
    const target = ((360 - (winnerIdx + 0.5) * seg) % 360 + 360) % 360;
    const cur    = ((prevR % 360) + 360) % 360;
    let   delta  = (target - cur + 360) % 360;
    if (delta < 2) delta += 360;          // always spin forward
    const extra  = 5 + Math.floor(Math.random() * 3); // 5–7 full rotations
    return prevR + delta + extra * 360;
  }

  // ── Build SVG slice data ──────────────────────────────────────────────────

  const CX = 200, CY = 200, R = 183;

  function buildSlices(recipes, evenFill, oddFill, evenText, oddText) {
    const n = recipes.length;
    if (!n) return [];
    const seg   = 360 / n;
    const maxCh = n <= 5 ? 16 : n <= 8 ? 11 : 8;
    const fs    = n <= 5 ? 13 : n <= 8 ? 11 : 9;

    return recipes.map((recipe, i) => {
      const startSvg = i * seg - 90;          // offset so 0° is at top
      const endSvg   = startSvg + seg;
      const sRad = startSvg * Math.PI / 180;
      const eRad = endSvg   * Math.PI / 180;

      const x1 = (CX + R * Math.cos(sRad)).toFixed(3);
      const y1 = (CY + R * Math.sin(sRad)).toFixed(3);
      const x2 = (CX + R * Math.cos(eRad)).toFixed(3);
      const y2 = (CY + R * Math.sin(eRad)).toFixed(3);
      const la = seg > 180 ? 1 : 0;
      const d  = `M${CX} ${CY} L${x1} ${y1} A${R} ${R} 0 ${la} 1 ${x2} ${y2}Z`;

      const midSvg = startSvg + seg / 2;
      const mRad   = midSvg * Math.PI / 180;
      const tr     = R * 0.62;
      const tx     = CX + tr * Math.cos(mRad);
      const ty     = CY + tr * Math.sin(mRad);

      const norm = ((midSvg % 360) + 360) % 360;
      let textRot = midSvg;
      if (norm > 90 && norm <= 270) textRot += 180;

      const fill     = i % 2 === 0 ? evenFill : oddFill;
      const textFill = i % 2 === 0 ? evenText : oddText;
      const label    = recipe.name.length > maxCh
        ? recipe.name.slice(0, maxCh - 1) + '…'
        : recipe.name;

      return { id: recipe.id, d, fill, textFill, tx, ty, textRot, label, fs, sRad };
    });
  }

  // ── WheelSVG ──────────────────────────────────────────────────────────────

  function WheelSVG({ slices, rotation, isSpinning, winId }) {
    const gRef = useRef(null);
    const groupStyle = {
      transformOrigin: `${CX}px ${CY}px`,
      transform:  `rotate(${rotation}deg)`,
      transition: isSpinning
        ? 'transform 4.2s cubic-bezier(0.19, 1, 0.22, 1)'
        : 'none',
    };

    // Pointer flick: while spinning, sample the live rotation each frame and
    // kick the pointer whenever a peg (slice boundary) sweeps past 12 o'clock.
    useEffect(() => {
      if (!isSpinning || !gRef.current || !slices.length) return;
      const pointer = gRef.current.closest('.wheel-wrap')?.querySelector('.wheel-pointer');
      if (!pointer) return;
      const segAngle = 360 / slices.length;
      let last = null, raf;
      const tick = () => {
        const t = getComputedStyle(gRef.current).transform;
        if (t && t !== 'none') {
          const m = t.match(/matrix\(([-\d.e]+),\s*([-\d.e]+)/);
          if (m) {
            let deg = Math.atan2(parseFloat(m[2]), parseFloat(m[1])) * 180 / Math.PI;
            if (deg < 0) deg += 360;
            const peg = Math.floor(deg / segAngle);
            if (last !== null && peg !== last) {
              pointer.classList.remove('flick');
              void pointer.offsetWidth;
              pointer.classList.add('flick');
            }
            last = peg;
          }
        }
        raf = requestAnimationFrame(tick);
      };
      raf = requestAnimationFrame(tick);
      return () => { cancelAnimationFrame(raf); pointer.classList.remove('flick'); };
    }, [isSpinning, slices.length]);

    const pegs = slices.map(s => ({
      id: s.id,
      x: CX + (R + 5.5) * Math.cos(s.sRad),
      y: CY + (R + 5.5) * Math.sin(s.sRad),
    }));

    return (
      <svg viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg"
           className="wheel-svg" aria-hidden="true">
        <defs>
          <radialGradient id="rlt-vign" cx="50%" cy="42%" r="65%">
            <stop offset="62%" stopColor="rgba(255,255,255,0)" />
            <stop offset="100%" stopColor="rgba(36,29,18,0.16)" />
          </radialGradient>
          <radialGradient id="rlt-hub" cx="42%" cy="38%" r="70%">
            <stop offset="0%" stopColor="#3e6b50" />
            <stop offset="100%" stopColor="#16382a" />
          </radialGradient>
        </defs>
        <circle cx={CX} cy={CY} r={R + 11} fill="#241d12" />
        <circle cx={CX} cy={CY} r={R +  8.5} fill="none"
                stroke={RLT.gold} strokeWidth="2.2" opacity="0.85" />
        <g ref={gRef} style={groupStyle}>
          {slices.map(s => (
            <g key={s.id}>
              <path d={s.d} fill={s.fill} stroke="#cdbf9f" strokeWidth="1"
                    className={s.id === winId ? 'rlt-seg-win' : ''} />
              <text
                x={s.tx.toFixed(2)} y={s.ty.toFixed(2)}
                textAnchor="middle" dominantBaseline="middle"
                fontSize={s.fs} fontWeight="700"
                fontFamily="Lato, sans-serif" fill={s.textFill}
                transform={`rotate(${s.textRot.toFixed(1)},${s.tx.toFixed(2)},${s.ty.toFixed(2)})`}
                style={{ pointerEvents: 'none', userSelect: 'none' }}
              >{s.label}</text>
            </g>
          ))}
          <circle cx={CX} cy={CY} r={R} fill="url(#rlt-vign)" pointerEvents="none" />
          {pegs.map(p => (
            <circle key={`p${p.id}`} cx={p.x.toFixed(2)} cy={p.y.toFixed(2)} r="4.6"
                    fill={RLT.gold} stroke="#8a6418" strokeWidth="1" />
          ))}
          <circle cx={CX} cy={CY} r="28" fill="#241d12" />
          <circle cx={CX} cy={CY} r="23" fill="url(#rlt-hub)" stroke={RLT.gold} strokeWidth="3" />
          <circle cx={CX - 6.5} cy={CY - 7} r="6" fill="rgba(244,238,224,0.32)" />
        </g>
      </svg>
    );
  }

  // ── Confetti ──────────────────────────────────────────────────────────────

  function Confetti() {
    const dots = useMemo(() => {
      const cols = ['#1f4a38', RLT.gold, '#5a7a5c', '#2c6e99', RLT.bg, '#d4a853', '#a0522d'];
      return Array.from({ length: 30 }, (_, i) => ({
        id:  i,
        x:   4 + Math.random() * 92,
        col: cols[i % cols.length],
        w:   6 + Math.random() * 8,
        h:   4 + Math.random() * 7,
        del: Math.random() * 0.55,
        dur: 1.1 + Math.random() * 0.9,
        rot: Math.floor(Math.random() * 360),
      }));
    }, []);

    return (
      <div className="rlt-confetti" aria-hidden="true">
        {dots.map(d => (
          <span key={d.id} className="rlt-cfp" style={{
            left:              `${d.x}%`,
            width:             d.w,
            height:            d.h,
            background:        d.col,
            transform:         `rotate(${d.rot}deg)`,
            animationDelay:    `${d.del}s`,
            animationDuration: `${d.dur}s`,
          }} />
        ))}
      </div>
    );
  }

  // ── ResultCard ────────────────────────────────────────────────────────────

  function ResultCard({ recipe, onView, onAgain }) {
    return (
      <div className="roul-result-wrap">
        <Confetti />
        <div className="roul-result-divider">Tonight's Pick</div>
        <div className="roul-result" onClick={onView}>
          <div className="roul-result-img"
               style={{ backgroundImage: recipe.image ? `url(${recipe.image})` : undefined }}>
            {recipe.favorite && (
              <div className="card-fav"><IconHeart size={14} filled={true} /></div>
            )}
          </div>
          <div className="roul-result-body">
            <div className="roul-result-eyebrow">
              {recipe.category && <span>{recipe.category}</span>}
              {recipe.addedBy && <em>{recipe.category ? ' · ' : ''}by {recipe.addedBy}</em>}
            </div>
            <h2 className="roul-result-title">{recipe.name}</h2>
            {recipe.description && (
              <p className="roul-result-desc">{recipe.description}</p>
            )}
            <div className="roul-result-meta">
              {recipe.prep && <span><IconClock size={12} /> {recipe.prep}</span>}
              {recipe.prep && recipe.cook && <span className="dot" />}
              {recipe.cook && <span><IconFlame size={12} /> {recipe.cook}</span>}
            </div>
            {((recipe.mealTypes || []).length + (recipe.meatTypes || []).length > 0) && (
              <div className="roul-result-tags">
                {(recipe.mealTypes || []).map(t => <span key={t} className="tag tag-meal">{t}</span>)}
                {(recipe.meatTypes || []).map(t => <span key={t} className="tag tag-meat">{t}</span>)}
              </div>
            )}
            <div className="roul-result-cta">
              <button className="primary-btn" onClick={e => { e.stopPropagation(); onView(); }}>
                <IconBook size={15} /> View Recipe
              </button>
              <button className="ghost-btn" onClick={e => { e.stopPropagation(); onAgain(); }}>
                Spin Again
              </button>
            </div>
          </div>
        </div>
      </div>
    );
  }

  // ── RouletteView ──────────────────────────────────────────────────────────

  function RouletteView({ recipes, onOpenRecipe, onBack, onAddRecipe }) {
    const [localQE,    setLocalQE]    = useState(DEFAULTS.qe);
    const [localFav,   setLocalFav]   = useState(DEFAULTS.fav);
    const [localMeal,  setLocalMeal]  = useState(DEFAULTS.meal);
    const [localMeat,  setLocalMeat]  = useState(DEFAULTS.meat);
    const [rotation,   setRotation]   = useState(0);
    const [isSpinning, setIsSpinning] = useState(false);
    const [winner,     setWinner]     = useState(null);
    const [winId,      setWinId]      = useState(null);

    const [pool,   setPool]   = useState(() => {
      const init = recipes.filter(r => isQuickAndEasy(r));
      return sample12(init);
    });
    const [slices, setSlices] = useState(() => {
      const p = sample12(recipes.filter(r => isQuickAndEasy(r)));
      return buildSlices(p, RLT.paper, RLT.stone, RLT.ink, RLT.ink);
    });

    const timerRef        = useRef(null);
    const lastWinnerIdRef = useRef(null);

    const mealTypes = useMemo(() => {
      const s = new Set();
      recipes.forEach(r => (r.mealTypes || []).forEach(t => s.add(t)));
      return [...s].sort();
    }, [recipes]);

    const meatTypes = useMemo(() => {
      const s = new Set();
      recipes.forEach(r => (r.meatTypes || []).forEach(t => s.add(t)));
      return [...s].sort();
    }, [recipes]);

    // Full filtered pool — respects all four active filters
    const filtered = useMemo(() =>
      recipes.filter(r => {
        if (localQE  && !isQuickAndEasy(r))                       return false;
        if (localFav && !r.favorite)                              return false;
        if (localMeal && !(r.mealTypes || []).includes(localMeal)) return false;
        if (localMeat && !(r.meatTypes || []).includes(localMeat)) return false;
        return true;
      }),
    [recipes, localQE, localFav, localMeal, localMeat]);

    // ── Pill counts: each shows how many recipes match that pill's condition
    // combined with all OTHER currently-active filters (not itself).
    // This makes counts predictive: "if you click this, here's your pool."

    // Q&E count: how many match isQE AND (fav, meal, meat)
    const qeCount = useMemo(() =>
      recipes.filter(r => {
        if (!isQuickAndEasy(r)) return false;
        if (localFav  && !r.favorite)                              return false;
        if (localMeal && !(r.mealTypes || []).includes(localMeal)) return false;
        if (localMeat && !(r.meatTypes || []).includes(localMeat)) return false;
        return true;
      }).length,
    [recipes, localFav, localMeal, localMeat]);

    // Favorites count: how many match fav=true AND (qe, meal, meat)
    const favCount = useMemo(() =>
      recipes.filter(r => {
        if (!r.favorite) return false;
        if (localQE  && !isQuickAndEasy(r))                       return false;
        if (localMeal && !(r.mealTypes || []).includes(localMeal)) return false;
        if (localMeat && !(r.meatTypes || []).includes(localMeat)) return false;
        return true;
      }).length,
    [recipes, localQE, localMeal, localMeat]);

    // Meal pill counts: each meal type t combined with (qe, fav, meat)
    const countByMeal = useMemo(() => {
      const c = {};
      mealTypes.forEach(t => {
        c[t] = recipes.filter(r => {
          if (localQE  && !isQuickAndEasy(r))          return false;
          if (localFav && !r.favorite)                 return false;
          if (!(r.mealTypes || []).includes(t))        return false;
          if (localMeat && !(r.meatTypes || []).includes(localMeat)) return false;
          return true;
        }).length;
      });
      return c;
    }, [recipes, localQE, localFav, localMeat, mealTypes]);

    // Meat pill counts: each meat type t combined with (qe, fav, meal)
    const countByMeat = useMemo(() => {
      const c = {};
      meatTypes.forEach(t => {
        c[t] = recipes.filter(r => {
          if (localQE  && !isQuickAndEasy(r))          return false;
          if (localFav && !r.favorite)                 return false;
          if (localMeal && !(r.mealTypes || []).includes(localMeal)) return false;
          if (!(r.meatTypes || []).includes(t))        return false;
          return true;
        }).length;
      });
      return c;
    }, [recipes, localQE, localFav, localMeal, meatTypes]);

    // Refresh wheel when filters change (not mid-spin)
    useEffect(() => {
      if (isSpinning) return;
      const p = sample12(filtered);
      setPool(p);
      setSlices(buildSlices(p, RLT.paper, RLT.stone, RLT.ink, RLT.ink));
      setWinner(null);
      setWinId(null);
    }, [filtered]);

    useEffect(() => () => { if (timerRef.current) clearTimeout(timerRef.current); }, []);

    function spin() {
      if (isSpinning || filtered.length < 1) return;
      if (timerRef.current) clearTimeout(timerRef.current);

      const p  = sample12(filtered);
      const sl = buildSlices(p, RLT.paper, RLT.stone, RLT.ink, RLT.ink);

      // Same-recipe guard: no-ops when pool has only one recipe
      let wi = Math.floor(Math.random() * p.length);
      if (p.length > 1 && p[wi].id === lastWinnerIdRef.current) {
        const alt = Math.floor(Math.random() * (p.length - 1));
        wi = alt < wi ? alt : alt + 1;
      }

      const newR         = calcTargetRotation(rotation, wi, p.length);
      const pickedRecipe = p[wi];

      setPool(p);
      setSlices(sl);
      setWinner(null);
      setWinId(null);
      setRotation(newR);
      setIsSpinning(true);

      timerRef.current = setTimeout(() => {
        setIsSpinning(false);
        setWinner(pickedRecipe);
        setWinId(pickedRecipe.id);
        lastWinnerIdRef.current = pickedRecipe.id;
      }, 4400);
    }

    function resetFilters() {
      setLocalQE(DEFAULTS.qe);
      setLocalFav(DEFAULTS.fav);
      setLocalMeal(DEFAULTS.meal);
      setLocalMeat(DEFAULTS.meat);
    }

    const isDefault = localQE === DEFAULTS.qe && localFav === DEFAULTS.fav
                   && !localMeal && !localMeat;
    const canSpin   = !isSpinning && filtered.length >= 1 && !winner;

    // ── Pill class helper
    function pillClass(isToggle, isActive, count) {
      const parts = ['roul-pill'];
      if (isToggle && isActive) parts.push('is-toggle-active');
      else if (!isToggle && isActive) parts.push('is-active');
      if (count === 0) parts.push('is-zero');
      return parts.join(' ');
    }

    // ── Empty state copy: detect whether cookbook is empty or filters are too narrow
    function emptyContent() {
      if (recipes.length === 0) {
        return (
          <>
            <p>Add your first recipe to spin the wheel.</p>
            <button className="primary-btn" onClick={onAddRecipe}>
              <IconPlus size={14} stroke={2} /> Add Recipe
            </button>
          </>
        );
      }
      return (
        <>
          <p>No recipes match these filters.</p>
          {!isDefault && (
            <button className="ghost-btn" onClick={resetFilters}>Reset filters</button>
          )}
        </>
      );
    }

    return (
      <div className="roulette-view">

        {/* ── Head ── */}
        <div className="roul-head">
          <div className="roul-eyebrow">
            <span className="eyebrow-line" />
            Cookbook Roulette
            <span className="eyebrow-line" />
          </div>
          <h1 className="roul-title">What's for <em>Dinner?</em></h1>
          <p className="roul-sub">
            Can't decide? Let fate pick tonight's recipe from the family collection.
          </p>
          <button className="roul-exit" onClick={onBack}>
            <IconX size={13} /> Back to cookbook
          </button>
        </div>

        {/* ── Filters ── */}
        <div className="roul-filters">

          {/* Boolean toggles — Q&E and Favorites */}
          <div className="roul-toggle-row">
            <button
              className={pillClass(true, localQE, qeCount)}
              onClick={() => setLocalQE(v => !v)}>
              ⚡ Quick &amp; Easy
              <span className="roul-pill-suffix">{qeCount}</span>
            </button>
            <button
              className={pillClass(true, localFav, favCount)}
              onClick={() => setLocalFav(v => !v)}>
              <IconHeart size={13} filled={localFav} /> Favorites
              <span className="roul-pill-suffix">{favCount}</span>
            </button>
          </div>

          {/* Category filters — meal type */}
          {mealTypes.length > 0 && (
            <div className="roul-filter-group">
              {mealTypes.map(t => (
                <button key={t}
                  className={pillClass(false, localMeal === t, countByMeal[t])}
                  onClick={() => setLocalMeal(localMeal === t ? '' : t)}>
                  {t}
                  <span className="roul-pill-suffix">{countByMeal[t]}</span>
                </button>
              ))}
            </div>
          )}

          {/* Category filters — meat type */}
          {meatTypes.length > 0 && (
            <div className="roul-filter-group">
              {meatTypes.map(t => (
                <button key={t}
                  className={pillClass(false, localMeat === t, countByMeat[t])}
                  onClick={() => setLocalMeat(localMeat === t ? '' : t)}>
                  {t}
                  <span className="roul-pill-suffix">{countByMeat[t]}</span>
                </button>
              ))}
            </div>
          )}
        </div>

        {/* ── Recipe count ── */}
        <div className="roul-count">
          <span className="roul-count-num">{filtered.length}</span>
          <span className="roul-count-label">
            recipe{filtered.length !== 1 ? 's' : ''} in the wheel
          </span>
          {!isDefault && (
            <button className="roul-clear" onClick={resetFilters}>Reset</button>
          )}
        </div>

        {/* ── Stage or empty ── */}
        {filtered.length < 1 ? (
          <div className="roul-empty">{emptyContent()}</div>
        ) : (
          <div className="roul-stage">
            <div className="wheel-wrap">
              <svg className="wheel-pointer" width="38" height="52" viewBox="0 0 38 52"
                   xmlns="http://www.w3.org/2000/svg">
                <path d="M19 50 C12 36 5 26 5 16 a14 13 0 0 1 28 0 c0 10 -7 20 -14 34z" fill="#241d12" />
                <path d="M19 45.5 C13.5 34 8.5 25.5 8.5 16.5 a10.5 10 0 0 1 21 0 c0 9 -5 17.5 -10.5 29z" fill="#1f4a38" />
                <circle cx="19" cy="15" r="5" fill="#c9922a" stroke="#8a6418" strokeWidth="1" />
                <circle cx="17.4" cy="13.4" r="1.5" fill="rgba(255,250,235,0.55)" />
              </svg>
              <WheelSVG
                slices={slices}
                rotation={rotation}
                isSpinning={isSpinning}
                winId={winId}
              />
            </div>
            <button
              className={`spin-btn${isSpinning ? ' is-spinning' : ''}`}
              onClick={spin}
              disabled={!canSpin}
            >
              <span className="spin-btn-inner">
                {isSpinning
                  ? <><span className="spin-dot" /><span className="spin-dot" /><span className="spin-dot" /> Spinning…</>
                  : 'Spin the Wheel'
                }
              </span>
            </button>
          </div>
        )}

        {/* ── Result ── */}
        {winner && (
          <ResultCard
            recipe={winner}
            onView={() => onOpenRecipe(winner.id)}
            onAgain={spin}
          />
        )}

      </div>
    );
  }

  Object.assign(window, { RouletteView });
})();
