// track.jsx — generates the snaking race-track SVG path,
// exposes path utilities (length, point + tangent at distance),
// and renders the asphalt + dashed centerline + (faint) progress glow.
//
// Coordinate system: SVG has width/height in CSS pixels (no viewBox
// scaling) so path coords ARE document pixel coords.

const { useEffect, useMemo, useRef, useState } = React;

/* Build a smooth path from waypoints using catmull-rom-ish cubic beziers.
   waypoints: [{x, y}] in pixels.
   The "tension" parameter softens or sharpens the curves. */
function buildSmoothPath(points, tension = 0.5) {
  if (points.length < 2) return "";
  const p = points;
  let d = `M ${p[0].x} ${p[0].y}`;
  for (let i = 0; i < p.length - 1; i++) {
    const p0 = p[i - 1] || p[i];
    const p1 = p[i];
    const p2 = p[i + 1];
    const p3 = p[i + 2] || p2;

    // Cubic control points (Catmull-Rom -> Bezier)
    const c1x = p1.x + ((p2.x - p0.x) / 6) * tension * 2;
    const c1y = p1.y + ((p2.y - p0.y) / 6) * tension * 2;
    const c2x = p2.x - ((p3.x - p1.x) / 6) * tension * 2;
    const c2y = p2.y - ((p3.y - p1.y) / 6) * tension * 2;

    d += ` C ${c1x.toFixed(2)} ${c1y.toFixed(2)}, ${c2x.toFixed(2)} ${c2y.toFixed(2)}, ${p2.x.toFixed(2)} ${p2.y.toFixed(2)}`;
  }
  return d;
}

/* Given waypoint definitions in (xFraction, yPx), build absolute pixel points
   based on the container width. */
function resolveWaypoints(defs, width) {
  return defs.map((d) => ({ x: d.xFrac * width, y: d.y }));
}

/* Hook: subscribe to scrollY and return (scrollY, viewportH, docH). */
function useScroll() {
  const [s, setS] = useState({ y: 0, vh: typeof window !== "undefined" ? window.innerHeight : 800 });
  useEffect(() => {
    let raf = 0;
    const tick = () => {
      raf = 0;
      setS({ y: window.scrollY || window.pageYOffset, vh: window.innerHeight });
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(tick); };
    const onResize = () => tick();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onResize);
    tick();
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onResize);
      cancelAnimationFrame(raf);
    };
  }, []);
  return s;
}

/* Hook: measure container size + reflow. */
function useSize(ref) {
  const [sz, setSz] = useState({ w: 0, h: 0 });
  useEffect(() => {
    if (!ref.current) return;
    const ro = new ResizeObserver(() => {
      const r = ref.current.getBoundingClientRect();
      setSz({ w: r.width, h: ref.current.scrollHeight });
    });
    ro.observe(ref.current);
    // also reobserve on window resize for height changes from media loads
    const onR = () => {
      const r = ref.current.getBoundingClientRect();
      setSz({ w: r.width, h: ref.current.scrollHeight });
    };
    window.addEventListener("resize", onR);
    // initial
    onR();
    // and a delayed pass to catch async content (videos, fonts)
    const t1 = setTimeout(onR, 400);
    const t2 = setTimeout(onR, 1200);
    return () => {
      ro.disconnect();
      window.removeEventListener("resize", onR);
      clearTimeout(t1);
      clearTimeout(t2);
    };
  }, [ref]);
  return sz;
}

window.useScroll = useScroll;
window.useSize = useSize;
window.buildSmoothPath = buildSmoothPath;
window.resolveWaypoints = resolveWaypoints;
