// Penrose v4 — Story of the Day.
//
// Stories-style player: vertical, multi-frame, auto-progress, tap to skip,
// swipe down to close. Story content is deterministic by UTC date (hash
// of date → picks one of the test sujets in STORY_TEMPLATES).
//
// Each frame is a React component receiving { ctx } props + a static
// duration declared in the template. Only the active frame renders, so its
// hooks fire predictably on each render of that frame.

const { useState: useS, useEffect: useE, useRef: useR, useMemo: useM, useCallback: useCB } = React;

const frameCenter = {
  position: 'absolute', inset: 0,
  display: 'flex', alignItems: 'center', justifyContent: 'center',
  overflow: 'hidden',
};

// ─── Tiny Penrose preview (centered patch, decorative only) ─────────────
function StoryPatch({ size = 280, pattern = 0.5, highlightFigure = null, opacity = 1 }) {
  const tiles = useM(() => window.PenroseGeo.generateTiling({ radius: 7, pattern }), [pattern]);
  const C = window.PenrosePalettes.COLORS;
  const VFX = window.PenroseVFX;
  const cx = size / 2, cy = size / 2;
  const SC = size / 14;

  const highlightIds = useM(() => {
    if (!highlightFigure) return new Set();
    const ids = new Set();
    if (highlightFigure === 'Sun') {
      const suns = window.PenroseGeo.findSunPatterns(tiles) || [];
      for (const s of suns.slice(0, 1)) s.tileIds.forEach(id => ids.add(id));
    }
    return ids;
  }, [tiles, highlightFigure]);

  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}
         style={{ opacity, ...VFX.fadeInStyle({ duration: 480 }) }}>
      {tiles.map(t => {
        const isThick = t.type === 'thick';
        const fill = isThick ? C.thick : C.thin;
        const edge = isThick ? C.thickEdge : C.thinEdge;
        const hi = highlightIds.has(t.id);
        const path = t.verts.map((v, i) => (i === 0 ? 'M' : 'L') + (cx + v.x * SC) + ' ' + (cy - v.y * SC)).join(' ') + ' Z';
        return (
          <path key={t.id} d={path}
                fill={hi ? C.glow : fill}
                stroke={hi ? C.glow : edge}
                strokeWidth={hi ? 1.6 : 0.6}
                opacity={hi ? 1 : 0.65}
                style={hi ? VFX.glowPulseStyle({ color: C.glow, duration: 1600 }) : {}}
          />
        );
      })}
    </svg>
  );
}

// ─── Frame components ──────────────────────────────────────────────────

function IntroFrame({ ctx }) {
  const C = window.PenrosePalettes.COLORS;
  const VFX = window.PenroseVFX;
  return (
    <div style={frameCenter}>
      <StoryPatch size={300} pattern={ctx.pattern} opacity={0.55} />
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
                    alignItems: 'center', justifyContent: 'center', padding: 30,
                    background: `radial-gradient(ellipse at 50% 50%, ${C.bg}00, ${C.bg}cc 80%)` }}>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.44em',
                      color: C.textMuted, ...VFX.fadeInStyle({ duration: 420 }) }}>
          MOSAIC · {ctx.daily.date}
        </div>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 38, fontWeight: 700,
                      letterSpacing: '0.04em', color: C.text, marginTop: 18,
                      textShadow: `0 0 32px ${C.glow}55`, ...VFX.fadeInStyle({ duration: 520, delay: 120 }) }}>
          TODAY
        </div>
        <div style={{ fontSize: 13, color: C.textMuted, marginTop: 20, textAlign: 'center', lineHeight: 1.55,
                      maxWidth: 240, ...VFX.fadeInStyle({ duration: 520, delay: 280 }) }}>
          A unique aperiodic mosaic just for {ctx.daily.date}.
        </div>
      </div>
    </div>
  );
}

