/* Poise onboarding - S3/S4/S5: the "why" beats between the hook and the questions.
   S3 · Seen and felt - the walking silhouette (user-supplied asset), head down,
         floating on the flat canvas with a subtle top/bottom dissolve. Copy:
         outward read + inward physiology. FINAL - locked, no tweaks.
         (Compliance: awareness framing only - no pain/medical/treatment language.)
   S4 · The compounding - held long enough it becomes your default.
   S5 · The turn to "you" - absolving tone; tees up "see where you stand." */

const { useState, useEffect, useRef } = React;
const { Button } = window.PoiseDesignSystem_eee0d2;

/* Shared staged-reveal hook: returns show(n) style helper. */
function useStaged(times, motion) {
  const [stage, setStage] = useState(0);
  useEffect(() => {
    const base = motion ? 1 : 0.02;
    const ts = times.map((t, i) => setTimeout(() => setStage(i + 1), t * base));
    return () => ts.forEach(clearTimeout);
  }, [motion]);
  return (n) => ({ opacity: stage >= n ? 1 : 0, pointerEvents: stage >= n ? 'auto' : 'none', transform: stage >= n ? 'none' : 'translateY(10px)', transition: 'opacity 750ms var(--ease-out), transform 750ms var(--ease-out)' });
}

/* Feet now render in full at the bottom; no fades. The figure sits anchored
   at the bottom of the container with headroom above it. */
const FIGURE_MASK = 'none';

/* ============ S3 · Why: seen and felt ============ */
function WhyReadScreen() {
  const flow = useFlow();
  // Text, CTA, and the silhouette image all load in together, immediately -
  // the image's own fade no longer waits on its onLoad event (which lagged
  // visibly behind the text whenever the fetch/decode took a beat). The
  // image is preloaded from page load (see index.html) so by the time a
  // visitor reaches S3 it's already decoded and paints on the same frame.
  const show = useStaged([0, 0, 0, 0], flow.t.motion);
  const figIn = show(1).opacity === 1;

  return (
    <div data-screen-label="S3 · Why: seen and felt" style={{ position: 'absolute', inset: 0, background: 'var(--black)', display: 'flex', flexDirection: 'column', paddingTop: 'var(--status-bar-inset)' }}>
      <TopBar onBack={() => flow.back()} />
      <div className="onb-screen-enter" style={{ position: 'relative', zIndex: 2, flex: 1, display: 'flex', flexDirection: 'column' }}>
        <div className="onb-scroll-y" style={{ flex: 1, display: 'flex', flexDirection: 'column', padding: '0 var(--screen-margin)', minHeight: 0 }}>
          {/* The figure: fades up out of the black, no translate */}
          <div style={{ height: 235, flexShrink: 0, display: 'flex', justifyContent: 'center', alignItems: 'flex-end', WebkitMaskImage: FIGURE_MASK, maskImage: FIGURE_MASK, opacity: figIn ? 1 : 0, transition: 'opacity 750ms var(--ease-out)' }}>
            <img
              src={window.__resources ? window.__resources.imgSilhouetteWalk : "/onboarding-demo/app/silhouette-walk-complete.png"}
              alt=""
              style={{ height: 190, display: 'block', filter: 'brightness(0.72)' }} />
          </div>
          <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'flex-start', gap: 14, marginTop: 44 }}>
            <H style={{ fontSize: 31, lineHeight: 1.2, ...show(1) }}>Others see it. You feel it.</H>
            <P style={{ fontSize: 18, marginTop: 8, ...show(2) }}>People pick up on it before you’ve said a word.</P>
            <P style={{ fontSize: 18, ...show(3) }}>Your body reads it too. Slouching restricts breathing and drains energy; sitting upright measurably lifts mood and alertness.</P>
          </div>
          <div style={{ flexShrink: 0, paddingBottom: 34, paddingTop: 12, display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center' }}>
            <div style={{ width: '100%', ...show(4) }}>
              <Button variant="primary" size="lg" fullWidth onClick={() => flow.next()}>Continue</Button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ============ S4 · Why: nobody notices ============ */
function WhyCompoundScreen() {
  const flow = useFlow();
  // Text and CTA load in immediately. The graph's fade-in wrapper and its
  // line-draw both start 250ms after that.
  const show = useStaged([0, 0, 0, 0], flow.t.motion);
  const graphShow = useStaged([250], flow.t.motion);
  const [graphPlay, setGraphPlay] = useState(false);

  useEffect(() => {
    const base = flow.t.motion ? 1 : 0.02;
    const t = setTimeout(() => setGraphPlay(true), 250 * base);
    return () => clearTimeout(t);
  }, [flow.t.motion]);

  return (
    <Screen
      id="why-compound" label="S4 · Why: nobody notices"
      topBar={<TopBar onBack={() => flow.back()} />}
      cta={
        <div style={{ width: '100%', marginTop: -10, ...show(4) }}>
          <Button variant="primary" size="lg" fullWidth onClick={() => flow.next()}>How it works</Button>
        </div>
      }
    >
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 14 }}>
        <H style={{ fontSize: 31, ...show(1) }}>The best version of you stands up straight</H>
        <P style={{ fontSize: 18, marginTop: 12, ...show(2) }}>People instantly pick up when you have good posture.</P>
        <P style={{ fontSize: 18, ...show(3) }}>Poise pays attention to how you're holding yourself, so you don't have to.</P>
        <div style={{ marginTop: 32, ...graphShow(1) }}><PostureGraph play={graphPlay} /></div>
      </div>
    </Screen>
  );
}

