// waiv-journey.jsx — one continuous scroll story. A single card persists across
// three beats: HERO (right) → X-RAY (center, surface dissolves) → TAP (card
// shrinks onto a phone) → ONELYNK (profile builds in). All driven by scroll.

function WaivJourney() {
  const { useState, useRef, useEffect } = React;
  const [finish, setFinish] = useState('midnightgold');
  const [revealed, setRevealed] = useState(false);
  const revRef = useRef(false);

  const trackRef = useRef(null);
  const stickyRef = useRef(null);
  const posRef = useRef(null);     // card position wrapper
  const tiltRef = useRef(null);    // wv-card3d-tilt (rotation)
  const phoneRef = useRef(null);
  const screenRef = useRef(null);
  const copyRef = useRef(null);
  const cueRef = useRef(null);
  const stat1Ref = useRef(null);
  const stat2Ref = useRef(null);
  const capRefs = useRef([]);
  const dotRefs = useRef([]);

  useEffect(() => {
    const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
    const ease = t => t * t * (3 - 2 * t);
    const es = (p, a, b) => ease(clamp((p - a) / (b - a), 0, 1));
    const mix = (a, b, t) => a + (b - a) * t;
    const mobile = () => window.matchMedia('(max-width:1080px)').matches;
    let raf;

    const tick = (now) => {
      const track = trackRef.current, sticky = stickyRef.current;
      if (track && sticky && !mobile()) {
        const r = track.getBoundingClientRect();
        const vh = window.innerHeight;
        const p = clamp(-r.top / (r.height - vh), 0, 1);
        const t = now / 1000;

        // ── segments ──
        const sHC = es(p, 0.16, 0.42);   // hero → center
        const sCT = es(p, 0.46, 0.64);   // center → tap
        const sTP = es(p, 0.66, 0.82);   // tap → park

        // ── card position / scale ──
        let cx = mix(20, 0, sHC); cx = mix(cx, 0, sCT); cx = mix(cx, 27, sTP);
        let cy = mix(0, 2, sHC);  cy = mix(cy, -13, sCT); cy = mix(cy, -30, sTP);
        let cs = mix(1, 1.06, sHC); cs = mix(cs, 0.42, sCT); cs = mix(cs, 0.26, sTP);
        cy += Math.sin(t * 1.1) * 0.55 * (1 - sHC);   // idle bob in hero only
        if (posRef.current)
          posRef.current.style.transform = `translate(-50%,-50%) translate3d(${cx.toFixed(2)}vw,${cy.toFixed(2)}vh,0) scale(${cs.toFixed(3)})`;

        // ── card rotation ──
        let rx = mix(7, 4, sHC); rx = mix(rx, 17, sCT); rx = mix(rx, 8, sTP);
        let ry = mix(-22, 6, sHC); ry = mix(ry, -12, sCT); ry = mix(ry, -20, sTP);
        let rz = mix(2, 1, sHC); rz = mix(rz, -7, sCT); rz = mix(rz, 8, sTP);
        if (tiltRef.current)
          tiltRef.current.style.transform = `rotateX(${rx.toFixed(2)}deg) rotateY(${ry.toFixed(2)}deg) rotateZ(${rz.toFixed(2)}deg)`;

        // ── x-ray reveal window (face dissolves to internals) ──
        const wantReveal = p > 0.24 && p < 0.45;
        if (wantReveal !== revRef.current) { revRef.current = wantReveal; setRevealed(wantReveal); }

        // ── phone enter ──
        const pe = es(p, 0.50, 0.66);
        if (phoneRef.current) {
          const px = mix(120, 0, pe), ps = mix(0.95, 1, pe);
          phoneRef.current.style.transform = `translate(-50%,-50%) translate3d(${px.toFixed(2)}vw,0,0) scale(${ps.toFixed(3)})`;
          phoneRef.current.style.opacity = pe.toFixed(3);
        }
        // profile build-in
        if (screenRef.current) screenRef.current.classList.toggle('is-built', p > 0.72);
        // floating stats
        const so = es(p, 0.80, 0.96);
        if (stat1Ref.current) { stat1Ref.current.style.opacity = so.toFixed(3); stat1Ref.current.style.transform = `translateY(${(1 - so) * 16}px)`; }
        if (stat2Ref.current) { stat2Ref.current.style.opacity = so.toFixed(3); stat2Ref.current.style.transform = `translateY(${(1 - so) * 16}px)`; }

        // tap pulse
        sticky.classList.toggle('is-tapping', p > 0.60 && p < 0.80);

        // hero copy + cue fade
        const heroOp = 1 - es(p, 0.08, 0.18);
        if (copyRef.current) { copyRef.current.style.opacity = heroOp.toFixed(3); copyRef.current.style.pointerEvents = heroOp < 0.1 ? 'none' : 'auto'; copyRef.current.style.transform = `translateY(calc(-50% + ${(-(1 - heroOp) * 30).toFixed(1)}px))`; }
        if (cueRef.current) cueRef.current.style.opacity = heroOp.toFixed(3);

        // ── captions + dots ──
        const phase = p >= 0.74 ? 2 : p >= 0.55 ? 1 : p >= 0.26 ? 0 : -1;
        capRefs.current.forEach((el, i) => el && el.classList.toggle('is-on', i === phase));
        dotRefs.current.forEach((el, i) => el && el.classList.toggle('is-on', phase >= 0 && i <= phase));
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  const cfg = WAIV_FINISHES[finish];
  const caps = [
    <>Beneath the finish — a copper antenna and a <em>secure NTAG 424 chip.</em></>,
    <>Hold it to <em>any phone.</em> No app. No scanning.</>,
    <>And your whole world <em>arrives</em> — in a single tap.</>,
  ];

  return (
    <section className="jr-track" id="top" ref={trackRef}>
      <div className="jr-sticky" ref={stickyRef}>
        <div className="jr-field" aria-hidden="true">
          <div className="jr-glow jr-glow-1" data-parallax="0.05" />
          <div className="jr-glow jr-glow-2" data-parallax="0.04" />
          <div className="jr-grid" />
          <div className="jr-grain" />
        </div>

        {/* Beat A — hero copy */}
        <div className="jr-hero-copy" ref={copyRef}>
          <div className="hb-eyebrow"><span className="hb-eyebrow-mark" />SHARE YOUR STORY · NFC</div>
          <h1 className="hb-display">Make the<br />first move<br /><em>unforgettable.</em></h1>
          <p className="hb-lede">One premium card with a secure NFC chip inside. Tap any phone and your whole world arrives — contacts, socials, payments, portfolio.</p>
          <div className="hb-cta-row">
            <button className="wv-btn wv-btn-primary wv-magnetic">Design your card</button>
            <a href="#cards" className="wv-btn wv-btn-ghost wv-magnetic">Browse the range <span className="wv-arrow">→</span></a>
          </div>
          <div className="hb-controls">
            <div className="hb-finishes">
              {WAIV_FINISH_ORDER.map(id => (
                <button key={id} className={`hb-finish-btn ${id === finish ? 'is-active' : ''}`}
                  style={{ background: WAIV_FINISHES[id].grad }} onClick={() => setFinish(id)}
                  aria-label={WAIV_FINISHES[id].name} title={WAIV_FINISHES[id].name} />
              ))}
            </div>
            <div className="hb-finish-meta">
              <span className="hb-finish-label">Finish</span>
              <span className="hb-finish-name">{cfg.name}</span>
            </div>
          </div>
        </div>

        {/* The single shared card */}
        <div className="jr-card-pos" ref={posRef}>
          <WaivCard3D ref={tiltRef} w={540} finish={finish} revealed={revealed} />
        </div>

        {/* Phone + tap pulse */}
        <div className="jr-phone-pos" ref={phoneRef}>
          <div className="jr-tap" aria-hidden="true"><span /><span /><span /></div>
          <div className="jr-phone">
            <div className="jr-notch" />
            <div className="jr-screen" ref={screenRef}>
              <div className="jr-cover" />
              <div className="jr-pbody">
                <div className="jr-avatar" />
                <h3 className="jr-pname">Maya Okafor</h3>
                <p className="jr-prole">Product Designer · Studio North</p>
                <span className="jr-ptag">⚡ via waiv</span>
                <div className="jr-plinks">
                  <div className="jr-plink"><div className="jr-plink-ico"><Ico n="grid" /></div><div className="jr-plink-txt"><b>Portfolio</b><span>maya.design</span></div></div>
                  <div className="jr-plink"><div className="jr-plink-ico"><Ico n="calendar" /></div><div className="jr-plink-txt"><b>Book a coffee</b><span>cal.com/maya</span></div></div>
                  <div className="jr-plink"><div className="jr-plink-ico"><Ico n="share" /></div><div className="jr-plink-txt"><b>Instagram</b><span>@maya.makes</span></div></div>
                </div>
                <div className="jr-psave">Save contact</div>
              </div>
            </div>
          </div>
          <div className="jr-stat" ref={stat1Ref} style={{ top: '12%', right: '-30%' }}>
            <div className="jr-num">1.2k</div><div className="jr-cap">profile<br />views</div>
          </div>
          <div className="jr-stat" ref={stat2Ref} style={{ bottom: '14%', left: '-32%' }}>
            <div className="jr-num">+318</div><div className="jr-cap">contacts<br />saved</div>
          </div>
        </div>

        {/* captions */}
        <div className="jr-caps">
          <div className="jr-cap">
            {caps.map((c, i) => <p key={i} ref={el => capRefs.current[i] = el}>{c}</p>)}
          </div>
          <div className="jr-dots">
            {[0, 1, 2].map(i => <i key={i} ref={el => dotRefs.current[i] = el} />)}
          </div>
        </div>

        <div className="jr-cue" ref={cueRef}>Scroll<div className="jr-cue-line" /></div>
      </div>
    </section>
  );
}

window.WaivJourney = WaivJourney;
