import { useEffect, useRef, useState, useCallback } from "react";
import { Copy, Check } from "lucide-react";
import { Button } from "@/components/ui/button";

const SSH_COMMAND = "ssh portfolio@keshavanand.net";

const CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$%^&*()_+-=[]{}|;:,.<>?/\\~`アイウエオカキクケコサシスセソタチツテト";

interface MatrixColumn {
  x: number;
  y: number;
  speed: number;
  chars: string[];
  length: number;
  baseOpacity: number;
}

function ParticleBackground() {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const columnsRef = useRef<MatrixColumn[]>([]);
  const mouseRef = useRef({ x: -1000, y: -1000 });
  const animationRef = useRef<number>();
  const timeRef = useRef(0);

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

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

    const fontSize = 14;
    const columnSpacing = fontSize * 1.2;

    const initColumns = () => {
      const cols: MatrixColumn[] = [];
      const numColumns = Math.ceil(canvas.width / columnSpacing);
      
      for (let i = 0; i < numColumns; i++) {
        const length = Math.floor(Math.random() * 20) + 10;
        const chars: string[] = [];
        for (let j = 0; j < length; j++) {
          chars.push(CHARACTERS[Math.floor(Math.random() * CHARACTERS.length)]);
        }
        cols.push({
          x: i * columnSpacing,
          y: Math.random() * canvas.height - canvas.height,
          speed: Math.random() * 1.5 + 0.5,
          chars,
          length,
          baseOpacity: Math.random() * 0.4 + 0.1,
        });
      }
      columnsRef.current = cols;
    };

    const resizeCanvas = () => {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
      initColumns();
    };

    resizeCanvas();
    window.addEventListener("resize", resizeCanvas);

    const handleMouseMove = (e: MouseEvent) => {
      mouseRef.current = { x: e.clientX, y: e.clientY };
    };

    const getColor = (y: number, distanceToMouse: number, charIndex: number, totalChars: number) => {
      const heightRatio = y / canvas.height;
      const mouseInfluence = Math.max(0, 1 - distanceToMouse / 250);
      const headGlow = charIndex === totalChars - 1 ? 1 : 0;
      
      if (headGlow && mouseInfluence > 0.3) {
        return `rgba(255, 255, 255, ${0.9 + mouseInfluence * 0.1})`;
      }
      
      const r = Math.floor(30 + mouseInfluence * 50 + heightRatio * 20);
      const g = Math.floor(180 + mouseInfluence * 75 - heightRatio * 40);
      const b = Math.floor(160 + heightRatio * 95 + mouseInfluence * 40);
      
      return `rgb(${r}, ${g}, ${b})`;
    };

    const animate = () => {
      timeRef.current++;
      
      ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
      ctx.fillRect(0, 0, canvas.width, canvas.height);

      ctx.font = `${fontSize}px 'JetBrains Mono', monospace`;

      columnsRef.current.forEach((col) => {
        const dx = mouseRef.current.x - col.x;
        const dy = mouseRef.current.y - col.y;
        const distanceToMouse = Math.sqrt(dx * dx + dy * dy);
        
        const gravityRadius = 200;
        let gravityEffect = 0;
        let pullX = 0;
        
        if (distanceToMouse < gravityRadius) {
          gravityEffect = (gravityRadius - distanceToMouse) / gravityRadius;
          pullX = (dx / distanceToMouse) * gravityEffect * 2;
        }

        for (let i = 0; i < col.chars.length; i++) {
          const charY = col.y + i * fontSize;
          
          if (charY < -fontSize || charY > canvas.height + fontSize) continue;
          
          const charDx = mouseRef.current.x - (col.x + pullX);
          const charDy = mouseRef.current.y - charY;
          const charDistance = Math.sqrt(charDx * charDx + charDy * charDy);
          
          const fadeRatio = i / col.chars.length;
          let opacity = col.baseOpacity * (0.3 + fadeRatio * 0.7);
          
          if (charDistance < 250) {
            const boost = (250 - charDistance) / 250;
            opacity = Math.min(1, opacity + boost * 0.8);
          }
          
          if (i === col.chars.length - 1) {
            opacity = Math.min(1, opacity * 1.5);
          }
          
          const displayX = col.x + pullX * (1 - i / col.chars.length);
          
          ctx.globalAlpha = opacity;
          ctx.fillStyle = getColor(charY, charDistance, i, col.chars.length);
          ctx.fillText(col.chars[i], displayX, charY);
          
          if (charDistance < 150 && i === col.chars.length - 1) {
            ctx.globalAlpha = opacity * 0.3;
            ctx.shadowColor = getColor(charY, charDistance, i, col.chars.length);
            ctx.shadowBlur = 10;
            ctx.fillText(col.chars[i], displayX, charY);
            ctx.shadowBlur = 0;
          }
        }
        
        ctx.globalAlpha = 1;
        
        if (Math.random() < 0.02) {
          const randomIndex = Math.floor(Math.random() * col.chars.length);
          col.chars[randomIndex] = CHARACTERS[Math.floor(Math.random() * CHARACTERS.length)];
        }
        
        const speedMultiplier = 1 + gravityEffect * 0.5;
        col.y += col.speed * speedMultiplier;
        
        if (col.y > canvas.height + col.length * fontSize) {
          col.y = -col.length * fontSize;
          col.speed = Math.random() * 1.5 + 0.5;
          col.baseOpacity = Math.random() * 0.4 + 0.1;
        }
      });

      if (mouseRef.current.x > 0 && mouseRef.current.y > 0) {
        const gradient = ctx.createRadialGradient(
          mouseRef.current.x, mouseRef.current.y, 0,
          mouseRef.current.x, mouseRef.current.y, 150
        );
        gradient.addColorStop(0, "rgba(148, 226, 213, 0.03)");
        gradient.addColorStop(0.5, "rgba(137, 180, 250, 0.02)");
        gradient.addColorStop(1, "rgba(0, 0, 0, 0)");
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
      }

      animationRef.current = requestAnimationFrame(animate);
    };

    window.addEventListener("mousemove", handleMouseMove);
    animate();

    return () => {
      window.removeEventListener("resize", resizeCanvas);
      window.removeEventListener("mousemove", handleMouseMove);
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, []);

  return (
    <canvas
      ref={canvasRef}
      className="fixed inset-0 z-0"
      style={{ background: "#000000" }}
      data-testid="canvas-background"
    />
  );
}

function CommandBox() {
  const [copied, setCopied] = useState(false);
  const [isAnimating, setIsAnimating] = useState(false);

  const handleCopy = useCallback(async () => {
    try {
      await navigator.clipboard.writeText(SSH_COMMAND);
      setIsAnimating(true);
      setCopied(true);
      setTimeout(() => setIsAnimating(false), 150);
      setTimeout(() => setCopied(false), 2000);
    } catch (err) {
      console.error("Failed to copy:", err);
    }
  }, []);

  return (
    <div
      className="relative z-10 flex items-center gap-4 px-6 py-4 rounded-xl border border-border/30 backdrop-blur-sm"
      style={{ backgroundColor: "rgba(49, 50, 68, 0.8)" }}
      data-testid="command-box"
    >
      <span className="text-muted-foreground mr-1" data-testid="text-prompt">$</span>
      <code
        className="text-lg md:text-xl font-mono"
        style={{ color: "#a6e3a1" }}
        data-testid="text-ssh-command"
      >
        {SSH_COMMAND}
      </code>
      <Button
        size="icon"
        variant="ghost"
        onClick={handleCopy}
        className={`ml-2 text-muted-foreground transition-transform duration-150 ${isAnimating ? "scale-90" : "scale-100"}`}
        aria-label={copied ? "Copied to clipboard" : "Copy SSH command"}
        data-testid="button-copy"
      >
        {copied ? (
          <Check className="h-5 w-5" style={{ color: "#a6e3a1" }} />
        ) : (
          <Copy className="h-5 w-5" />
        )}
      </Button>
    </div>
  );
}

export default function Home() {
  return (
    <div className="min-h-screen w-full flex items-center justify-center overflow-hidden">
      <ParticleBackground />
      <CommandBox />
    </div>
  );
}