/* ============ S5 · How it works: priming ============ */
/* ============ S5 · How it works: priming ============ */

/* The approved nudge-demo figure (sketch A): user-supplied head + torso
   assets in mint, white AirPod, white pulse rings. The neck bridge is
   computed from the two pixel contours so the join stays smooth at every
   pitch angle. */
const S2C_PIVOT_X = 348, S2C_PIVOT_Y = 817, S2C_EAR_X = 389, S2C_EAR_Y = 480;

function s2cBridgePath(pitch) {
  const A = (pitch * Math.PI) / 180, cos = Math.cos(A), sin = Math.sin(A);
  const rot = ([x, y]) => [S2C_PIVOT_X + (x - S2C_PIVOT_X) * cos - (y - S2C_PIVOT_Y) * sin, S2C_PIVOT_Y + (x - S2C_PIVOT_X) * sin + (y - S2C_PIVOT_Y) * cos];
  const rotv = ([x, y]) => [x * cos - y * sin, x * sin + y * cos];
  const backLift = pitch < 0 ? Math.abs(pitch) * 2.2 : 0;
  const back = Math.max(0, -pitch) / 50;
  const mix = (fixed, follow) => [fixed[0] + (follow[0] - fixed[0]) * back, fixed[1] + (follow[1] - fixed[1]) * back];
  const anchorBack = Math.min(1, Math.max(0, -pitch) / 18);
  const aMix = (fixed, follow) => [fixed[0] + (follow[0] - fixed[0]) * anchorBack, fixed[1] + (follow[1] - fixed[1]) * anchorBack];
  const B0 = rot(aMix([212, 718], [218, 621]));
  const F0 = rot(aMix([497, 731], [482, 771]));
  const C1b = rot([201, 845]);
  const C1f = rot([444, 873]);
  const B1 = mix([187, 980], [B0[0] + rotv([-60.5, 115])[0], B0[1] + rotv([-60.5, 115])[1]]);
  const C2b = mix([176, 903], [B0[0] + rotv([-37.3, 85])[0], B0[1] + rotv([-37.3, 85])[1]]);
  const F1 = mix([366, 1009], [F0[0] + rotv([-19.5, 145])[0], F0[1] + rotv([-19.5, 145])[1]]);
  const C2f = mix([397, 1433 - backLift], [F0[0] + rotv([-20.5, 90])[0], F0[1] + rotv([-20.5, 90])[1]]);
  const botL = mix([85, 1032], [B1[0] + 64, B1[1] + 55]);
  const botR = mix([484, 1265], [F1[0] - 9, F1[1] + 25]);
  const p = (v) => v.map((n) => n.toFixed(1)).join(' ');
  return `M ${p(B0)} C ${p(C1b)}, ${p(C2b)}, ${p(B1)} L ${p(botL)} L ${p(botR)} L ${p(F1)} C ${p(C2f)}, ${p(C1f)}, ${p(F0)} Z`;
}

