"use client";

import { useEffect, useRef } from "react";
import { useReducedMotion } from "motion/react";

const COLORS = {
  bg: "#030506",
  line: "rgba(44, 53, 58, 0.46)",
  dot: "rgba(244, 247, 248, 0.38)",
  cyan: "rgba(0, 240, 255, 0.82)",
};

const GRID_COLUMNS = 14;
const GRID_ROWS = 13;
const PULSE_PERIOD_MS = 5200;

function projectX(width: number, xIndex: number, yIndex: number, time: number) {
  const normalizedX = (xIndex / (GRID_COLUMNS - 1) - 0.5) * 2;
  const normalizedY = yIndex / (GRID_ROWS - 1);
  const depth = normalizedY * normalizedY;

  return (
    width * 0.5 +
    normalizedX * width * (0.13 + depth * 0.5) +
    Math.sin(time * 0.00008 + yIndex * 0.45) * 7
  );
}

function projectY(height: number, yIndex: number, time: number) {
  const normalizedY = yIndex / (GRID_ROWS - 1);
  const drift = Math.sin(time * 0.00012 + yIndex * 0.7) * 5;

  return height * 0.24 + height * 0.82 * normalizedY * normalizedY + drift;
}

export function HeroCanvas() {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const shouldReduceMotion = useReducedMotion();

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) {
      return;
    }

    const context = canvas.getContext("2d", { alpha: true });
    if (!context) {
      return;
    }

    let width = 0;
    let height = 0;
    let dpr = 1;
    let frameId = 0;
    let isMounted = true;
    let resizeObserver: ResizeObserver | null = null;

    const resize = () => {
      const rect = canvas.getBoundingClientRect();
      dpr = Math.min(window.devicePixelRatio || 1, 2);
      width = Math.max(1, rect.width);
      height = Math.max(1, rect.height);
      canvas.width = Math.floor(width * dpr);
      canvas.height = Math.floor(height * dpr);
      context.setTransform(dpr, 0, 0, dpr, 0, 0);

      if (shouldReduceMotion) {
        draw(0);
      }
    };

    const drawGridLines = (time: number) => {
      context.lineWidth = 1;
      context.strokeStyle = COLORS.line;

      for (let column = 0; column < GRID_COLUMNS; column += 1) {
        context.beginPath();
        for (let row = 0; row < GRID_ROWS; row += 1) {
          const x = projectX(width, column, row, time);
          const y = projectY(height, row, time);
          if (row === 0) {
            context.moveTo(x, y);
          } else {
            context.lineTo(x, y);
          }
        }
        context.stroke();
      }

      for (let row = 0; row < GRID_ROWS; row += 1) {
        context.beginPath();
        for (let column = 0; column < GRID_COLUMNS; column += 1) {
          const x = projectX(width, column, row, time);
          const y = projectY(height, row, time);
          if (column === 0) {
            context.moveTo(x, y);
          } else {
            context.lineTo(x, y);
          }
        }
        context.stroke();
      }
    };

    const drawDots = (time: number) => {
      context.fillStyle = COLORS.dot;

      for (let row = 0; row < GRID_ROWS; row += 1) {
        const normalizedY = row / (GRID_ROWS - 1);
        const radius = 0.9 + normalizedY * 1.15;

        for (let column = 0; column < GRID_COLUMNS; column += 1) {
          context.beginPath();
          context.arc(
            projectX(width, column, row, time),
            projectY(height, row, time),
            radius,
            0,
            Math.PI * 2,
          );
          context.fill();
        }
      }
    };

    const drawPulse = (time: number) => {
      if (shouldReduceMotion) {
        return;
      }

      const progress = (time % PULSE_PERIOD_MS) / PULSE_PERIOD_MS;
      const row = 8;
      const maxColumn = Math.min(
        GRID_COLUMNS - 1,
        Math.max(1, Math.floor(progress * (GRID_COLUMNS + 2))),
      );

      context.save();
      context.globalAlpha = progress > 0.84 ? (1 - progress) / 0.16 : 1;
      context.lineWidth = 2;
      context.strokeStyle = COLORS.cyan;
      context.shadowBlur = 14;
      context.shadowColor = COLORS.cyan;
      context.beginPath();

      for (let column = 0; column <= maxColumn; column += 1) {
        const x = projectX(width, column, row, time);
        const y = projectY(height, row, time);
        if (column === 0) {
          context.moveTo(x, y);
        } else {
          context.lineTo(x, y);
        }
      }

      context.stroke();
      context.restore();
    };

    const draw = (time: number) => {
      context.clearRect(0, 0, width, height);
      context.fillStyle = COLORS.bg;
      context.fillRect(0, 0, width, height);
      drawGridLines(time);
      drawDots(time);
      drawPulse(time);
    };

    const tick = (time: number) => {
      if (!isMounted) {
        return;
      }

      draw(time);
      frameId = window.requestAnimationFrame(tick);
    };

    resize();
    if ("ResizeObserver" in window) {
      resizeObserver = new ResizeObserver(resize);
      resizeObserver.observe(canvas);
    }
    window.addEventListener("resize", resize, { passive: true });

    if (!shouldReduceMotion) {
      frameId = window.requestAnimationFrame(tick);
    }

    return () => {
      isMounted = false;
      resizeObserver?.disconnect();
      window.removeEventListener("resize", resize);
      if (frameId) {
        window.cancelAnimationFrame(frameId);
      }
    };
  }, [shouldReduceMotion]);

  return (
    <canvas
      ref={canvasRef}
      aria-hidden="true"
      className="pointer-events-none absolute inset-0 h-full w-full opacity-[0.4]"
    />
  );
}
