'use client';

import * as React from 'react';
import { useEffect, useRef, useCallback } from 'react';

interface Particle {
  x: number;
  y: number;
  baseX: number; // The "home" x position (in the gutters)
  baseY: number;
  vx: number;
  vy: number;
  size: number;
  alpha: number;
  targetAlpha: number;
}

interface ParticleNetworkProps {
  className?: string;
}

export const ParticleNetwork: React.FC<ParticleNetworkProps> = ({ className = '' }) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const particlesRef = useRef<Particle[]>([]);
  const animationFrameRef = useRef<number>(0);
  const scrollRef = useRef<number>(0);
  const mouseRef = useRef<{ x: number; y: number }>({ x: -1000, y: -1000 });
  const dimensionsRef = useRef<{ width: number; height: number }>({ width: 0, height: 0 });

  // Configuration
  const config = {
    particleCount: 60, // Reduced count for cleaner look
    connectionDistance: 180,
    mouseRadius: 250,
    baseSpeed: 0.2,
    gutterWidth: 0.25, // 25% of width on each side
    colors: {
      particle: 'rgba(148, 163, 184, 0.8)', // slate-400
      line: 'rgba(203, 213, 225, 0.4)', // slate-300
    },
  };

  // Initialize particles
  const initParticles = useCallback((width: number, height: number) => {
    const particles: Particle[] = [];
    const count = config.particleCount;
    
    // Create particles primarily in the side gutters
    for (let i = 0; i < count; i++) {
      const isLeft = Math.random() > 0.5;
      // Random position within the gutter (0-25% or 75-100%)
      const gutterX = isLeft 
        ? Math.random() * (width * config.gutterWidth) 
        : width - (Math.random() * (width * config.gutterWidth));
      
      // Add some occasional strays near the content but not IN it
      const x = gutterX;
      const y = Math.random() * height;

      particles.push({
        x,
        y,
        baseX: x,
        baseY: y,
        vx: (Math.random() - 0.5) * 0.1, // Very slight horizontal drift
        vy: 0.2 + Math.random() * 0.3, // Consistent downward flow
        size: Math.random() * 1.5 + 0.5,
        alpha: 0,
        targetAlpha: Math.random() * 0.6 + 0.2,
      });
    }

    particlesRef.current = particles;
  }, [config.particleCount, config.gutterWidth]);

  // Animation loop
  const animate = useCallback(() => {
    const canvas = canvasRef.current;
    const ctx = canvas?.getContext('2d');
    if (!canvas || !ctx) return;

    const { width, height } = dimensionsRef.current;
    const scroll = scrollRef.current;
    const mouse = mouseRef.current;
    const particles = particlesRef.current;

    // Clear canvas
    ctx.clearRect(0, 0, width, height);

    // Update and draw particles
    particles.forEach((p, i) => {
      // 1. Movement
      // Apply downward flow
      p.y += p.vy;
      p.x += p.vx;

      // Wrap around vertical
      if (p.y > height) {
        p.y = -10;
        p.x = p.baseX; // Reset X to base to keep structure
      }

      // 2. Mouse Interaction (Repulsion)
      const dx = p.x - mouse.x;
      const dy = p.y - mouse.y;
      const dist = Math.sqrt(dx * dx + dy * dy);

      if (dist < config.mouseRadius) {
        const force = (config.mouseRadius - dist) / config.mouseRadius;
        const angle = Math.atan2(dy, dx);
        const pushX = Math.cos(angle) * force * 2;
        const pushY = Math.sin(angle) * force * 2;
        
        p.x += pushX;
        p.y += pushY;
      }

      // 3. Return to "Lane" (Elasticity)
      // Gently pull x back towards baseX if not influenced by mouse
      if (dist >= config.mouseRadius) {
        p.x += (p.baseX - p.x) * 0.02;
      }

      // 4. Scroll Effect (Parallax/Speed)
      // Scroll adds a temporary velocity boost or shift
      // We use a simple factor here, but could be more complex
      const scrollFactor = Math.max(0, Math.min(1, scroll * 0.001));
      p.y += scrollFactor * 0.5; // Move faster when scrolled down? 
      // Actually, let's make them react to scroll speed if we tracked delta, 
      // but for now just position shift based on scroll is handled by the container being fixed.
      // Let's add a subtle wave based on scroll position
      p.x += Math.sin(scroll * 0.002 + p.y * 0.01) * 0.2;

      // Fade in
      if (p.alpha < p.targetAlpha) p.alpha += 0.01;

      // Draw Particle
      ctx.beginPath();
      ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
      ctx.fillStyle = `rgba(148, 163, 184, ${p.alpha})`;
      ctx.fill();
    });

    // Draw Connections
    // We only connect particles that are close enough
    ctx.lineWidth = 0.5;
    
    for (let i = 0; i < particles.length; i++) {
      const p1 = particles[i];
      // Optimization: only check particles after this one
      for (let j = i + 1; j < particles.length; j++) {
        const p2 = particles[j];
        
        // Quick check for distance
        const dx = p1.x - p2.x;
        const dy = p1.y - p2.y;
        
        // Optimization: skip sqrt if obviously too far
        if (Math.abs(dx) > config.connectionDistance || Math.abs(dy) > config.connectionDistance) continue;

        const dist = Math.sqrt(dx * dx + dy * dy);

        if (dist < config.connectionDistance) {
          // Calculate opacity based on distance
          const opacity = (1 - dist / config.connectionDistance) * 0.3;
          
          ctx.beginPath();
          ctx.moveTo(p1.x, p1.y);
          ctx.lineTo(p2.x, p2.y);
          ctx.strokeStyle = `rgba(203, 213, 225, ${opacity})`;
          ctx.stroke();
        }
      }
    }

    animationFrameRef.current = requestAnimationFrame(animate);
  }, [config]);

  // Handle resize
  const handleResize = useCallback(() => {
    const container = containerRef.current;
    const canvas = canvasRef.current;
    if (!container || !canvas) return;

    const rect = container.getBoundingClientRect();
    const dpr = window.devicePixelRatio || 1;
    
    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;
    canvas.style.width = `${rect.width}px`;
    canvas.style.height = `${rect.height}px`;
    
    const ctx = canvas.getContext('2d');
    if (ctx) {
      ctx.scale(dpr, dpr);
    }

    dimensionsRef.current = { width: rect.width, height: rect.height };
    initParticles(rect.width, rect.height);
  }, [initParticles]);

  // Handle scroll
  const handleScroll = useCallback(() => {
    scrollRef.current = window.scrollY;
  }, []);

  // Handle mouse move
  const handleMouseMove = useCallback((e: MouseEvent) => {
    const container = containerRef.current;
    if (!container) return;
    
    const rect = container.getBoundingClientRect();
    mouseRef.current = {
      x: e.clientX - rect.left,
      y: e.clientY - rect.top, // Fixed position, so no scrollY needed for mouse relative to canvas
    };
  }, []);

  // Handle mouse leave
  const handleMouseLeave = useCallback(() => {
    mouseRef.current = { x: -1000, y: -1000 };
  }, []);

  useEffect(() => {
    handleResize();
    handleScroll();

    window.addEventListener('resize', handleResize);
    window.addEventListener('scroll', handleScroll, { passive: true });
    window.addEventListener('mousemove', handleMouseMove, { passive: true });
    window.addEventListener('mouseleave', handleMouseLeave);

    animationFrameRef.current = requestAnimationFrame(animate);

    return () => {
      window.removeEventListener('resize', handleResize);
      window.removeEventListener('scroll', handleScroll);
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseleave', handleMouseLeave);
      cancelAnimationFrame(animationFrameRef.current);
    };
  }, [handleResize, handleScroll, handleMouseMove, handleMouseLeave, animate]);

  return (
    <div
      ref={containerRef}
      className={`fixed inset-0 pointer-events-none -z-10 ${className}`}
      aria-hidden="true"
    >
      <canvas
        ref={canvasRef}
        className="w-full h-full"
      />
    </div>
  );
};

export default ParticleNetwork;