function S5Figure({ pitch, flashKey, onTap, height = 260, wideMode = false }) {
  return (
    <div onClick={onTap} role="button" aria-label="Replay the nudge demo"
      style={{ cursor: 'pointer', WebkitTapHighlightColor: 'transparent', WebkitMaskImage: 'linear-gradient(180deg, #000 60%, transparent 100%)', maskImage: 'linear-gradient(180deg, #000 60%, transparent 100%)',
        ...(wideMode ? { width: 260, display: 'flex', justifyContent: 'center' } : { width: 330, display: 'flex', justifyContent: 'center' }),
      }}>
      <svg viewBox="-60 0 920 1500" height={height} fill="none" style={{ display: 'block', overflow: 'visible', ...(wideMode ? {} : {}) }}>
        <path d={s2cBridgePath(pitch)} fill="#BDEECD"></path>
        <g style={{ transform: `rotate(${pitch}deg)`, transformOrigin: `${S2C_PIVOT_X}px ${S2C_PIVOT_Y}px` }}>
          <image href={window.__resources ? window.__resources.imgHeadMint : "/onboarding-demo/app/head-mint.png"} x="15" y="0" width="806" height="980"></image>
          {flashKey > 0 && (
            <g key={flashKey}>
              <circle className="pod-pulse" cx={S2C_EAR_X} cy={S2C_EAR_Y} r="120" stroke="#FFFFFF" strokeWidth="10" fill="none"></circle>
              <circle className="pod-pulse p2" cx={S2C_EAR_X} cy={S2C_EAR_Y} r="120" stroke="#FFFFFF" strokeWidth="7" fill="none"></circle>
              <g transform={`translate(${S2C_EAR_X - 148} ${S2C_EAR_Y - 76}) rotate(${-pitch})`}>
                <g className="pod-note">
                  <ellipse cx="0" cy="0" rx="30" ry="22" transform="rotate(-20)" fill="#020003"></ellipse>
                  <path d="M 26 -10 L 26 -112" stroke="#020003" strokeWidth="14" strokeLinecap="round"></path>
                  <path d="M 26 -112 C 60 -100, 66 -68, 46 -44" stroke="#020003" strokeWidth="14" strokeLinecap="round" fill="none"></path>
                </g>
              </g>
            </g>
          )}
          <g transform={`rotate(-8 ${S2C_EAR_X} ${S2C_EAR_Y})`}>
            <ellipse cx={S2C_EAR_X} cy={S2C_EAR_Y} rx="34" ry="42" fill="#FFFFFF"></ellipse>
            <path d={`M ${S2C_EAR_X - 2} ${S2C_EAR_Y + 30} L ${S2C_EAR_X - 10} ${S2C_EAR_Y + 118}`} stroke="#FFFFFF" strokeWidth="30" strokeLinecap="round"></path>
          </g>
        </g>
        <image href={window.__resources ? window.__resources.imgTorsoMint : "/onboarding-demo/app/torso-mint.png"} x="-81.5" y="815" width="822" height="1073"></image>
      </svg>
    </div>
  );
}