function SunsCountFrame({ ctx }) {
  const C = window.PenrosePalettes.COLORS;
  const big = useM(() => window.PenroseGeo.generateTiling({ radius: 10, pattern: ctx.pattern }), [ctx.pattern]);
  const suns = useM(() => (window.PenroseGeo.findSunPatterns(big) || []).length, [big]);

  const [shown, setShown] = useS(0);
  useE(() => {
    let n = 0;
    if (suns === 0) { setShown(0); return; }
    const step = Math.max(1, Math.round(suns / 24));
    const t = setInterval(() => {
      n = Math.min(suns, n + step);
      setShown(n);
      if (n >= suns) clearInterval(t);
    }, 40);
    return () => clearInterval(t);
  }, [suns]);

  return (
    <div style={frameCenter}>
      <StoryPatch size={280} pattern={ctx.pattern} highlightFigure="Sun" opacity={0.85} />
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
                    alignItems: 'center', justifyContent: 'flex-end', padding: '0 24px 80px' }}>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.44em',
                      color: C.textMuted }}>★ SUNS TODAY</div>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 84, fontWeight: 700,
                      color: C.glow, lineHeight: 1, marginTop: 10,
                      textShadow: `0 0 28px ${C.glow}88` }}>
          {shown}
        </div>
        <div style={{ fontSize: 12, color: C.textMuted, marginTop: 14, textAlign: 'center', maxWidth: 240, lineHeight: 1.5 }}>
          A Sun is five thick rhombi meeting at their pointy tips.
          Find every one — they hide in plain sight.
        </div>
      </div>
    </div>
  );
}

function PaletteRevealFrame({ ctx }) {
  const C = window.PenrosePalettes.COLORS;
  const VFX = window.PenroseVFX;
  const dailyP = window.PenrosePalettes.getDailyPalette(ctx.daily.date);
  return (
    <div style={frameCenter}>
      <div style={{ position: 'absolute', inset: 0, padding: '60px 30px 90px',
                    display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ textAlign: 'center', ...VFX.fadeInStyle({ duration: 420 }) }}>
          <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.44em',
                        color: C.textMuted }}>PALETTE OF THE DAY</div>
          <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 28, fontWeight: 700,
                        color: C.text, marginTop: 12, letterSpacing: '0.02em' }}>
            {dailyP.name}
          </div>
          <div style={{ fontSize: 12, color: C.textMuted, marginTop: 4, fontStyle: 'italic' }}>{dailyP.mood}</div>
        </div>
        <div style={{ display: 'flex', gap: 10, ...VFX.fadeInStyle({ duration: 520, delay: 200 }) }}>
          {['bg','thick','thin','glow','text'].map((k, i) => (
            <div key={k} style={{
              width: 44, height: 80, borderRadius: 8,
              background: dailyP.palette[k],
              border: '1px solid ' + (dailyP.palette.outlineStrong || 'rgba(0,0,0,0.2)'),
              boxShadow: '0 4px 14px ' + dailyP.palette[k] + '40',
              animation: `vfx-fill-pop 480ms cubic-bezier(0.18,0.89,0.32,1.28) ${120 + i*60}ms both`,
              transformOrigin: 'bottom',
            }} />
          ))}
        </div>
        <div style={{ fontSize: 12, color: C.textMuted, textAlign: 'center', maxWidth: 280, lineHeight: 1.55,
                      ...VFX.fadeInStyle({ duration: 520, delay: 400 }) }}>
          Tap the palette chip on Home to try this look across all of Penrose.
        </div>
      </div>
    </div>
  );
}

