/* JourneyPath — straight vertical scroll-driven path between the
   careers banner and the recruiting game. Six stops total:
     start label  → 4 milestone projects → end label
   The line is dead-straight (matches the user's redesign direction),
   text content sits to the side of milestones and ABOVE/BELOW the
   start/end labels (not on top of them), and dots/text light up as
   the user scrolls past. The whole thing reads as a quiet editorial
   spacer that hands off to the game below. */

const JourneyPath = ({ data }) => {
  /* Six stops: start label + 4 milestones + end label. */
  const stops = [
    { kind: "start", title: data.start },
    ...data.steps.map(s => ({ kind: "milestone", ...s })),
    { kind: "end",   title: data.end },
  ];
  const total = stops.length;

  const [passed, setPassed] = React.useState(0);
  const [pathPct, setPathPct] = React.useState(0);
  /* Line span — pinned between the bottom of the start label and the
     top of the end label, in pixels relative to the section. Measured
     in the same scroll/resize handler so it survives reflow. */
  const [lineSpan, setLineSpan] = React.useState({ top: 0, height: 0 });
  const stopRefs = React.useRef([]);
  const sectionRef = React.useRef(null);

  React.useEffect(() => {
    if (typeof window === "undefined") return;
    let raf = 0;
    const compute = () => {
      raf = 0;
      const vh = window.innerHeight;
      const vpMid = vh * 0.55;
      let lastPassed = -1;
      stopRefs.current.forEach((el, i) => {
        if (!el) return;
        const r = el.getBoundingClientRect();
        const cy = r.top + r.height / 2;
        if (cy <= vpMid) lastPassed = i;
      });
      setPassed(p => (p === lastPassed ? p : lastPassed));
      const s = sectionRef.current;
      if (s) {
        const sr = s.getBoundingClientRect();
        const span = sr.height + vh * 0.5;
        /* +15% viewport-height offset shifts the fill-start a touch
           earlier — the line begins illuminating before the section
           top has fully crossed into view, instead of waiting until
           the section is on-screen. Net effect: gentler / earlier
           reveal as the user scrolls in. */
        const dist = (vh - sr.top) + vh * 0.15;
        const pct = Math.max(0, Math.min(1, dist / span));
        setPathPct(p => (Math.abs(p - pct) < 0.005 ? p : pct));

        /* Pin the SVG between the start label's bottom and the end
           label's top — the line starts UNDER "Your journey at
           Aguilera" and finishes BEFORE "…begins with a challenge",
           rather than running edge-to-edge of the section. */
        const startEl = stopRefs.current[0];
        const endEl   = stopRefs.current[stopRefs.current.length - 1];
        if (startEl && endEl) {
          const startR = startEl.getBoundingClientRect();
          const endR   = endEl.getBoundingClientRect();
          /* Find the inner content's painted bottom/top — the
             .journey__content box, not the outer flex stop — so we
             clear the text exactly at its background edge. */
          const startContent = startEl.querySelector(".journey__content");
          const endContent   = endEl.querySelector(".journey__content");
          const startBottom = startContent
            ? startContent.getBoundingClientRect().bottom
            : startR.bottom;
          const endTop = endContent
            ? endContent.getBoundingClientRect().top
            : endR.top;
          /* Clearance gaps so the line visibly ends BEFORE the text,
             not flush against it. The end gap is larger because the
             closing phrase ("Tu trayectoria empieza con un reto") is
             a heavier headline and wants more breathing room. */
          const TOP_GAP = 12;
          /* END_GAP ≈ one line-height of the closing headline
             (clamp(28px, 3.6vw, 48px) at line-height 1.2 → ~48-58px
             rendered) so the line ends a full text-height ABOVE the
             phrase, not flush with it. */
          const END_GAP = 120;
          const top    = (startBottom - sr.top) + TOP_GAP;
          const height = Math.max(0, endTop - startBottom - TOP_GAP - END_GAP);
          setLineSpan(prev =>
            (Math.abs(prev.top - top) < 0.5 && Math.abs(prev.height - height) < 0.5)
              ? prev
              : { top, height });
        }
      }
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(compute); };
    compute();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll, { passive: true });
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      if (raf) cancelAnimationFrame(raf);
    };
  }, [total]);

  /* Path length is implicit in the SVG height (1000 units). Straight
     vertical line from (50, 0) to (50, 1000) — no curves, no winding.
     The drawn-in effect comes from stroke-dasharray + offset driven
     by pathPct (scroll progress through the section). */
  const PATH_LEN = 1000;
  const offset = PATH_LEN * (1 - pathPct);

  return (
    <section ref={sectionRef} className="journey">
      <div className="journey__inner">
        {/* SVG line — vector-effect="non-scaling-stroke" keeps the
            stroke at its CSS-pixel width regardless of viewBox scaling
            (otherwise the 1.5px stroke would compress to a sub-pixel
            sliver inside a 2px-wide SVG and disappear). */}
        {/* SVG span is set inline so the line starts at the start
            label's bottom edge and ends at the end label's top edge
            (lineSpan is measured each scroll/resize tick). */}
        <svg className="journey__svg" viewBox="0 0 100 1000" preserveAspectRatio="none" aria-hidden="true"
             style={{ top: lineSpan.top, height: lineSpan.height }}>
          <line x1="50" y1="0" x2="50" y2="1000" className="journey__track"
                vectorEffect="non-scaling-stroke" />
          <line x1="50" y1="0" x2="50" y2="1000" className="journey__line"
                vectorEffect="non-scaling-stroke"
                style={{strokeDasharray: PATH_LEN, strokeDashoffset: offset}} />
        </svg>
        <ol className="journey__stops">
          {stops.map((s, i) => (
            <li key={i}
                ref={el => stopRefs.current[i] = el}
                className={"journey__stop journey__stop--" + s.kind +
                           (s.kind === "milestone"
                              ? (i % 2 === 1 ? " is-right" : " is-left")
                              : "") +
                           (i <= passed ? " is-passed" : "")}>
              {/* Milestones get a dot dead-centre on the line. Start
                  and end stops skip the dot entirely — the line should
                  appear to emerge from / dissolve into the centre of
                  the phrase, so the text itself is the visual cap. */}
              {s.kind === "milestone" && (
                <span className="journey__dot-wrap" aria-hidden="true">
                  <span className="journey__dot" />
                </span>
              )}
              <div className="journey__content">
                {s.tag && <span className="journey__tag">{s.tag}</span>}
                <div className="journey__title">{s.title}</div>
              </div>
            </li>
          ))}
        </ol>
      </div>
    </section>
  );
};

Object.assign(window, { JourneyPath });