function WhyYouScreen() {
  const flow = useFlow();
  /* Choreography: figure + title land immediately, then p1, a beat of
     pause, the demo plays (dip at ~3.75s + chime, recovers by ~5.55s), p2
     lands half a second after the head is back upright, CTA follows
     shortly after. head-mint.png/torso-mint.png are preloaded (see
     index.html) so the figure paints on the same frame as the title
     without a separate load-gated fade. */
  const show = useStaged([0, 1100, 6050, 7150], flow.t.motion);
  const [pitch, setPitch] = useState(0);
  const [flashKey, setFlashKey] = useState(0);
  const busy = useRef(false);
  const alive = useRef(true);
  useEffect(() => () => { alive.current = false; }, []);

  const tween = (from, to, dur) => new Promise((res) => {
    const t0 = performance.now();
    const ease = (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2);
    const step = (now) => {
      if (!alive.current) return;
      const k = Math.min(1, (now - t0) / dur);
      setPitch(from + (to - from) * ease(k));
      if (k < 1) requestAnimationFrame(step); else res();
    };
    requestAnimationFrame(step);
  });
  const pause = (ms) => new Promise((r) => setTimeout(r, ms));

  const play = async () => {
    if (busy.current || !flow.t.motion) return;
    busy.current = true;
    await tween(0, 30, 950);
    if (!alive.current) return;
    setFlashKey((k) => k + 1);
    PoiseAudio.chime();
    await pause(850);
    if (!alive.current) return;
    await tween(30, 0, 950);
    busy.current = false;
  };

  useEffect(() => {
    if (!flow.t.motion) { setPitch(20); return; }
    const t = setTimeout(play, 2800);
    return () => clearTimeout(t);
  }, [flow.t.motion]);

  return (
    <Screen
      id="why-you" label="S5 · How it works: priming"
      topBar={<TopBar onBack={() => flow.back()} />}
      cta={
        <div style={{ width: '100%', ...show(4) }}>
          <Button variant="primary" size="lg" fullWidth onClick={() => flow.next()}>Personalize</Button>
        </div>
      }
    >
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 14 }}>
        <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 8, ...show(1) }}>
          <S5Figure pitch={pitch} flashKey={flashKey} onTap={play} />
        </div>
        <H style={{ fontSize: 31, ...show(1) }}>How Poise works</H>
        <P style={{ fontSize: 18, marginTop: 12, ...show(2) }}>Poise reads your posture through your AirPods. When your head starts to drift, a soft chime nudges you upright.</P>
        <P style={{ fontSize: 18, ...show(3) }}>The detection is smart, and it works best tuned to you: your routine, your goals, what you want to change. Let's tailor it to you.</P>
      </div>
    </Screen>
  );
}

/* Compact posture-over-time graph: a flat grey "without Poise" reference draws
   first, then the mint "with Poise" curve draws over it (slower, per the DS's
   calm/short motion rule - one draw-in, then it settles; never loops). Purely
   illustrative for this priming screen (no real user data exists yet), so no
   numbers are shown; only axis concepts (time / posture score). */
function PostureGraph({ play }) {
  return (
    <div className={`gA${play ? ' play' : ''}`}>
      <div className="chart-row">
        <div className="y-axis-label"><span>Posture</span></div>
        <svg viewBox="-16 0 276 110" preserveAspectRatio="none">
          <line className="axisline axis-y" x1="0" y1="0" x2="0" y2="108"></line>
          <line className="axisline axis-x" x1="-16" y1="96" x2="260" y2="96"></line>
          <path className="greyline" d="M0,80 C40,82 70,76 100,79 C140,82 170,75 200,78 C230,80 245,74 260,76" fill="none"></path>
          <path className="linepath" d="M1.5,80 C2.667,80.072 10.333,80.93 16,80.43 C21.667,79.93 28.333,77.613 34,77.0 C39.667,76.387 45,77.568 50,76.75 C55,75.932 58.667,73.068 64,72.09 C69.333,71.112 76,72.017 82,70.88 C88,69.743 94.333,66.483 100,65.27 C105.667,64.057 110.667,64.833 116,63.6 C121.333,62.367 126.333,59.28 132,57.87 C137.667,56.46 144,56.822 150,55.14 C156,53.458 162.333,49.498 168,47.78 C173.667,46.062 178.333,46.62 184,44.83 C189.667,43.04 196,39.443 202,37.04 C208,34.637 214.333,32.158 220,30.41 C225.667,28.662 229.333,29.118 236,26.55 C242.667,23.982 256,16.925 260,15" stroke="var(--mint)" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"></path>
          <circle className="ring" cx="260" cy="15" r="8" fill="none" stroke="var(--mint)" strokeWidth="2"></circle>
        </svg>
        <div className="line-labels">
          <span className="line-label grey">Without Poise</span>
          <span className="line-label mint">With Poise</span>
        </div>
      </div>
      <div className="x-axis-row"><div className="x-axis-spacer"></div><div className="x-axis-label">Time</div><div className="x-axis-spacer-right"></div></div>
    </div>
  );
}

Object.assign(window, { WhyReadScreen, WhyCompoundScreen, WhyYouScreen, S5Figure });