const FACTS = [
  { t: 'φ', h: 'THE GOLDEN RATIO', body: 'Every Penrose tiling hides φ ≈ 1.618. The ratio of thick to thin rhombi, as the tiling grows, approaches φ exactly.' },
  { t: '5', h: 'FIVE FAMILIES', body: 'A Penrose mosaic is made from five families of parallel lines, each rotated by 72°. The intersections become tiles.' },
  { t: '7', h: 'SEVEN FIGURES', body: 'Only seven kinds of vertex can exist: Sun, Star, Ace, Deuce, Jack, Queen, King. Anything else is geometrically forbidden.' },
  { t: '∞', h: 'NEVER REPEATS', body: 'No two patches in a Penrose tiling are ever exactly the same. The pattern is aperiodic — infinite, non-repeating, deterministic.' },
];

function GeometryFactFrame({ ctx, factIdx = 0 }) {
  const C = window.PenrosePalettes.COLORS;
  const VFX = window.PenroseVFX;
  // factIdx 0 = golden ratio — render the rich infographic instead of plain symbol.
  if (factIdx === 0) return <GoldenRatioFrame ctx={ctx} />;
  const fact = FACTS[factIdx % FACTS.length];
  return (
    <div style={frameCenter}>
      <div style={{ position: 'absolute', inset: 0, padding: '70px 32px 90px',
                    display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 180, fontWeight: 700,
                      color: C.glow, lineHeight: 1,
                      textShadow: `0 0 40px ${C.glow}88`,
                      ...VFX.fadeInStyle({ duration: 520 }) }}>
          {fact.t}
        </div>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, letterSpacing: '0.32em',
                      color: C.textMuted, marginTop: 8, ...VFX.fadeInStyle({ duration: 520, delay: 160 }) }}>
          {fact.h}
        </div>
        <div style={{ fontSize: 13, color: C.text, marginTop: 24, textAlign: 'center', maxWidth: 280, lineHeight: 1.6,
                      ...VFX.fadeInStyle({ duration: 520, delay: 320 }) }}>
          {fact.body}
        </div>
      </div>
    </div>
  );
}

