"use client";

import { useCallback, useEffect, useRef, useState } from "react";

type Link = { from: string; to: string };

/**
 * Overlays an SVG on the thread container and draws a connector from each
 * parent comment's avatar down into each of its replies' avatars, with a
 * light pulse travelling along the path.
 *
 * Positions are measured from the DOM rather than computed from layout
 * rules, so the lines stay correct no matter how the comments wrap or how
 * many replies are expanded.
 */
export function ThreadLines({
  containerRef,
  links,
  deps,
}: {
  containerRef: React.RefObject<HTMLDivElement | null>;
  links: Link[];
  deps: unknown[];
}) {
  const svgRef = useRef<SVGSVGElement>(null);
  const [paths, setPaths] = useState<{ d: string; mid: { x: number; y: number } }[]>([]);

  const draw = useCallback(() => {
    const container = containerRef.current;
    if (!container) return;
    const cr = container.getBoundingClientRect();
    const next: { d: string; mid: { x: number; y: number } }[] = [];

    for (const { from, to } of links) {
      const a = container.querySelector<HTMLElement>(`[data-thread-avatar="${from}"]`);
      const b = container.querySelector<HTMLElement>(`[data-thread-avatar="${to}"]`);
      if (!a || !b) continue;
      const ra = a.getBoundingClientRect();
      const rb = b.getBoundingClientRect();
      if (!ra.width || !rb.width) continue;

      // Start just under the parent avatar, end at the left edge of the reply's.
      const px = ra.left + ra.width / 2 - cr.left;
      const py = ra.bottom - cr.top - 4;
      const bx = rb.left - cr.left;
      const cy = rb.top + rb.height / 2 - cr.top;

      let d: string;
      if (bx + 20 <= px + 2) {
        d = `M ${px} ${py} L ${px} ${cy}`;
      } else {
        const r = Math.min(16, Math.max(6, cy - py - 6));
        d = `M ${px} ${py} L ${px} ${cy - r} Q ${px} ${cy} ${px + r} ${cy} L ${bx + 6} ${cy}`;
      }
      next.push({ d, mid: { x: px, y: (py + cy) / 2 } });
    }
    // Only when something has actually moved. Setting on every draw made
    // a new render, which made a new draw, without end.
    setPaths((prev) =>
      prev.length === next.length &&
      prev.every((p, i) => p.d === next[i].d)
        ? prev
        : next
    );
  }, [containerRef, links]);

  useEffect(() => {
    draw();
    // Re-measure after layout settles (fonts, images, expanding replies).
    const raf = requestAnimationFrame(draw);
    window.addEventListener("resize", draw);
    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("resize", draw);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [draw, ...deps]);

  if (paths.length === 0) return null;

  return (
    <svg
      ref={svgRef}
      aria-hidden
      className="absolute inset-0 w-full h-full pointer-events-none z-0 overflow-visible"
    >
      {paths.map((p, i) => (
        <g key={i}>
          <path d={p.d} className="thread-base" />
          <path
            d={p.d}
            className="thread-pulse"
            pathLength={100}
            style={{ animationDelay: `${i * 0.45}s` }}
          />
          <circle
            cx={p.mid.x}
            cy={p.mid.y}
            r={3}
            className="thread-dot"
            style={{ animationDelay: `${i * 0.45}s` }}
          />
        </g>
      ))}
    </svg>
  );
}
