// ScrollPath — a single crayon ribbon that winds through the entire homepage
// as the user scrolls. Fixed SVG overlay spanning the viewport; its path
// geometry is recomputed from [data-path-anchor] elements in the DOM, then
// stroke-dashoffset is bound to scroll progress.
//
// The anchors get rendered at their center points; the path threads between
// them with smooth cubic bezier curves. Crayon texture via the same filter
// used in HandMarks.jsx so it reads as part of the same handwritten world.
//
// Usage: drop <ScrollPath/> once in the App. Add data-path-anchor="left|right|center"
// on elements the line should pass near.

const ScrollPath = () => {
  const svgRef = React.useRef(null);
  const pathRef = React.useRef(null);
  const [state, setState] = React.useState({ w: 0, h: 0, d: "" });

  const compute = React.useCallback(() => {
    const W = window.innerWidth;
    const H = document.documentElement.scrollHeight;
    const anchors = Array.from(document.querySelectorAll("[data-path-anchor]"));
    if (!anchors.length) { setState({ w: W, h: H, d: "" }); return; }

    // Compute anchor absolute center points, sorted by y.
    const pts = anchors.map(el => {
      const r = el.getBoundingClientRect();
      const y = r.top + window.scrollY + r.height / 2;
      const side = el.getAttribute("data-path-anchor") || "center";
      const offX = parseFloat(el.getAttribute("data-path-offset-x") || "0");
      const offY = parseFloat(el.getAttribute("data-path-offset-y") || "0");
      let x;
      if (side === "left")  x = r.left + r.width * 0.18;
      else if (side === "right") x = r.left + r.width * 0.82;
      else x = r.left + r.width / 2;
      return { x: x + offX, y: y + offY };
    }).sort((a, b) => a.y - b.y);

    // Build a smooth path through the points with cubic bezier using
    // horizontal tangents scaled by inter-point gap — gives a ribbon-like feel.
    let d = `M ${pts[0].x.toFixed(1)} ${pts[0].y.toFixed(1)}`;
    for (let i = 1; i < pts.length; i++) {
      const p0 = pts[i - 1], p1 = pts[i];
      const dy = Math.max(80, (p1.y - p0.y) * 0.55);
      const c1x = p0.x, c1y = p0.y + dy;
      const c2x = p1.x, c2y = p1.y - dy;
      d += ` C ${c1x.toFixed(1)} ${c1y.toFixed(1)}, ${c2x.toFixed(1)} ${c2y.toFixed(1)}, ${p1.x.toFixed(1)} ${p1.y.toFixed(1)}`;
    }

    setState({ w: W, h: H, d });
  }, []);

  React.useEffect(() => {
    compute();
    const ro = new ResizeObserver(compute);
    ro.observe(document.body);
    window.addEventListener("resize", compute);
    // recompute a few times as fonts/images load
    const timers = [300, 900, 1800].map(t => setTimeout(compute, t));
    return () => {
      ro.disconnect();
      window.removeEventListener("resize", compute);
      timers.forEach(clearTimeout);
    };
  }, [compute]);

  // Bind scroll progress to stroke-dashoffset.
  React.useEffect(() => {
    const path = pathRef.current;
    if (!path) return;
    let len = 0;
    try { len = path.getTotalLength(); } catch (e) { return; }
    if (!len) return;
    path.style.strokeDasharray = `${len}`;
    path.style.strokeDashoffset = `${len}`;

    let raf = null;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        raf = null;
        const scrollable = document.documentElement.scrollHeight - window.innerHeight;
        // Reveal path slightly ahead of the viewport bottom so the line feels
        // like it's drawing *into* the next section as you approach it.
        const progress = Math.max(0, Math.min(1,
          (window.scrollY + window.innerHeight * 0.72) / scrollable
        ));
        path.style.strokeDashoffset = `${len * (1 - progress)}`;
      });
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, [state.d]);

  if (!state.d) return null;

  return (
    <svg
      ref={svgRef}
      aria-hidden="true"
      style={{
        position: "absolute",
        top: 0, left: 0,
        width: state.w, height: state.h,
        pointerEvents: "none",
        zIndex: 5,
        overflow: "visible",
      }}
      width={state.w}
      height={state.h}
    >
      <defs>
        <filter id="scroll-path-crayon" x="-5%" y="-50%" width="110%" height="200%">
          <feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" seed="4"/>
          <feDisplacementMap in="SourceGraphic" scale="2.2"/>
        </filter>
      </defs>

      {/* Soft outer halo — ocean */}
      <path
        d={state.d}
        fill="none"
        stroke="var(--ocean-500)"
        strokeWidth="14"
        strokeLinecap="round"
        strokeLinejoin="round"
        opacity="0.08"
      />
      {/* Body — crayon with texture */}
      <path
        ref={pathRef}
        d={state.d}
        fill="none"
        stroke="var(--ocean-500)"
        strokeWidth="6"
        strokeLinecap="round"
        strokeLinejoin="round"
        opacity="0.55"
        filter="url(#scroll-path-crayon)"
      />
    </svg>
  );
};

window.ScrollPath = ScrollPath;
