"use client";

import { useRef } from "react";
import { motion, useScroll, useTransform } from "motion/react";

/**
 * Two courses of knitting, drawn.
 *
 * A course is one continuous yarn: it arches up into a head, dives down into a
 * bight, and repeats. The course below runs half a wale out of phase and sits
 * high enough that its heads push up through the bights of the course above.
 * That interlock is the whole difference between a knit and a weave, which is
 * exactly what the heading above it claims.
 */

const WALE = 84; // one full head plus one bight
const HALF = WALE / 2;
const ARM = 23; // half the width of a head
const RISE = 46; // how far a head arches above the course line
const COURSES = 9;

/** One course of loops, as a single continuous path. */
function coursePath(startX: number, y: number, count: number): string {
  const parts = [`M${startX - ARM} ${y}`];

  for (let i = 0; i < count; i++) {
    const centre = startX + i * WALE;

    // Up and over the head.
    parts.push(
      `C${centre - ARM} ${y - RISE}, ${centre + ARM} ${y - RISE}, ${centre + ARM} ${y}`,
    );

    // Down through the bight, arriving at the next head.
    const next = centre + WALE - ARM;
    parts.push(
      `C${centre + ARM} ${y + RISE}, ${next} ${y + RISE}, ${next} ${y}`,
    );
  }

  return parts.join(" ");
}

export function KnitLoop() {
  const ref = useRef<HTMLDivElement>(null);

  const { scrollYProgress } = useScroll({
    target: ref,
    offset: ["start 90%", "end 50%"],
  });

  // The second course is raised by less than a full head, so it interlocks
  // rather than sitting underneath.
  const courses = [
    { d: coursePath(60, 78, COURSES), opacity: 1, width: 3.2, start: 0 },
    { d: coursePath(60 + HALF, 130, COURSES), opacity: 0.55, width: 3.2, start: 0.18 },
  ];

  return (
    <div ref={ref} className="relative w-full" aria-hidden="true">
      <svg viewBox="0 0 830 210" className="w-full overflow-visible">
        <defs>
          <linearGradient id="knit-thread" x1="0" x2="1">
            <stop offset="0%" stopColor="var(--thread)" stopOpacity="0.28" />
            <stop offset="38%" stopColor="var(--thread)" stopOpacity="1" />
            <stop offset="82%" stopColor="var(--cotton)" stopOpacity="0.92" />
            <stop offset="100%" stopColor="var(--cotton)" stopOpacity="0.22" />
          </linearGradient>
        </defs>

        {/* Lower course first, so the upper yarn crosses over it. */}
        {[...courses].reverse().map((course) => (
          <Course key={course.start} course={course} progress={scrollYProgress} />
        ))}
      </svg>
    </div>
  );
}

function Course({
  course,
  progress,
}: {
  course: { d: string; opacity: number; width: number; start: number };
  progress: ReturnType<typeof useScroll>["scrollYProgress"];
}) {
  // The yarn feeds in left to right, the direction a knitting carriage travels.
  const pathLength = useTransform(
    progress,
    [course.start, course.start + 0.62],
    [0, 1],
  );

  return (
    <motion.path
      d={course.d}
      fill="none"
      stroke="url(#knit-thread)"
      strokeWidth={course.width}
      strokeLinecap="round"
      opacity={course.opacity}
      style={{ pathLength }}
    />
  );
}