// ─── Golden Ratio infographic — animated thick/thin bar chart + SVG spiral ──
function GoldenRatioFrame({ ctx }) {
  const C = window.PenrosePalettes.COLORS;
  const VFX = window.PenroseVFX;

  const tiles = useM(
    () => window.PenroseGeo.generateTiling({ radius: 9, pattern: ctx.pattern }),
    [ctx.pattern],
  );
  const thickCount = useM(() => tiles.filter(t => t.type === 'thick').length, [tiles]);
  const thinCount  = useM(() => tiles.filter(t => t.type === 'thin').length,  [tiles]);
  const target = thinCount > 0 ? thickCount / thinCount : 1.618;

  // Animate the ratio counter from 1.000 → actual value.
  const [displayRatio, setDisplayRatio] = useS(1.0);
  useE(() => {
    let raf;
    let start = null;
    function step(ts) {
      if (!start) start = ts;
      const p = Math.min(1, (ts - start) / 2200);
      const e = 1 - Math.pow(1 - p, 3);
      setDisplayRatio(1.0 + (target - 1.0) * e);
      if (p < 1) raf = requestAnimationFrame(step);
    }
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [target]);

  // Animate bar heights from 0 → 1.
  const [progress, setProgress] = useS(0);
  useE(() => {
    let raf;
    let start = null;
    function step(ts) {
      if (!start) start = ts;
      const p = Math.min(1, (ts - start) / 1400);
      const e = 1 - Math.pow(1 - p, 2.5);
      setProgress(e);
      if (p < 1) raf = requestAnimationFrame(step);
    }
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, []);

  const total   = thickCount + thinCount;
  const MAX_BAR = 110;
  const thickH  = total > 0 ? (thickCount / total) * MAX_BAR * progress : 0;
  const thinH   = total > 0 ? (thinCount  / total) * MAX_BAR * progress : 0;
  const BAR_W   = 48;

  // Golden-spiral SVG (6 nested quarter-arcs, stroke-dasharray animated via CSS).
  // Bounding box: 180 × 111 (φ ratio). Each level is a square cut from the longer side.
  const W = 180, H = 111;
  // arc segments: [cx, cy, r, startAngle_deg, endAngle_deg]
  // building the spiral: square 0 = H×H (left), rect 1 = (W-H)×H right ...
  // Precomputed for W=180, H=111:
  //  s0: 111×111, leftover 69×111
  //  s1: 69×69   (bottom-right of leftover), leftover 69×42
  //  s2: 42×42   (top of leftover), leftover 27×42
  //  s3: 27×27   (right of leftover), leftover 27×15
  //  s4: 15×15   (bottom-left), leftover 12×15
  const spiralArcs = [
    // cx, cy, r,   a0,  a1   (angles: 0=right, 90=down, etc., SVG coords)
    [111,   0, 111, 270, 180], // s0: center top-right of square, sweeps from 270→180 (counter-ccw = from top to left)
    [111, 111,  69,   0, 270], // s1
    [111,  42,  42,  90,   0], // s2
    [153,  42,  27, 180,  90], // s3
    [153,  69,  15, 270, 180], // s4
    [138,  69,   9,   0, 270], // s5
  ];

  function arcPath(cx, cy, r, a0, a1) {
    const rad = d => d * Math.PI / 180;
    const x0 = cx + r * Math.cos(rad(a0));
    const y0 = cy + r * Math.sin(rad(a0));
    const x1 = cx + r * Math.cos(rad(a1));
    const y1 = cy + r * Math.sin(rad(a1));
    // Large arc flag: 1 if sweep > 180 degrees going counterclockwise
    // We always sweep 90° counterclockwise in Euclidean, but SVG is clockwise by default.
    // Sweep-flag=0 means counterclockwise (in SVG y-down coords, this goes the right way).
    return `M ${x0.toFixed(1)} ${y0.toFixed(1)} A ${r} ${r} 0 0 0 ${x1.toFixed(1)} ${y1.toFixed(1)}`;
  }

  return (
    <div style={frameCenter}>
      {/* Ghost φ background */}
      <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center',
                    justifyContent: 'center', pointerEvents: 'none' }}>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 260, fontWeight: 700,
                      color: C.glow, opacity: 0.055, lineHeight: 1, userSelect: 'none' }}>φ</div>
      </div>

      <div style={{ position: 'absolute', inset: 0, padding: '52px 28px 60px',
                    display: 'flex', flexDirection: 'column', alignItems: 'center',
                    justifyContent: 'space-between', gap: 0 }}>

        {/* Kicker */}
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.44em',
                      color: C.textMuted, ...VFX.fadeInStyle({ duration: 420 }) }}>
          THE GOLDEN RATIO
        </div>

        {/* Golden spiral SVG */}
        <div style={{ ...VFX.fadeInStyle({ duration: 600, delay: 160 }) }}>
          <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`}
               style={{ overflow: 'visible', display: 'block' }}>
            {/* Rectangle outlines */}
            <rect x={0}   y={0}   width={111} height={111} fill="none"
                  stroke={C.thick} strokeWidth="0.7" opacity="0.25" />
            <rect x={111} y={0}   width={69}  height={111} fill="none"
                  stroke={C.thin}  strokeWidth="0.7" opacity="0.25" />
            <rect x={111} y={42}  width={69}  height={69}  fill="none"
                  stroke={C.thick} strokeWidth="0.5" opacity="0.18" />
            <rect x={111} y={0}   width={42}  height={42}  fill="none"
                  stroke={C.thin}  strokeWidth="0.5" opacity="0.18" />
            <rect x={153} y={0}   width={27}  height={42}  fill="none"
                  stroke={C.thick} strokeWidth="0.4" opacity="0.14" />
            {/* Spiral arcs */}
            {spiralArcs.map(([cx, cy, r, a0, a1], i) => (
              <path key={i} d={arcPath(cx, cy, r, a0, a1)}
                    fill="none"
                    stroke={C.glow}
                    strokeWidth={2.2 - i * 0.28}
                    opacity={1 - i * 0.1}
                    style={{
                      strokeDasharray: `${2 * Math.PI * r * 0.25}`,
                      strokeDashoffset: progress < 1 ? `${2 * Math.PI * r * 0.25 * (1 - progress)}` : '0',
                      transition: `stroke-dashoffset ${0.4 + i * 0.18}s ease-out ${0.1 + i * 0.14}s`,
                    }} />
            ))}
            {/* φ label at the end of the spiral */}
            <text x="148" y="62"
                  fontFamily="JetBrains Mono, monospace" fontSize="10"
                  fill={C.glow} opacity={Math.min(1, progress * 2)}
                  textAnchor="middle">φ</text>
          </svg>
        </div>

        {/* Bar chart: THICK / ratio / THIN */}
        <div style={{ display: 'flex', gap: 28, alignItems: 'flex-end',
                      ...VFX.fadeInStyle({ duration: 520, delay: 300 }) }}>

          {/* THICK bar */}
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 }}>
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 9,
                          letterSpacing: '0.2em', color: C.textMuted }}>{thickCount}</div>
            <div style={{ width: BAR_W, height: Math.max(4, thickH),
                          background: `linear-gradient(180deg, ${C.thick}bb, ${C.thick})`,
                          borderRadius: '4px 4px 0 0',
                          boxShadow: `0 0 18px ${C.thick}44` }} />
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 8,
                          letterSpacing: '0.18em', color: C.textDim }}>THICK</div>
          </div>

          {/* Ratio counter */}
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center',
                        paddingBottom: 20, gap: 2 }}>
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 20, fontWeight: 700,
                          color: C.glow, letterSpacing: '0.04em', lineHeight: 1 }}>
              {displayRatio.toFixed(3)}
            </div>
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 8,
                          letterSpacing: '0.2em', color: C.textMuted }}>÷ → φ</div>
          </div>

          {/* THIN bar */}
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 }}>
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 9,
                          letterSpacing: '0.2em', color: C.textMuted }}>{thinCount}</div>
            <div style={{ width: BAR_W, height: Math.max(4, thinH),
                          background: `linear-gradient(180deg, ${C.thin}bb, ${C.thin})`,
                          borderRadius: '4px 4px 0 0',
                          boxShadow: `0 0 18px ${C.thin}44` }} />
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 8,
                          letterSpacing: '0.18em', color: C.textDim }}>THIN</div>
          </div>
        </div>

        {/* Bottom body text */}
        <div style={{ fontSize: 12, color: C.textMuted, textAlign: 'center',
                      maxWidth: 272, lineHeight: 1.6,
                      ...VFX.fadeInStyle({ duration: 520, delay: 480 }) }}>
          Every Penrose tiling converges to exactly{' '}
          <span style={{ color: C.text }}>φ ≈ 1.618</span>. Today:{' '}
          <span style={{ color: C.text }}>{thickCount} thick ÷ {thinCount} thin
          = {target.toFixed(3)}</span>.
        </div>
      </div>
    </div>
  );
}

function CtaObjectFrame({ ctx }) {
  const C = window.PenrosePalettes.COLORS;
  const VFX = window.PenroseVFX;
  return (
    <div style={frameCenter}>
      <StoryPatch size={300} pattern={ctx.pattern + 0.13} opacity={0.35} />
      <div style={{ position: 'absolute', inset: 0, padding: '0 30px 90px',
                    display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', alignItems: 'center',
                    background: `radial-gradient(ellipse at 50% 50%, ${C.bg}00, ${C.bg}dd 70%)` }}>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.44em',
                      color: C.textMuted, ...VFX.fadeInStyle({ duration: 420 }) }}>NOW TOUCH IT</div>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 26, fontWeight: 700,
                      color: C.text, marginTop: 10, letterSpacing: '0.02em', textAlign: 'center',
                      ...VFX.fadeInStyle({ duration: 520, delay: 120 }) }}>
          Open today's<br />reset.
        </div>
        <div style={{ fontSize: 12, color: C.textMuted, marginTop: 14, textAlign: 'center', maxWidth: 260, lineHeight: 1.55,
                      ...VFX.fadeInStyle({ duration: 520, delay: 240 }) }}>
          A living object of the day. Tap, drag, hold, then save the state.
        </div>
        <div onClick={(e) => { e.stopPropagation(); ctx.openObject(); }} style={{
          marginTop: 26, padding: '14px 30px', borderRadius: 999,
          border: '1px solid ' + C.glow,
          background: C.glow + '14',
          color: C.text, fontFamily: 'JetBrains Mono, monospace', fontSize: 11,
          letterSpacing: '0.32em', cursor: 'pointer', fontWeight: 700,
          boxShadow: '0 0 26px ' + C.glow + '40',
          ...VFX.fadeInStyle({ duration: 520, delay: 360 }),
        }}>
          OPEN RESET →
        </div>
      </div>
    </div>
  );
}

// ─── Story templates ────────────────────────────────────────────────────
// Each frame is { Comp, props, durationMs }. Comp gets ctx + props.

const STORY_TEMPLATES = [
  {
    id: 'suns-today',
    title: 'Suns Today',
    frames: [
      { Comp: IntroFrame, durationMs: 3200 },
      { Comp: SunsCountFrame, durationMs: 4200 },
      { Comp: GeometryFactFrame, props: { factIdx: 2 }, durationMs: 5200 },
      { Comp: CtaObjectFrame, durationMs: 5000 },
    ],
  },
  {
    id: 'palette',
    title: 'Palette of the Day',
    frames: [
      { Comp: IntroFrame, durationMs: 3200 },
      { Comp: PaletteRevealFrame, durationMs: 4000 },
      { Comp: GeometryFactFrame, props: { factIdx: 0 }, durationMs: 5200 },
      { Comp: CtaObjectFrame, durationMs: 5000 },
    ],
  },
  {
    id: 'never-repeats',
    title: 'Never Repeats',
    frames: [
      { Comp: IntroFrame, durationMs: 3200 },
      { Comp: GeometryFactFrame, props: { factIdx: 3 }, durationMs: 5200 },
      { Comp: SunsCountFrame, durationMs: 4200 },
      { Comp: CtaObjectFrame, durationMs: 5000 },
    ],
  },
  {
    id: 'five-families',
    title: 'Five Families',
    frames: [
      { Comp: IntroFrame, durationMs: 3200 },
      { Comp: GeometryFactFrame, props: { factIdx: 1 }, durationMs: 5200 },
      { Comp: PaletteRevealFrame, durationMs: 4000 },
      { Comp: CtaObjectFrame, durationMs: 5000 },
    ],
  },
  {
    id: 'golden',
    title: 'Golden Ratio',
    frames: [
      { Comp: IntroFrame, durationMs: 3200 },
      { Comp: GeometryFactFrame, props: { factIdx: 0 }, durationMs: 5200 },
      { Comp: SunsCountFrame, durationMs: 4200 },
      { Comp: CtaObjectFrame, durationMs: 5000 },
    ],
  },
];

function hashDate(s) {
  let h = 2166136261 >>> 0;
  for (let i = 0; i < s.length; i++) {
    h ^= s.charCodeAt(i);
    h = Math.imul(h, 16777619) >>> 0;
  }
  return h;
}

function pickTodaysTemplate(dateStr) {
  return STORY_TEMPLATES[hashDate(dateStr) % STORY_TEMPLATES.length];
}

// ─── Player ────────────────────────────────────────────────────────────

function StoryScreen({ goto, daily, progress, onSeen }) {
  const C = window.PenrosePalettes.COLORS;
  const template = useM(() => pickTodaysTemplate(daily.date), [daily.date]);

  const ctx = useM(() => ({
    daily,
    pattern: 0.42 + (hashDate(daily.date) % 100) / 200,
    openObject: () => { onSeen(); goto('object'); },
  }), [daily, goto, onSeen]);

  const [idx, setIdx] = useS(0);
  const [paused, setPaused] = useS(false);
  const endedRef = useR(false);

  const finish = useCB(() => {
    if (endedRef.current) return;
    endedRef.current = true;
    onSeen();
    goto('home');
  }, [onSeen, goto]);

  const advance = useCB((delta) => {
    setIdx(i => {
      const n = i + delta;
      if (n < 0) return 0;
      if (n >= template.frames.length) return i; // finish handled by effect
      return n;
    });
    // If forward-past-end → finish
    if (delta > 0 && idx >= template.frames.length - 1) finish();
  }, [idx, template.frames.length, finish]);

  useE(() => {
    if (paused) return;
    const dur = template.frames[idx]?.durationMs || 4000;
    const t = setTimeout(() => {
      if (idx >= template.frames.length - 1) finish();
      else setIdx(i => i + 1);
    }, dur);
    return () => clearTimeout(t);
  }, [idx, paused, template, finish]);

  const startY = useR(0);
  const onPointerDown = (e) => { startY.current = e.clientY; setPaused(true); };
  const onPointerUp = (e) => {
    setPaused(false);
    const dy = e.clientY - startY.current;
    if (dy > 80) { onSeen(); goto('home'); }
  };

  const onTap = (e) => {
    const r = e.currentTarget.getBoundingClientRect();
    const x = e.clientX - r.left;
    advance(x < r.width / 3 ? -1 : 1);
  };

  const Active = template.frames[idx].Comp;
  const activeProps = template.frames[idx].props || {};

  return (
    <div onPointerDown={onPointerDown} onPointerUp={onPointerUp} onClick={onTap}
         style={{ position: 'absolute', inset: 0, background: C.bg, color: C.text, overflow: 'hidden',
                  userSelect: 'none', touchAction: 'none' }}>
      {/* Progress bars */}
      <div style={{ position: 'absolute', top: 12, left: 12, right: 12, zIndex: 10,
                    display: 'flex', gap: 4 }}>
        {template.frames.map((f, i) => (
          <div key={i} style={{ flex: 1, height: 2, background: C.outline, borderRadius: 1, overflow: 'hidden' }}>
            <div style={{
              height: '100%', background: C.text, transformOrigin: 'left',
              transform: i < idx ? 'scaleX(1)' : i === idx ? undefined : 'scaleX(0)',
              animation: i === idx && !paused ? `vfx-progress ${f.durationMs}ms linear` : 'none',
            }} />
          </div>
        ))}
      </div>

      {/* Close button */}
      <div onClick={(e) => { e.stopPropagation(); onSeen(); goto('home'); }}
           style={{ position: 'absolute', top: 26, right: 18, zIndex: 12,
                    width: 32, height: 32, borderRadius: 16,
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    background: 'rgba(0,0,0,0.25)', cursor: 'pointer',
                    fontFamily: 'JetBrains Mono, monospace', fontSize: 16, color: C.text }}>×</div>

      {/* Story label */}
      <div style={{ position: 'absolute', top: 26, left: 18, zIndex: 12,
                    fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.32em',
                    color: C.textMuted, pointerEvents: 'none' }}>
        {template.title.toUpperCase()} · {idx + 1}/{template.frames.length}
      </div>

      {/* Current frame */}
      <div key={idx} style={{ position: 'absolute', inset: 0 }}>
        <Active ctx={ctx} {...activeProps} />
      </div>
    </div>
  );
}

window.PenroseStories = {
  StoryScreen,
  templates: STORY_TEMPLATES,
  pickTodaysTemplate,
};
