/* ─── RocketJourney — GIF mascot flies a scroll-driven curved flight path across the page ─── */

function rocketLineFor(section) {
  const el = section.querySelector('h2, h3');
  const t = ((el && el.textContent) || '').toLowerCase();
  if (t.includes('best') || t.includes('tested')) return 'Our fan-favourites — tap any to shop! ⭐';
  if (t.includes('height')) return '50 years of DOMS — still climbing! 🚀';
  if (t.includes('collection')) return 'Hover a panel to explore each range 🎨';
  if (t.includes('rating') || t.includes('star')) return 'Loved by creators everywhere! 💬';
  if (t.includes('creativity') || t.includes('curiosity')) return 'Stay curious — keep going! ✨';
  if (t.includes('embrace') || t.includes('discover') || t.includes('latest') || t.includes('new')) return 'Meet our latest creations ✨';
  return 'Ooh, look here — keep scrolling 👇';
}

function smoothPath(pts) {
  if (pts.length < 2) return '';
  let d = `M ${pts[0].x.toFixed(1)} ${pts[0].y.toFixed(1)}`;
  for (let i = 0; i < pts.length - 1; i++) {
    const p0 = pts[i - 1] || pts[i];
    const p1 = pts[i];
    const p2 = pts[i + 1];
    const p3 = pts[i + 2] || p2;
    const c1x = p1.x + (p2.x - p0.x) / 6;
    const c1y = p1.y + (p2.y - p0.y) / 6;
    const c2x = p2.x - (p3.x - p1.x) / 6;
    const c2y = p2.y - (p3.y - p1.y) / 6;
    d += ` C ${c1x.toFixed(1)} ${c1y.toFixed(1)}, ${c2x.toFixed(1)} ${c2y.toFixed(1)}, ${p2.x.toFixed(1)} ${p2.y.toFixed(1)}`;
  }
  return d;
}

