"use client";

import { useEffect, useRef } from "react";

export type TimelineStep = { title: string; body: string };

/**
 * Numbered steps with a rail that fills as the section scrolls past.
 *
 * The fill is a scaleY on a single gradient element, written directly to the
 * node inside a RAF — compositor-only work, so it costs nothing per tick. Each
 * step's marker lights up once the fill reaches it.
 */
export default function ScrollTimeline({ steps }: { steps: TimelineStep[] }) {
  const sectionRef = useRef<HTMLOListElement>(null);
  const fillRef = useRef<HTMLDivElement>(null);
  const markerRefs = useRef<(HTMLDivElement | null)[]>([]);
  const tickingRef = useRef(false);

  useEffect(() => {
    const list = sectionRef.current;
    const fill = fillRef.current;
    if (!list || !fill) return;

    const update = () => {
      const rect = list.getBoundingClientRect();
      const vh = window.innerHeight;
      // Fill tracks the rail from the moment it enters the lower third of the
      // viewport until its end passes the middle.
      const start = vh * 0.75;
      const end = -rect.height + vh * 0.5;
      const raw = (start - rect.top) / (start - end);
      const progress = Math.min(1, Math.max(0, raw));

      fill.style.transform = `scaleY(${progress.toFixed(4)})`;

      const filledPx = progress * rect.height;
      markerRefs.current.forEach((m) => {
        if (!m) return;
        // Each marker is absolutely positioned inside its own <li>, so
        // offsetTop measures from that <li> and is ~0 for every one of them.
        // Compare viewport rects against the list instead.
        const mRect = m.getBoundingClientRect();
        const centreInList = mRect.top + mRect.height / 2 - rect.top;
        m.dataset.reached = centreInList <= filledPx + 8 ? "true" : "false";
      });

      tickingRef.current = false;
    };

    const onScroll = () => {
      if (tickingRef.current) return;
      tickingRef.current = true;
      requestAnimationFrame(update);
    };

    update();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll, { passive: true });
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
    };
  }, [steps.length]);

  return (
    <ol ref={sectionRef} className="relative ml-1 pl-12 md:pl-16">
      {/* Rail */}
      <div className="absolute top-2 bottom-2 left-[15px] w-[3px] rounded-full bg-zinc-200 md:left-[23px]" />
      <div
        ref={fillRef}
        className="absolute top-2 bottom-2 left-[15px] w-[3px] origin-top rounded-full bg-gradient-to-b from-amber-500 to-orange-600 md:left-[23px]"
        style={{ transform: "scaleY(0)" }}
      />

      {steps.map((s, i) => (
        <li key={s.title} className="relative pb-12 last:pb-0">
          <div
            ref={(el) => {
              markerRefs.current[i] = el;
            }}
            data-reached="false"
            className="group absolute top-0 -left-12 flex h-8 w-8 items-center justify-center rounded-full border border-zinc-200 bg-white font-mono text-xs font-semibold text-zinc-400 shadow-[var(--pill-shadow)] transition-all duration-500 data-[reached=true]:border-transparent data-[reached=true]:bg-gradient-to-br data-[reached=true]:from-amber-500 data-[reached=true]:to-orange-600 data-[reached=true]:text-white md:-left-16 md:h-12 md:w-12 md:text-sm"
          >
            {String(i + 1).padStart(2, "0")}
          </div>
          <h3 className="text-lg font-semibold tracking-tight text-zinc-900 md:text-xl">
            {s.title}
          </h3>
          <p className="mt-2 max-w-[60ch] text-sm leading-relaxed text-zinc-600 md:text-base">
            {s.body}
          </p>
        </li>
      ))}
    </ol>
  );
}
