/* =============================================================================
   SheetHead — the finale stage (Tournament champion + end of a normal game)
   One shared piece of presentation: the winner's avatar raises a golden trophy under a spotlight, and every "loser" figure
   gets a cartoon poop-head dropped on it (the SheetHead joke). It only visualises a result that the engine / tournament layer
   already decided; it never computes one. Pixi (fx.Celebration) adds rays, fireworks and splat particles when available; the
   whole scene is also complete with CSS alone (no WebGL, reduced motion). Everything it starts (Pixi app, timers) is torn
   down on unmount. Exposes window.SH.ui.Finale.
============================================================================= */
(function () {
  const { useEffect, useRef } = React;
  const PR = window.SH.presenter;
  const { cx } = window.SH.ui;

  // ---- art -------------------------------------------------------------------------------------------------------
  function Trophy() {
    return (
      <svg className="fig-trophy" viewBox="0 0 100 120" aria-hidden="true" data-testid="finale-trophy">
        <defs>
          <linearGradient id="trG" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#fff2b0" /><stop offset=".45" stopColor="#f1bf3c" /><stop offset="1" stopColor="#b7791a" /></linearGradient>
        </defs>
        <path d="M22 10h56v30c0 22-12 34-28 38C34 74 22 62 22 40z" fill="url(#trG)" stroke="#7a4a08" strokeWidth="3" strokeLinejoin="round" />
        <path d="M22 18H9c-3 22 5 38 24 42M78 18h13c3 22-5 38-24 42" fill="none" stroke="#d99a22" strokeWidth="7" strokeLinecap="round" />
        <path d="M46 78h8v16h-8z" fill="url(#trG)" stroke="#7a4a08" strokeWidth="3" strokeLinejoin="round" />
        <path d="M30 96h40l4 14H26z" fill="#8a5a12" stroke="#5a3606" strokeWidth="3" strokeLinejoin="round" />
        <path d="M50 24l5.2 10.6 11.6 1.7-8.4 8.2 2 11.6L50 50.6 39.6 56l2-11.6-8.4-8.2 11.6-1.7z" fill="#fff8d6" opacity=".92" />
        <path d="M30 16c-2 14 1 26 8 34" fill="none" stroke="#fff" strokeWidth="3.4" strokeLinecap="round" opacity=".55" />
      </svg>
    );
  }

  // Cute, cartoon-y (not gross): a soft-serve swirl with a sheepish face, sitting on the loser's head.
  function PoopHat({ uid }) {
    return (
      <svg className="poop-svg" viewBox="0 0 100 96" aria-hidden="true">
        <defs>
          <linearGradient id={'pg' + uid} x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#a9713a" /><stop offset="1" stopColor="#5e3a17" /></linearGradient>
        </defs>
        <path className="stink s1" d="M30 14c-6-5 6-8 0-14M50 12c-6-5 6-8 0-14M70 14c-6-5 6-8 0-14" fill="none" stroke="#8fcf4a" strokeWidth="2.6" strokeLinecap="round" />
        <path d="M11 82c-3-14 12-22 39-22s42 8 39 22c-3 11-19 13-39 13S14 93 11 82z" fill={'url(#pg' + uid + ')'} stroke="#4a2a0d" strokeWidth="2.6" />
        <path d="M22 62c-3-12 9-20 28-20s31 8 28 20c-8 5-48 5-56 0z" fill={'url(#pg' + uid + ')'} stroke="#4a2a0d" strokeWidth="2.6" />
        <path d="M34 44c-2-10 6-17 16-17s18 7 16 17c-6 4-26 4-32 0z" fill={'url(#pg' + uid + ')'} stroke="#4a2a0d" strokeWidth="2.6" />
        <path d="M50 27c-8-3-8-13 2-19-1 7 6 10 4 19z" fill={'url(#pg' + uid + ')'} stroke="#4a2a0d" strokeWidth="2.6" strokeLinejoin="round" />
        <path d="M22 76c4-3 8-4 12-4M30 56c3-2 6-3 10-3M40 39c2-1 5-2 8-2" fill="none" stroke="#e2b57a" strokeWidth="3" strokeLinecap="round" opacity=".7" />
        <circle cx="38" cy="76" r="7.4" fill="#fff" stroke="#3a210a" strokeWidth="2" /><circle cx="62" cy="76" r="7.4" fill="#fff" stroke="#3a210a" strokeWidth="2" />
        <circle cx="36" cy="78" r="3.4" fill="#1d1208" /><circle cx="60" cy="78" r="3.4" fill="#1d1208" />
        <path d="M31 66l12 3M69 66l-12 3" stroke="#3a210a" strokeWidth="2.6" strokeLinecap="round" />
        <path d="M40 87q10 6 20 0" fill="none" stroke="#3a210a" strokeWidth="2.8" strokeLinecap="round" />
      </svg>
    );
  }

  // ---- one figure --------------------------------------------------------------------------------------------------
  function Figure({ f, index, landMs }) {
    const av = PR.avatarFor({ seat: f.seat });
    const win = f.role === 'winner';
    const dl = win ? 0.35 : 1.4 + index * 0.5;
    return (
      <div className={cx('fig', win ? 'winner' : 'loser', f.isYou && 'you')} data-seat={f.seat} data-role={f.role} data-testid={win ? 'finale-winner' : 'finale-loser'}
           style={{ '--hue': av.hue, '--dl': dl + 's' }}>
        <div className="fig-art">
          {win && (
            <svg className="fig-arms" viewBox="0 0 200 200" aria-hidden="true">
              <path d="M58 150C34 130 40 96 66 66M142 150c24-20 18-54-8-84" fill="none" stroke="#2a1a14" strokeWidth="19" strokeLinecap="round" />
              <path d="M58 150C34 130 40 96 66 66M142 150c24-20 18-54-8-84" fill="none" style={{ stroke: 'hsl(var(--hue) 55% 62%)' }} strokeWidth="12" strokeLinecap="round" />
              <circle cx="66" cy="62" r="11" fill="#fff" stroke="#2a1a14" strokeWidth="3" /><circle cx="134" cy="62" r="11" fill="#fff" stroke="#2a1a14" strokeWidth="3" />
            </svg>
          )}
          <div className="fig-avatar" data-delay={landMs} aria-hidden="true">{av.glyph}</div>
          {win && <div className="fig-lift"><Trophy /></div>}
          {win && <div className="fig-sparkles" aria-hidden="true"><i /><i /><i /><i /><i /></div>}
          {!win && <div className="fig-poop" data-testid="finale-poop"><PoopHat uid={f.seat} /></div>}
          {!win && <div className="fig-drips" aria-hidden="true"><i /><i /><i /></div>}
        </div>
        <div className="fig-plate">
          <b>{f.isYou ? f.name + ' (you)' : f.name}</b>
          <span className={cx('fig-tag', win ? 'gold' : 'brown')}>{f.tag}</span>
          {!win && <span className="fig-smear" aria-hidden="true" />}
        </div>
      </div>
    );
  }

  // ---- the stage --------------------------------------------------------------------------------------------------
  // figures: [{ seat, name, isYou, role: 'winner' | 'loser', tag }]. Winners first in the array is not required.
  function Finale({ figures, settings, kicker, caption, id }) {
    const s = settings || {};
    const rm = !!s.reducedMotion || s.animations === false;
    const gl = useRef(null), root = useRef(null);
    const winners = figures.filter(f => f.role === 'winner'), losers = figures.filter(f => f.role === 'loser');
    const key = figures.map(f => f.seat + f.role).join('|');
    const landMs = (i) => Math.round((1.4 + i * 0.5 + 0.56) * 1000);

    useEffect(() => {
      const F = window.SH.fx;
      if (!F || !F.Celebration || !gl.current) return undefined;
      F.configure({ quality: s.quality || 'auto', reducedMotion: rm, enabled: s.fx !== false });
      const cfg = F.resolve();
      if (!cfg.enabled || cfg.reducedMotion || !F.available()) return undefined;
      let cel = null, dead = false; const timers = []; const t0 = performance.now();
      const rel = (el) => { const h = gl.current.getBoundingClientRect(), r = el.getBoundingClientRect(); return { x: r.left - h.left + r.width / 2, y: r.top - h.top + r.height / 2, w: r.width, h: r.height, hw: h.width, hh: h.height }; };
      const at = (ms, fn) => timers.push(setTimeout(() => { if (!dead && cel) fn(); }, Math.max(0, ms - (performance.now() - t0))));
      F.Celebration.create(gl.current, { focus: { x: 0.5, y: 0.35 } }).then((x) => {
        if (dead) { x.destroy(); return; }
        cel = x;
        const w = root.current && root.current.querySelector('[data-role="winner"] .fig-avatar');
        if (w) { const p = rel(w); cel.setFocus(p.x / p.hw, (p.y - p.h * 0.3) / p.hh); at(1100, () => { const q = rel(w); cel.burst(q.x, q.y - q.h * 0.8, 0xf6dc9a); }); }
        (root.current ? Array.from(root.current.querySelectorAll('[data-role="loser"] .fig-avatar')) : []).forEach((el) => {
          at(+el.dataset.delay || 2000, () => { const p = rel(el); cel.splat(p.x, p.y - p.h * 0.25); });
        });
      }).catch(() => { /* the CSS scene stands on its own */ });
      return () => { dead = true; timers.forEach(clearTimeout); if (cel) cel.destroy(); };
    }, [key, rm]);

    return (
      <div ref={root} className={cx('finale', rm && 'rm')} id={id} data-testid="finale" data-winners={winners.map(f => f.seat).join(',')} data-losers={losers.map(f => f.seat).join(',')}>
        <div className="finale-spot" aria-hidden="true" />
        {kicker && <div className="finale-kicker">{kicker}</div>}
        <div className={cx('finale-body', winners.length === 1 && losers.length === 1 && 'duel')}>
          <div className="finale-row win">{winners.map((f, i) => <Figure key={f.seat} f={f} index={i} />)}</div>
          <div className={cx('finale-row lose', 'n' + losers.length)}>{losers.map((f, i) => <Figure key={f.seat} f={f} index={i} landMs={landMs(i)} />)}</div>
        </div>
        {caption && <div className="finale-caption">{caption}</div>}
        <div className="finale-gl" ref={gl} aria-hidden="true" />
      </div>
    );
  }

  window.SH.ui.Finale = Finale;
})();