function RocketJourney() {
  const { useEffect, useRef, useState } = React;
  const gRef = useRef(null);
  const glowRef = useRef(null);
  const coreRef = useRef(null);
  const rocketRef = useRef(null);
  const bubbleRef = useRef(null);
  const bubbleTxtRef = useRef(null);
  const tailRef = useRef(null);
  const tableRef = useRef([]);
  const lenRef = useRef(0);
  const nodeGRef = useRef(null);
  const nodesRef = useRef([]);
  const targetLenRef = useRef(0);
  const curLenRef = useRef(-1);
  const [ready, setReady] = useState(false);
  const [isPhone, setIsPhone] = useState(typeof window !== 'undefined' && window.innerWidth <= 768);

  useEffect(() => {
    const onR = () => setIsPhone(window.innerWidth <= 768);
    window.addEventListener('resize', onR);
    return () => window.removeEventListener('resize', onR);
  }, []);

  useEffect(() => {
    const ROCKET = 'https://domsindia.com/wp-content/uploads/2025/06/5-1.gif';
    const SMOOTH = 0.16;         // higher = snappier settle (no post-stop drift)
    if (rocketRef.current) rocketRef.current.src = ROCKET;
    let running = true;
    let heading = 1;             // +1 faces right, -1 faces left (kept stable via hysteresis)
    let vDir = 1;               // +1 travelling down (scroll down), -1 travelling up
    let lastW = -1, lastH = -1;  // skip no-op rebuilds that make the trail jump

    function docHeight() {
      return Math.max(
        document.body.scrollHeight, document.documentElement.scrollHeight,
        document.body.offsetHeight, document.documentElement.offsetHeight
      );
    }

    function build(force) {
      const w = window.innerWidth;
      const h = docHeight();
      // ignore constant micro-resizes (image loads, mobile address bar, animations)
      // that would otherwise rebuild the path mid-scroll and jolt the trail
      if (!force && w === lastW && Math.abs(h - lastH) < 24) return;
      lastW = w; lastH = h;
      const mobile = w < 768;
      const leftF = mobile ? 0.16 : 0.07;
      const rightF = mobile ? 0.84 : 0.93;

      // start centred between the hero and the product (Inxon) section, land before the footer
      const heroEl = document.querySelector('main > section');     // first section = hero
      const startEl = document.getElementById('discover-section'); // DOMS Inxon / product showcase
      let startY;
      if (heroEl && startEl) {
        const heroBottom = heroEl.getBoundingClientRect().bottom + window.scrollY;
        const discTop = startEl.getBoundingClientRect().top + window.scrollY;
        startY = (heroBottom + discTop) / 2;                       // perfectly between the two
      } else if (startEl) {
        startY = Math.max(0, startEl.getBoundingClientRect().top + window.scrollY + 60);
      } else {
        startY = mobile ? 320 : 460;
      }
      const botPad = mobile ? 260 : 340;
      const usable = Math.max(420, h - startY - botPad);
      const segs = Math.max(6, Math.round(usable / (mobile ? 640 : 560)));

      const pts = [];
      for (let i = 0; i <= segs; i++) {
        const y = startY + usable * (i / segs);
        let xf;
        if (i === 0) xf = 0.5;
        else if (i === segs) xf = 0.5;
        else xf = (i % 2 === 1) ? leftF : rightF;
        pts.push({ x: w * xf, y });
      }
      const oldL = lenRef.current;
      const frac = oldL > 0 ? curLenRef.current / oldL : null;
      const tFrac = oldL > 0 ? targetLenRef.current / oldL : null;

      const d = smoothPath(pts);
      [glowRef.current, coreRef.current].forEach(p => p && p.setAttribute('d', d));

      const probe = coreRef.current;
      const L = probe.getTotalLength();
      lenRef.current = L;
      // keep the rocket at the SAME relative point on the path across a rebuild,
      // so changing path length can never snap it back to the start
      if (frac !== null) curLenRef.current = frac * L;
      if (tFrac !== null) targetLenRef.current = tFrac * L;
      const N = 360;
      const table = [];
      for (let i = 0; i <= N; i++) {
        const len = (L * i) / N;
        const pt = probe.getPointAtLength(len);
        table.push({ len, x: pt.x, y: pt.y });
      }
      tableRef.current = table;
      // STATIC, fully-visible flight path: a dotted core + soft glow, drawn once.
      // No scroll-driven stroke-dash animation → nothing flickers in and out.
      if (coreRef.current) { coreRef.current.style.strokeDasharray = '2 13'; coreRef.current.style.strokeDashoffset = '0'; }
      if (glowRef.current) { glowRef.current.style.strokeDasharray = 'none'; glowRef.current.style.strokeDashoffset = '0'; }

      // rest points: a node on the line at each section's centre
      const nodeG = nodeGRef.current;
      if (nodeG) {
        while (nodeG.firstChild) nodeG.removeChild(nodeG.firstChild);
        nodesRef.current = [];
        const NS = 'http://www.w3.org/2000/svg';
        Array.from(document.querySelectorAll('main > section')).forEach(s => {
          const rect = s.getBoundingClientRect();
          const cy = rect.top + window.scrollY + rect.height / 2;
          if (cy <= table[0].y || cy >= table[table.length - 1].y) return;
          const len = yToLen(cy);
          const pt = probe.getPointAtLength(len);
          const ring = document.createElementNS(NS, 'circle');
          ring.setAttribute('cx', pt.x.toFixed(1)); ring.setAttribute('cy', pt.y.toFixed(1));
          ring.setAttribute('fill', 'none'); ring.setAttribute('stroke-width', '2.5');
          ring.style.transition = 'all 0.3s ease';
          const dot = document.createElementNS(NS, 'circle');
          dot.setAttribute('cx', pt.x.toFixed(1)); dot.setAttribute('cy', pt.y.toFixed(1));
          dot.setAttribute('fill', '#FDC327'); dot.style.transition = 'all 0.3s ease';
          nodeG.appendChild(ring); nodeG.appendChild(dot);
          nodesRef.current.push({ ring, dot, len, msg: rocketLineFor(s) });
        });
      }
      computeTarget();
      if (curLenRef.current < 0) curLenRef.current = targetLenRef.current; // no fly-in on first build
      apply();
      setReady(true);
    }

    function yToLen(y) {
      const t = tableRef.current;
      if (!t.length) return 0;
      if (y <= t[0].y) return t[0].len;
      if (y >= t[t.length - 1].y) return t[t.length - 1].len;
      let lo = 0, hi = t.length - 1;
      while (lo < hi) { const m = (lo + hi) >> 1; if (t[m].y < y) lo = m + 1; else hi = m; }
      const b = t[lo], a = t[lo - 1] || t[0];
      const f = (y - a.y) / Math.max(1, b.y - a.y);
      return a.len + (b.len - a.len) * f;
    }

    function computeTarget() {
      const scrollY = window.scrollY || window.pageYOffset;
      // follow scroll continuously so the rocket glides THROUGH each section point and
      // rests wherever scrolling stops — no snapping, so nothing moves after you stop
      targetLenRef.current = Math.max(0, Math.min(lenRef.current, yToLen(scrollY + window.innerHeight * 0.52)));
    }

    function apply() {
      const probe = coreRef.current;
      if (!probe || !lenRef.current) return;
      const L = lenRef.current;
      const scrollY = window.scrollY || window.pageYOffset;
      const w = window.innerWidth;
      const cl = Math.max(0, Math.min(L, curLenRef.current));
      const p = probe.getPointAtLength(cl);
      const pa = probe.getPointAtLength(Math.max(0, cl - 9));
      const pb = probe.getPointAtLength(Math.min(L, cl + 9));
      const dx = pb.x - pa.x, dy = pb.y - pa.y;
      // travel direction = path tangent × scroll direction, so the nose follows the way
      // the rocket is actually moving (UP when the user scrolls up)
      const tvx = dx * vDir, tvy = dy * vDir;
      // airplane-style: nose toward horizontal travel, but only flip past a deadzone
      // so a resting rocket can't flicker left/right on sub-pixel tangent noise
      if (tvx > 4) heading = 1; else if (tvx < -4) heading = -1;
      const headingRight = heading > 0;
      const slope = Math.atan2(Math.abs(tvy), Math.abs(tvx)) * 180 / Math.PI; // 0 = level, 90 = vertical
      const tilt = Math.min(slope, 42);
      const noseUp = tvy < 0;     // travelling upward → lift the nose
      const atRest = scrollY < 170 || cl < 8;   // top of page → sit level (horizontal)

      // depth via SIZE only (crisp, no blur): bigger/nearer at centre, slightly smaller toward gutters
      const centrality = 1 - Math.min(1, Math.abs(p.x - w / 2) / (w / 2));
      const scale = (0.94 + centrality * 0.26).toFixed(3);

      if (gRef.current) gRef.current.setAttribute('transform', `translate(0 ${-scrollY})`);

      // dock highlight: light up the node the rocket is resting at
      const nodes = nodesRef.current;
      for (let i = 0; i < nodes.length; i++) {
        const near = Math.abs(nodes[i].len - cl) < 40;
        nodes[i].ring.setAttribute('r', near ? '21' : '13');
        nodes[i].ring.setAttribute('stroke', near ? '#FDC327' : '#02528A');
        nodes[i].ring.setAttribute('opacity', near ? '0.95' : '0.45');
        nodes[i].dot.setAttribute('r', near ? '7' : '5');
      }

      if (rocketRef.current) {
        const r = rocketRef.current;
        var phone = w <= 768;
        const base = phone
          ? `translate(${Math.round(p.x)}px, ${Math.round(p.y - scrollY)}px) translate(-50%, -50%)`
          : `translate(${p.x.toFixed(1)}px, ${(p.y - scrollY).toFixed(1)}px) translate(-50%, -50%)`;
        const pitch = atRest ? 0 : (noseUp ? -tilt : tilt);   // rest → level; down → nose down, up → nose up
        const orient = headingRight
          ? `rotate(${pitch.toFixed(1)}deg) scaleX(-1)`
          : `rotate(${(-pitch).toFixed(1)}deg)`;
        r.style.transform = `${base} ${orient} scale(${scale})`;
        r.style.filter = 'drop-shadow(0 16px 30px rgba(2,82,138,0.26))';
      }

      // speech bubble: greet at the top, then a short line while docked at each section
      const b = bubbleRef.current;
      if (b) {
        let msg = null;
        if (scrollY < 170) {
          msg = "Hey, I'm here! \uD83D\uDC4B Follow me down \u2193";
        } else {
          const nb = nodesRef.current.find(n => Math.abs(n.len - cl) < 130);
          if (nb) msg = nb.msg;
        }
        if (msg) {
          if (bubbleTxtRef.current && bubbleTxtRef.current.textContent !== msg) bubbleTxtRef.current.textContent = msg;
          const leftSide = p.x < w / 2;          // rocket in left gutter → bubble points right (inward)
          const rw = (rocketRef.current && rocketRef.current.offsetWidth) || 240;
          const off = rw * 0.40 + 18;            // clear the rocket art so the bubble never overlaps it
          const bx = p.x + (leftSide ? off : -off);
          const by = p.y - scrollY - 14;         // sit slightly above centre, beside the nose
          b.style.transform = `translate(${bx.toFixed(1)}px, ${by.toFixed(1)}px) translate(${leftSide ? '0' : '-100%'}, -50%)`;
          if (tailRef.current) {
            tailRef.current.style.left = leftSide ? '-5px' : 'auto';
            tailRef.current.style.right = leftSide ? 'auto' : '-5px';
          }
          b.style.opacity = '1';
        } else {
          b.style.opacity = '0';
        }
      }
    }

    function frame() {
      if (!running) return;
      computeTarget();
      const diff = targetLenRef.current - curLenRef.current;
      // scroll direction with hysteresis → drives which way the nose points
      if (diff > 1.2) vDir = 1; else if (diff < -1.2) vDir = -1;
      curLenRef.current += diff * SMOOTH;
      if (Math.abs(diff) < 0.5) curLenRef.current = targetLenRef.current;
      apply();
      requestAnimationFrame(frame);
    }

    // Rebuild ONLY on a real width change (orientation / desktop resize). Height-only
    // resizes (mobile address bar, late image loads) are ignored so the path never
    // shifts on its own mid-scroll. A few early builds let the layout settle, then freeze.
    let lastResizeW = window.innerWidth;
    const onResize = () => {
      if (window.innerWidth !== lastResizeW) { lastResizeW = window.innerWidth; build(true); }
    };
    const onLoad = () => build(true);

    build(true);
    requestAnimationFrame(frame);
    window.addEventListener('resize', onResize);
    window.addEventListener('load', onLoad);
    const t1 = setTimeout(() => build(false), 700);
    const t2 = setTimeout(() => build(false), 2000);

    return () => {
      running = false;
      window.removeEventListener('resize', onResize);
      window.removeEventListener('load', onLoad);
      clearTimeout(t1); clearTimeout(t2);
    };
  }, []);

  return (
    <div aria-hidden="true" style={{
      position: 'fixed', inset: 0, zIndex: 40, pointerEvents: 'none', overflow: 'hidden',
      opacity: ready ? 1 : 0, transition: 'opacity 0.6s ease',
    }}>
      <svg width="100%" height="100%" style={{ position: 'absolute', inset: 0, overflow: 'visible' }}>
        <defs>
          <linearGradient id="pt-trail" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#FDC327" />
            <stop offset="50%" stopColor="#0A6FB8" />
            <stop offset="100%" stopColor="#FDC327" />
          </linearGradient>
        </defs>
        <g ref={gRef}>
          <path ref={glowRef} fill="none" stroke="#FDC327" strokeWidth="14" strokeOpacity="0.1"
            strokeLinecap="round" style={{ filter: 'blur(8px)' }} />
          <path ref={coreRef} fill="none" stroke="url(#pt-trail)" strokeWidth="3.5" strokeOpacity="0.55"
            strokeLinecap="round" />
          <g ref={nodeGRef}></g>
        </g>
      </svg>
      <img ref={rocketRef} alt="DOMMY rocket"
        style={{
          position: 'absolute', top: 0, left: 0, width: 'clamp(210px, 25vw, 380px)',
          willChange: 'transform', transformOrigin: 'center',
        }} />
      <div ref={bubbleRef} style={{
        position: 'absolute', top: 0, left: 0, zIndex: 5, maxWidth: 188, padding: '10px 14px',
        background: '#fff', color: '#02528a', borderRadius: 15,
        fontFamily: "'Poppins', sans-serif", fontSize: 13.5, fontWeight: 600, lineHeight: 1.4,
        boxShadow: '0 14px 32px rgba(2,82,138,0.3), 0 3px 8px rgba(0,0,0,0.12)',
        border: '1.5px solid rgba(2,82,138,0.16)', opacity: 0,
        display: 'block',
        transition: 'opacity 0.4s ease', willChange: 'transform, opacity',
      }}>
        <span ref={bubbleTxtRef}></span>
        <span ref={tailRef} aria-hidden="true" style={{
          position: 'absolute', top: '50%', marginTop: -5, left: -5, width: 11, height: 11,
          background: '#fff', transform: 'rotate(45deg)',
          borderLeft: '1px solid rgba(2,82,138,0.1)', borderBottom: '1px solid rgba(2,82,138,0.1)',
        }} />
      </div>
    </div>
  );
}

window.RocketJourney = RocketJourney;
