import { useEffect, useRef } from "react";

export interface ASCIIBackgroundProps {
  mouseX?: number | null;
  mouseY?: number | null;
}

// ----- Particles.js-style config (matching particles.js behavior) -----
const PARTICLES_COUNT = 80;
const PARTICLE_RADIUS = 2.5;
const PARTICLE_RADIUS_RANDOM = true;
const PARTICLE_OPACITY = 0.5;
const LINE_LINKED_ENABLE = true;
const LINE_LINKED_DISTANCE = 150;
const LINE_LINKED_OPACITY = 0.4;
const LINE_LINKED_WIDTH = 1;
const MOVE_SPEED = 2;
const MOVE_OUT_MODE: "out" | "bounce" = "out";
const GRAB_DISTANCE = 100;
const GRAB_LINE_OPACITY = 1;
const REPULSE_ENABLE = true;
const REPULSE_DISTANCE = 200;
const REPULSE_FORCE = 50;

interface Particle {
  x: number;
  y: number;
  vx: number;
  vy: number;
  radius: number;
  opacity: number;
}

const BOX_SIZE = 120;

export default function ASCIIBackground({ mouseX, mouseY }: ASCIIBackgroundProps) {
  const svgRef = useRef<SVGSVGElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const particlesRef = useRef<Particle[]>([]);
  const mousePosRef = useRef<{ x: number; y: number } | null>(null);
  const x = mouseX ?? 0.5;
  const y = mouseY ?? 0.5;
  const isActive = mouseX != null && mouseY != null;

  useEffect(() => {
    mousePosRef.current =
      mouseX != null && mouseY != null ? { x: mouseX, y: mouseY } : null;
  }, [mouseX, mouseY]);

  // ----- Particles.js-style: init and animation loop -----
  useEffect(() => {
    const canvas = canvasRef.current;
    const container = containerRef.current;
    if (!canvas || !container) return;

    const ctx = canvas.getContext("2d");
    if (!ctx) return;

    const setCanvasSize = () => {
      if (!container) return;
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const rect = container.getBoundingClientRect();
      const w = rect.width;
      const h = rect.height;
      canvas.width = w * dpr;
      canvas.height = h * dpr;
      canvas.style.width = `${w}px`;
      canvas.style.height = `${h}px`;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      return { w, h, dpr };
    };

    const createParticles = (w: number, h: number): Particle[] => {
      const arr: Particle[] = [];
      for (let i = 0; i < PARTICLES_COUNT; i++) {
        const radius = PARTICLE_RADIUS_RANDOM
          ? PARTICLE_RADIUS * (0.5 + Math.random())
          : PARTICLE_RADIUS;
        arr.push({
          x: Math.random() * w,
          y: Math.random() * h,
          vx: (Math.random() - 0.5) * 2,
          vy: (Math.random() - 0.5) * 2,
          radius,
          opacity: PARTICLE_OPACITY,
        });
      }
      return arr;
    };

    const size = setCanvasSize();
    if (!size) return;
    let { w, h } = size;

    if (particlesRef.current.length === 0 && w > 0 && h > 0) {
      particlesRef.current = createParticles(w, h);
    }

    const resizeObserver = new ResizeObserver(() => {
      const next = setCanvasSize();
      if (next) {
        w = next.w;
        h = next.h;
      }
    });
    resizeObserver.observe(container);

    let rafId: number;

    const draw = () => {
      if (particlesRef.current.length === 0 && w > 0 && h > 0) {
        particlesRef.current = createParticles(w, h);
      }
      const particles = particlesRef.current;
      const mouse = mousePosRef.current;
      const mousePos =
        mouse != null ? { x: mouse.x * w, y: mouse.y * h } : null;

      ctx.clearRect(0, 0, w, h);

      const ms = MOVE_SPEED / 2;
      for (let i = 0; i < particles.length; i++) {
        const p = particles[i];
        p.x += p.vx * ms;
        p.y += p.vy * ms;

        if (MOVE_OUT_MODE === "out") {
          if (p.x - p.radius > w) {
            p.x = -p.radius;
            p.y = Math.random() * h;
          } else if (p.x + p.radius < 0) {
            p.x = w + p.radius;
            p.y = Math.random() * h;
          }
          if (p.y - p.radius > h) {
            p.y = -p.radius;
            p.x = Math.random() * w;
          } else if (p.y + p.radius < 0) {
            p.y = h + p.radius;
            p.x = Math.random() * w;
          }
        } else {
          if (p.x + p.radius > w) p.vx = -p.vx;
          else if (p.x - p.radius < 0) p.vx = -p.vx;
          if (p.y + p.radius > h) p.vy = -p.vy;
          else if (p.y - p.radius < 0) p.vy = -p.vy;
        }
      }

      if (REPULSE_ENABLE && mousePos) {
        for (let i = 0; i < particles.length; i++) {
          const p = particles[i];
          const dx = p.x - mousePos.x;
          const dy = p.y - mousePos.y;
          const dist = Math.sqrt(dx * dx + dy * dy);
          if (dist > 0 && dist <= REPULSE_DISTANCE) {
            const normX = dx / dist;
            const normY = dy / dist;
            const repulseFactor =
              (1 / REPULSE_DISTANCE) *
              (-1 * Math.pow(dist / REPULSE_DISTANCE, 2) + 1) *
              REPULSE_DISTANCE *
              (REPULSE_FORCE / 100);
            const clamped = Math.min(repulseFactor, 50);
            p.x += normX * clamped;
            p.y += normY * clamped;
          }
        }
      }

      if (LINE_LINKED_ENABLE) {
        for (let i = 0; i < particles.length; i++) {
          for (let j = i + 1; j < particles.length; j++) {
            const p1 = particles[i];
            const p2 = particles[j];
            const dx = p1.x - p2.x;
            const dy = p1.y - p2.y;
            const dist = Math.sqrt(dx * dx + dy * dy);
            if (dist <= LINE_LINKED_DISTANCE) {
              const opacity =
                LINE_LINKED_OPACITY -
                (dist / (1 / LINE_LINKED_OPACITY)) / LINE_LINKED_DISTANCE;
              if (opacity > 0) {
                ctx.strokeStyle = `rgba(107, 114, 128, ${opacity})`;
                ctx.lineWidth = LINE_LINKED_WIDTH;
                ctx.beginPath();
                ctx.moveTo(p1.x, p1.y);
                ctx.lineTo(p2.x, p2.y);
                ctx.stroke();
              }
            }
          }
        }
      }

      if (mousePos) {
        for (let i = 0; i < particles.length; i++) {
          const p = particles[i];
          const dx = p.x - mousePos.x;
          const dy = p.y - mousePos.y;
          const dist = Math.sqrt(dx * dx + dy * dy);
          if (dist <= GRAB_DISTANCE) {
            const opacity =
              GRAB_LINE_OPACITY -
              (dist / (1 / GRAB_LINE_OPACITY)) / GRAB_DISTANCE;
            if (opacity > 0) {
              ctx.strokeStyle = `rgba(107, 114, 128, ${opacity})`;
              ctx.lineWidth = LINE_LINKED_WIDTH;
              ctx.beginPath();
              ctx.moveTo(p.x, p.y);
              ctx.lineTo(mousePos.x, mousePos.y);
              ctx.stroke();
            }
          }
        }
      }

      for (let i = 0; i < particles.length; i++) {
        const p = particles[i];
        ctx.fillStyle = `rgba(107, 114, 128, ${p.opacity})`;
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2, false);
        ctx.fill();
      }

      rafId = requestAnimationFrame(draw);
    };

    draw();

    return () => {
      resizeObserver.disconnect();
      cancelAnimationFrame(rafId);
    };
  }, []);

  return (
    <div
      ref={containerRef}
      className="absolute inset-0 overflow-hidden pointer-events-none"
      style={{ zIndex: 0 }}
    >
      {/* Particles.js-style layer: floating particles + line links + grab to cursor */}
      <canvas
        ref={canvasRef}
        className="absolute inset-0 w-full h-full"
        style={{ opacity: 0.85 }}
        aria-hidden
      />
      {/* Mouse-follow spotlight — only visible when mouse is in section */}
      <div
        className="absolute pointer-events-none transition-opacity duration-300"
        style={{
          left: `${x * 100}%`,
          top: `${y * 100}%`,
          width: 'min(85vw, 520px)',
          height: 'min(85vw, 520px)',
          transform: 'translate(-50%, -50%)',
          background: 'radial-gradient(circle, rgba(66, 139, 77, 0.12) 0%, rgba(66, 139, 77, 0.04) 35%, transparent 65%)',
          opacity: isActive ? 1 : 0,
          transition: 'left 0.18s ease-out, top 0.18s ease-out, opacity 0.25s ease-out',
        }}
        aria-hidden
      />
      {/* Large Box Grid - Firecrawl Style */}
      <svg 
        ref={svgRef}
        className="absolute inset-0 w-full h-full"
        style={{
          opacity: 0.78,
        }}
      >
        <defs>
          {/* Box grid pattern */}
          <pattern
            id="largeBoxGrid"
            x="0"
            y="0"
            width={BOX_SIZE}
            height={BOX_SIZE}
            patternUnits="userSpaceOnUse"
          >
            <rect
              width={BOX_SIZE}
              height={BOX_SIZE}
              fill="none"
              stroke="rgba(107, 114, 128, 0.14)"
              strokeWidth="1"
            />
          </pattern>
        </defs>
        
        {/* Base grid - all boxes */}
        <rect width="100%" height="100%" fill="url(#largeBoxGrid)" />
      </svg>
      
      {/* Additional subtle grid overlay */}
      <div 
        className="absolute inset-0"
        style={{
          backgroundImage: `
            linear-gradient(rgba(107, 114, 128, 0.02) 1px, transparent 1px),
            linear-gradient(90deg, rgba(107, 114, 128, 0.02) 1px, transparent 1px)
          `,
          backgroundSize: `${BOX_SIZE}px ${BOX_SIZE}px`,
          opacity: 0.3,
        }}
      />
    </div>
  );
}
