"use client";

import { useEffect, useRef, useState } from "react";
import { usePathname } from "next/navigation";

// One target column width; the real gap is derived so columns evenly fill the
// viewport. Lines, waves and boxes all use this same `gap` → shared grid.
const TARGET_GAP = 96;
const INSET = 5; // box margin inside its grid cell
const MAX_BEAMS = 4;
const MAX_BOXES = 7;

type Grid = { gap: number; cols: number; rows: number };
type Beam = { id: number; col: number; top: number; duration: number };
type Box = { id: number; col: number; row: number; duration: number; delay: number };

const LINE_COLOR = "var(--grid-line)";

/**
 * Site-wide background (mounted once in the root layout).
 * - VERTICAL lines only, drawn on a grid of pitch `gap`.
 * - An occasional AI-coral light/current travels top→bottom exactly ON a line.
 * - Uniform, grid-cell-aligned boxes that fade in → relocate → fade out —
 *   HOMEPAGE ONLY.
 * Everything shares the same grid coordinate system, so nothing is offset.
 * Respects prefers-reduced-motion (beams + box motion off; lines stay).
 */
export function SiteBackground() {
  const ref = useRef<HTMLDivElement>(null);
  const [grid, setGrid] = useState<Grid>({ gap: TARGET_GAP, cols: 14, rows: 9 });
  const gridRef = useRef(grid);
  useEffect(() => {
    gridRef.current = grid;
  }, [grid]);

  const [beams, setBeams] = useState<Beam[]>([]);
  const [boxes, setBoxes] = useState<Box[]>([]);
  const idRef = useRef(0);

  const isHome = usePathname() === "/";

  // Measure the viewport and derive the shared grid.
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const measure = () => {
      const w = el.clientWidth || window.innerWidth || 1280;
      const h = el.clientHeight || window.innerHeight || 800;
      const cols = Math.max(4, Math.round(w / TARGET_GAP));
      const gap = Math.max(48, Math.floor(w / cols));
      const rows = Math.max(3, Math.floor(h / gap));
      setGrid({ gap, cols, rows });
    };
    measure();
    const ro = new ResizeObserver(measure);
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  // Travelling AI-current beams (all pages).
  useEffect(() => {
    const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
    if (mq.matches) return;

    let active = true;
    let timer = 0;
    const spawn = () => {
      if (!active) return;
      const { cols } = gridRef.current;
      const col = 1 + Math.floor(Math.random() * Math.max(1, cols - 1));
      const duration = 2600 + Math.random() * 2400;
      // Anchor the beam near the CURRENT scroll position so it is visible when
      // it spawns; because the whole layer scrolls with the page (absolute, not
      // fixed), the beam then travels down and scrolls away with the content.
      const vh = window.innerHeight || 800;
      const top = window.scrollY + Math.random() * vh * 0.55;
      const id = idRef.current++;
      setBeams((prev) => {
        const next = [...prev, { id, col, top, duration }];
        return next.length > MAX_BEAMS ? next.slice(next.length - MAX_BEAMS) : next;
      });
      timer = window.setTimeout(spawn, 1000 + Math.random() * 2400);
    };
    timer = window.setTimeout(spawn, 600);
    return () => {
      active = false;
      clearTimeout(timer);
    };
  }, []);

  // Grid boxes — HOMEPAGE ONLY (req 10), fade in → relocate → fade out.
  useEffect(() => {
    const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
    if (!isHome || mq.matches) {
      // eslint-disable-next-line react-hooks/set-state-in-effect -- intentional: clears boxes when leaving home or reduced-motion turns on (SSR-safe)
      setBoxes([]);
      return;
    }
    const make = (stagger: boolean): Box => {
      const { cols, rows } = gridRef.current;
      return {
        id: idRef.current++,
        col: Math.floor(Math.random() * cols),
        row: Math.floor(Math.random() * rows),
        duration: 5200 + Math.random() * 3800,
        delay: stagger ? Math.random() * 3500 : 0,
      };
    };
    setBoxes(Array.from({ length: MAX_BOXES }, () => make(true)));
    return () => setBoxes([]);
  }, [isHome]);

  const removeBeam = (id: number) =>
    setBeams((prev) => prev.filter((b) => b.id !== id));

  // On fade-out, drop the box and spawn a fresh one at a new grid cell.
  const recycleBox = (id: number) =>
    setBoxes((prev) => {
      const { cols, rows } = gridRef.current;
      const fresh: Box = {
        id: idRef.current++,
        col: Math.floor(Math.random() * cols),
        row: Math.floor(Math.random() * rows),
        duration: 5200 + Math.random() * 3800,
        delay: 0,
      };
      return prev.filter((b) => b.id !== id).concat(fresh);
    });

  const { gap, cols } = grid;
  const boxSize = Math.max(10, gap - INSET * 2);

  return (
    <div
      ref={ref}
      aria-hidden
      className="pointer-events-none absolute inset-0 -z-10 overflow-hidden"
    >
      {/* Vertical lines: a 1px line at the start of every grid column (x = i*gap) */}
      <div
        className="absolute inset-0"
        style={{
          backgroundImage: `repeating-linear-gradient(to right, ${LINE_COLOR} 0, ${LINE_COLOR} 1px, transparent 1px, transparent ${gap}px)`,
        }}
      />

      {/* Homepage-only grid boxes */}
      {boxes.map((b) => (
        <span
          key={b.id}
          onAnimationEnd={() => recycleBox(b.id)}
          className="absolute rounded-[3px] bg-foreground"
          style={{
            left: Math.min(b.col, cols - 1) * gap + INSET,
            top: b.row * gap + INSET,
            width: boxSize,
            height: boxSize,
            opacity: 0,
            animationName: "box-cycle",
            animationDuration: `${b.duration}ms`,
            animationTimingFunction: "ease-in-out",
            animationDelay: `${b.delay}ms`,
            animationFillMode: "forwards",
          }}
        />
      ))}

      {/* AI-current beams — travel exactly on a vertical line, with a narrow glow.
          Dimmed as a group on mobile so the signal stays subtle. */}
      <div className="opacity-55 max-sm:opacity-30">
        {beams.map((beam) => (
          <span
            key={beam.id}
            onAnimationEnd={() => removeBeam(beam.id)}
            className="absolute h-[22vh] w-0.5 sm:h-[26vh]"
            style={{
              left: beam.col * gap,
              top: beam.top,
              marginLeft: "-0.5px",
              background:
                "linear-gradient(to bottom, transparent, rgba(79, 218, 241, 0.7) 45%, rgba(103, 183, 231, 0.7) 55%, transparent)",
              boxShadow: "0 0 var(--beam-glow) 0 rgba(79, 218, 241, 0.4)",
              animationName: "line-current",
              animationDuration: `${beam.duration}ms`,
              animationTimingFunction: "linear",
              animationFillMode: "forwards",
            }}
          />
        ))}
      </div>
    </div>
  );
}
