/* ProcessJourney v3 — "The Route".
   A dark, full-bleed expedition map: an SVG line draws itself down the
   page as you scroll, a comet traveler rides it between six stations,
   and each station ignites as the comet arrives. Native scroll only.
   Reduced motion: line fully drawn, everything lit, no traveler. */

const RT_PAD = (n) => String(n).padStart(2, "0");

function ProcessJourney({ phases }) {
  const wrapRef = React.useRef(null);
  const mapRef = React.useRef(null);
  const svgRef = React.useRef(null);
  const baseRef = React.useRef(null);
  const lineRef = React.useRef(null);
  const travelerRef = React.useRef(null);
  const fracsRef = React.useRef([]);
  const ysRef = React.useRef([]);
  const lenRef = React.useRef(0);
  const [active, setActive] = React.useState(0);
  const [hudOn, setHudOn] = React.useState(false);

  React.useEffect(() => {
    const wrap = wrapRef.current;
    const map = mapRef.current;
    const svg = svgRef.current;
    const base = baseRef.current;
    const line = lineRef.current;
    const traveler = travelerRef.current;
    if (!wrap || !map || !svg) return;

    const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    wrap.classList.add(reduced ? "rt-static" : "rt-ready");
    const stations = Array.from(map.querySelectorAll(".rt-station"));
    const ns = "http://www.w3.org/2000/svg";
    let raf = 0;
    let lastActive = -1;
    let lastHud = null;

    const build = () => {
      const mr = map.getBoundingClientRect();
      const nodes = stations.map((s) => s.querySelector(".rt-node"));
      const pts = nodes.map((n) => {
        const r = n.getBoundingClientRect();
        return { x: r.left + r.width / 2 - mr.left, y: r.top + r.height / 2 - mr.top };
      });
      svg.setAttribute("viewBox", `0 0 ${Math.round(mr.width)} ${Math.round(mr.height)}`);

      let d = `M ${pts[0].x.toFixed(1)} ${pts[0].y.toFixed(1)}`;
      for (let i = 1; i < pts.length; i++) {
        const a = pts[i - 1], b = pts[i];
        const my = (a.y + b.y) / 2;
        d += ` C ${a.x.toFixed(1)} ${my.toFixed(1)}, ${b.x.toFixed(1)} ${my.toFixed(1)}, ${b.x.toFixed(1)} ${b.y.toFixed(1)}`;
      }
      base.setAttribute("d", d);
      line.setAttribute("d", d);

      const L = line.getTotalLength();
      lenRef.current = L;
      line.style.strokeDasharray = `${L}`;
      if (reduced) {
        line.style.strokeDashoffset = "0";
      }

      // cumulative length fraction at each station (for ignition timing)
      const tmp = document.createElementNS(ns, "path");
      const fr = [0];
      let dd = `M ${pts[0].x.toFixed(1)} ${pts[0].y.toFixed(1)}`;
      for (let i = 1; i < pts.length; i++) {
        const a = pts[i - 1], b = pts[i];
        const my = (a.y + b.y) / 2;
        dd += ` C ${a.x.toFixed(1)} ${my.toFixed(1)}, ${b.x.toFixed(1)} ${my.toFixed(1)}, ${b.x.toFixed(1)} ${b.y.toFixed(1)}`;
        tmp.setAttribute("d", dd);
        fr.push(tmp.getTotalLength() / L);
      }
      fracsRef.current = fr;
      // node Y centers in map coords — ignition is driven by these, so a
      // station lights exactly when the anchor line crosses its node.
      ysRef.current = pts.map((pt) => pt.y);
    };

    // The path's y is monotonically increasing (stations descend), so we can
    // binary-search the path length whose point sits at a given y. This keeps
    // the comet pinned to the anchor line on screen — length-based progress
    // drifts because the horizontal S-curves add length unevenly.
    const lengthAtY = (y) => {
      const L = lenRef.current;
      const path = lineRef.current;
      let lo = 0, hi = L;
      for (let k = 0; k < 22; k++) {
        const mid = (lo + hi) / 2;
        if (path.getPointAtLength(mid).y < y) lo = mid; else hi = mid;
      }
      return (lo + hi) / 2;
    };

    const update = () => {
      raf = 0;
      const rect = map.getBoundingClientRect();
      const vh = window.innerHeight;
      const anchor = vh * 0.55;
      const ys = ysRef.current;
      const L = lenRef.current;
      if (!ys.length || !L) return;

      // Anchor position in map coordinates. The path spans from the first
      // node's y to the last node's y — everything keys off where the anchor
      // line sits on screen, so ignition always matches what's mid-viewport.
      const anchorY = anchor - rect.top;
      const y0 = ys[0], y1 = ys[ys.length - 1];
      const t = anchorY <= y0 ? 0 : anchorY >= y1 ? L : lengthAtY(anchorY);
      const p = Math.max(0, Math.min(1, (anchorY - y0) / Math.max(1, y1 - y0)));
      wrap.style.setProperty("--p", p.toFixed(4));

      if (!reduced) {
        line.style.strokeDashoffset = `${L - t}`;
        const pt = lineRef.current.getPointAtLength(t);
        traveler.setAttribute("transform", `translate(${pt.x.toFixed(1)}, ${pt.y.toFixed(1)})`);
        traveler.style.opacity = anchorY < y0 - 40 ? "0" : "1";
      }

      let cur = 0;
      stations.forEach((el, i) => {
        // Light when the anchor crosses the node's center (tiny grace so the
        // glow starts as the number reaches mid-screen, not after).
        const lit = reduced || anchorY >= ys[i] - 8;
        el.classList.toggle("is-lit", lit);
        if (lit) cur = i;
      });
      stations.forEach((el, i) => el.classList.toggle("is-current", i === cur));
      wrap.classList.toggle("rt-done", anchorY >= y1 - 4);

      if (cur !== lastActive) { lastActive = cur; setActive(cur); }
      const hud = rect.top < vh * 0.6 && rect.bottom > vh * 0.45;
      if (hud !== lastHud) { lastHud = hud; setHudOn(hud); }
    };

    const onScroll = () => { if (!raf) raf = requestAnimationFrame(update); };
    const ro = new ResizeObserver(() => { build(); update(); });
    ro.observe(map);
    build();
    update();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      ro.disconnect();
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);

  const cur = phases[Math.min(active, phases.length - 1)];

  return (
    <section className="rt" ref={wrapRef} data-screen-label="Process route">
      <div className="rt__bg" aria-hidden="true">
        <span className="rt__bg-grid"></span>
        <span className="rt__bg-glow"></span>
      </div>

      <div className="rt__intro container">
        <span className="rt__eyebrow">The route</span>
        <h2 className="rt__headline">
          Twelve weeks.<br />Six stations.<br /><em>One launch.</em>
        </h2>
        <p className="rt__sub">Keep scrolling — the line draws as you travel.</p>
      </div>

      <div className="rt__map container" ref={mapRef}>
        <svg className="rt__svg" ref={svgRef} aria-hidden="true" preserveAspectRatio="none">
          <defs>
            <linearGradient id="rt-grad" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" stopColor="oklch(0.72 0.18 285)" />
              <stop offset="0.25" stopColor="oklch(0.72 0.17 255)" />
              <stop offset="0.5" stopColor="oklch(0.75 0.15 215)" />
              <stop offset="0.75" stopColor="oklch(0.78 0.16 150)" />
              <stop offset="1" stopColor="oklch(0.82 0.16 80)" />
            </linearGradient>
          </defs>
          <path className="rt__base" ref={baseRef} />
          <path className="rt__line" ref={lineRef} stroke="url(#rt-grad)" />
          <g className="rt__traveler" ref={travelerRef}>
            <circle className="rt__traveler-halo" r="17" />
            <circle className="rt__traveler-ring" r="10" />
            <circle className="rt__traveler-core" r="5" />
          </g>
        </svg>

        <ol className="rt__stations">
          {phases.map((ph, i) => (
            <li
              key={i}
              className="rt-station"
              style={{ "--acc": ph.accent }}
              data-screen-label={`Station ${i + 1} — ${ph.title}`}
            >
              <div className="rt-station__nodecell" aria-hidden="true">
                <span className="rt-node">
                  <span className="rt-node__pulse"></span>
                  <span className="rt-node__core">{RT_PAD(i + 1)}</span>
                </span>
              </div>
              <div className="rt-card">
                <span className="rt-card__big" aria-hidden="true">{RT_PAD(i + 1)}</span>
                <header className="rt-card__head">
                  <span className="rt-card__stn">STN {RT_PAD(i + 1)}</span>
                  <span className="rt-card__week">{ph.week}</span>
                  <span className="rt-card__dur">{ph.duration}</span>
                </header>
                <h3 className="rt-card__title">{ph.title}</h3>
                <p className="rt-card__desc">{ph.desc}</p>
                <ul className="rt-card__bullets">
                  {ph.bullets.map((b, bi) => (
                    <li key={b} style={{ "--i": bi }}>{b}</li>
                  ))}
                </ul>
                <footer className="rt-card__foot">
                  <span className="rt-card__foot-label">You leave with</span>
                  <strong className="rt-card__foot-val">{ph.deliverable}</strong>
                </footer>
              </div>
            </li>
          ))}
        </ol>
      </div>

      <div className="rt__finale" data-screen-label="Destination — live">
        <span className="rt__finale-burst" aria-hidden="true"></span>
        <span className="rt__finale-flag" aria-hidden="true">
          <svg width="20" height="20" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
            <path d="M3 14.5V2.2" />
            <path d="M3 2.5h9.5l-2.2 2.8 2.2 2.8H3" />
          </svg>
        </span>
        <h3 className="rt__finale-title">You're <em>live.</em></h3>
        <p className="rt__finale-text">
          Six stations behind you, an app with your name on it in both stores —
          and the same team one message away.
        </p>
        <div className="rt__finale-ctas">
          <a href="contact.html" className="btn btn--primary">Start at station 01 <Arrow /></a>
          <a href="pricing.html" className="btn btn--ghost-dark">See pricing</a>
        </div>
      </div>

      <div className={`rt-hud ${hudOn ? "is-on" : ""}`} aria-hidden="true">
        <span className="rt-hud__stn">STN {RT_PAD(active + 1)}<em>/{RT_PAD(phases.length)}</em></span>
        <span className="rt-hud__sep"></span>
        <span className="rt-hud__title">{cur.title}</span>
        <span className="rt-hud__week">{cur.week}</span>
        <span className="rt-hud__bar"><span style={{ width: `${((active + 1) / phases.length) * 100}%` }}></span></span>
      </div>
    </section>
  );
}

window.ProcessJourney = ProcessJourney;
