// ow-splash.jsx — OnWeight app launch splash (dark).
// Choreography: on a dark stage the boxing mark MAKES WEIGHT on the scale, fires a
// quick combo, throws its arms up into the victory "W" (which IS the OnWeight mark).
// Then it branches on journey:
//   first-run  → the mark eases up + settles as the brand lockup; ONWEIGHT wordmark,
//                tagline and CTAs resolve on the dark launch screen.
//   returning  → the app just opens: the Dashboard fades straight in over the win.
//
// Renders inside a fixed 393×852 device viewport. Self-clocked via rAF; replays on
// mount and whenever a tweak changes.
(function () {
  const clamp = (x, a = 0, b = 1) => Math.max(a, Math.min(b, x));
  const lerp = (a, b, t) => a + (b - a) * t;
  const eio = (t) => (t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1); // easeInOutCubic
  const eo = (t) => 1 - Math.pow(1 - t, 3); // easeOutCubic

  const DARK = '#16140f';        // launch + hero stage
  const CREAM = '#f4efe6';
  const INK = '#15140f';
  const MUTE = 'rgba(244,239,230,0.62)';

  // Device metrics (393 × 852)
  const DW = 393, DH = 852;
  const CX = DW / 2;
  const HERO_CY = 392, MK_HERO = 230;        // hero: big, low-centre
  const LAUNCH_CY = 300, MK_LAUNCH = 150;    // launch lockup: large mark, upper third

  // Timeline (seconds, at speed 1) — calm, deliberate pacing
  const SEG = { make: 1.95, hold: 0.5, fight: 2.0, win: 0.95, settle: 1.05, reveal: 1.35 };
  function bounds(speed) {
    const k = 1 / Math.max(0.4, speed);
    const m = {};
    let t = 0;
    m.m0 = t; t += SEG.make * k; m.m1 = t; t += SEG.hold * k; m.m2 = t;
    t += SEG.fight * k; m.m3 = t; t += SEG.win * k; m.m4 = t;
    t += SEG.settle * k; m.m5 = t; t += SEG.reveal * k; m.m6 = t;
    return m;
  }

  // ── status bar (cream, for the dark stage) ─────────────────────────────────
  function StatusBar({ color }) {
    return (
      <div style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 54, display: 'flex',
        alignItems: 'center', justifyContent: 'space-between', padding: '0 30px 0 34px', zIndex: 30,
        pointerEvents: 'none' }}>
        <span style={{ fontFamily: 'var(--sans)', fontSize: 15.5, fontWeight: 600, color, letterSpacing: '0.01em' }}>9:41</span>
        <span style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
          <svg width="18" height="11" viewBox="0 0 18 11" fill="none"><rect x="0" y="7" width="3" height="4" rx="1" fill={color}/><rect x="5" y="4.5" width="3" height="6.5" rx="1" fill={color}/><rect x="10" y="2" width="3" height="9" rx="1" fill={color}/><rect x="15" y="0" width="3" height="11" rx="1" fill={color} opacity="0.4"/></svg>
          <svg width="16" height="11" viewBox="0 0 16 11" fill="none"><path d="M8 2.4c2.1 0 4 .8 5.4 2.2l1.4-1.5A10 10 0 0 0 8 .2 10 10 0 0 0 1.2 3.1l1.4 1.5A7.6 7.6 0 0 1 8 2.4Z" fill={color}/><path d="M8 6c1 0 1.9.4 2.6 1.1l1.4-1.5A6 6 0 0 0 8 4a6 6 0 0 0-4 1.6l1.4 1.5A3.8 3.8 0 0 1 8 6Z" fill={color}/><circle cx="8" cy="9.4" r="1.5" fill={color}/></svg>
          <svg width="25" height="12" viewBox="0 0 25 12" fill="none"><rect x="0.5" y="0.5" width="21" height="11" rx="3" stroke={color} opacity="0.45"/><rect x="2" y="2" width="17" height="8" rx="1.5" fill={color}/><rect x="23" y="3.5" width="1.6" height="5" rx="0.8" fill={color} opacity="0.6"/></svg>
        </span>
      </div>
    );
  }

  // ── dark launch screen content (centred lockup beneath the settled mark) ────
  function LaunchContent({ wordOp, wordY, tagOp, btnOp }) {
    return (
      <div style={{ position: 'absolute', inset: 0, zIndex: 5 }}>
        <div style={{ position: 'absolute', left: 0, right: 0, top: LAUNCH_CY + MK_LAUNCH / 2 + 24,
          textAlign: 'center', padding: '0 28px' }}>
          <div style={{ fontFamily: 'var(--display)', fontSize: 46, fontWeight: 700, textTransform: 'uppercase',
            letterSpacing: '0.03em', lineHeight: 1, color: CREAM, opacity: wordOp,
            transform: `translateY(${wordY}px)` }}>OnWeight</div>
          <div style={{ fontFamily: 'var(--sans)', fontSize: 16.5, color: MUTE, marginTop: 15,
            lineHeight: 1.45, maxWidth: '24ch', marginLeft: 'auto', marginRight: 'auto',
            opacity: tagOp, transform: `translateY(${wordY * 0.6}px)` }}>Make weight.<br />Stay sharp.<br />Every camp.</div>
        </div>
        <div style={{ position: 'absolute', left: 32, right: 32, bottom: 60, display: 'flex',
          flexDirection: 'column', gap: 10, alignItems: 'center', opacity: btnOp,
          transform: `translateY(${(1 - btnOp) * 16}px)` }}>
          <button style={{ width: '100%', background: CREAM, color: INK, border: 'none', borderRadius: 13,
            minHeight: 54, fontFamily: 'var(--display)', fontSize: 14, letterSpacing: '0.14em', fontWeight: 600,
            textTransform: 'uppercase' }}>Lock In</button>
          <button style={{ width: '100%', background: 'transparent', color: MUTE, border: 'none', minHeight: 44,
            fontFamily: 'var(--sans)', fontSize: 15, fontWeight: 500 }}>I already have an account</button>
        </div>
      </div>
    );
  }

  function Splash({ journey = 'firstrun', sport = 'boxing', speed = 1, accent = '#a32a18',
                    paceKey = 'onTrack', nonce = 0 }) {
    const [tRaw, setT] = React.useState(0);
    const [, force] = React.useReducer((x) => x + 1, 0);
    const m = React.useMemo(() => bounds(speed), [speed]);
    const isFirst = journey === 'firstrun';

    React.useEffect(() => {
      let raf, start = null;
      const step = (ts) => {
        if (start == null) start = ts;
        const s = (ts - start) / 1000;
        setT(s);
        if (s < m.m6 + 0.2) raf = requestAnimationFrame(step);
        else setT(m.m6);
      };
      raf = requestAnimationFrame(step);
      return () => raf && cancelAnimationFrame(raf);
    }, [m, nonce, journey, sport, accent, paceKey]);

    // inert debug hooks (no effect unless called) — scrub the timeline deterministically
    React.useEffect(() => {
      window.__owSplashSeek = (s) => { window.__OW_SPLASH_FROZEN = s; force(); };
      window.__owSplashPlay = () => { window.__OW_SPLASH_FROZEN = null; force(); };
    }, []);
    const t = (typeof window.__OW_SPLASH_FROZEN === 'number') ? window.__OW_SPLASH_FROZEN : tRaw;

    // ── animation frame f (drives the OWScene pose) ──
    let f;
    if (t < m.m1) f = lerp(0.44, 0.566, eio(clamp((t - m.m0) / (m.m1 - m.m0))));
    else if (t < m.m2) f = 0.566 + 0.004 * Math.sin(t * 6);
    else if (t < m.m3) f = lerp(0.575, 0.94, eio(clamp((t - m.m2) / (m.m3 - m.m2))));
    else f = 0.94 + 0.004 * Math.sin(t * 3.6); // settled victory W ≈ the logo, faint breath

    // ── settle (mark eases up + shrinks to the lockup) + reveal ──
    const pSet = eio(clamp((t - m.m4) / (m.m5 - m.m4)));
    const cy = isFirst ? lerp(HERO_CY, LAUNCH_CY, pSet) : HERO_CY;
    const mk = isFirst ? lerp(MK_HERO, MK_LAUNCH, pSet) : MK_HERO;

    const wordOp = isFirst ? clamp((t - (m.m5 - 0.2)) / 0.6) : 0;
    const wordY = lerp(18, 0, eo(wordOp));
    const tagOp = isFirst ? clamp((t - (m.m5 + 0.02)) / 0.6) : 0;
    const btnOp = isFirst ? clamp((t - (m.m5 + 0.22)) / 0.6) : 0;
    // returning: the app just opens — Dashboard fades straight in over the win
    const dashOp = !isFirst ? eio(clamp((t - (m.m4 + 0.12)) / (m.m5 - m.m4 + 0.25))) : 0;

    const Scene = window.OWScene;
    const Dashboard = window.Dashboard;

    return (
      <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', background: DARK }}>
        {/* dark launch content (first-run only) */}
        {isFirst && <LaunchContent wordOp={wordOp} wordY={wordY} tagOp={tagOp} btnOp={btnOp} />}

        {/* status bar */}
        <StatusBar color={CREAM} />

        {/* the animated → settled OnWeight mark */}
        <div style={{ position: 'absolute', left: CX, top: cy, width: 0, height: 0, zIndex: 20,
          pointerEvents: 'none' }}>
          <div style={{ position: 'absolute', left: -mk / 2, top: -mk / 2, width: mk, height: mk,
            display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            {Scene && <Scene time={f * 8.4} dur={8.4} line={CREAM} accent={accent} sub="cream"
              sport={window.OW_sportKey ? window.OW_sportKey(sport) : sport} burst="rings" legs={false}
              svgW={mk * 0.96} svgH={mk * 0.96 * 1.08} />}
          </div>
        </div>

        {/* home indicator (first-run launch screen) */}
        {isFirst && (
          <div style={{ position: 'absolute', left: 0, right: 0, bottom: 9, display: 'flex',
            justifyContent: 'center', zIndex: 22, pointerEvents: 'none' }}>
            <div style={{ width: 140, height: 5, borderRadius: 3, background: CREAM, opacity: 0.8 }} />
          </div>
        )}

        {/* returning user → the app just opens: Dashboard fades in over the win */}
        {!isFirst && Dashboard && dashOp > 0.001 && (
          <div style={{ position: 'absolute', inset: 0, zIndex: 40, opacity: dashOp, overflow: 'hidden' }}>
            <div className="ow-splash-dash" style={{ position: 'absolute', inset: 0, overflowY: 'auto' }}>
              <Dashboard styleKey="balanced" paceKey={paceKey} btnStyle="solid" logPos="below" chartPlace="right" />
            </div>
          </div>
        )}
      </div>
    );
  }

  window.OWSplash = Splash;
})();
