import React, { useRef, useEffect, useState } from 'react';
import './BackgroundCanvas.css';

const BackgroundCanvas = ({ theme = 'light' }) => {
  const canvasRef = useRef(null);
  const animationRef = useRef(null);
  const jointsRef = useRef([]);
  const cameraRef = useRef(null);
  const keysRef = useRef(new Array(127).fill(0));
  const worldRef = useRef({ width: 0, height: 0 });
  const themeRef = useRef(theme); 

  class Camera {
    constructor(position, zoom) {
      this.position = position;
      this.speed = 3;
      this.acceleration = { x: 0, y: 0, z: 0 };
      this.zoom = zoom;
    }
  }

  class Joint {
    constructor(position, vector) {
      this.position = position;
      this.vector = vector;
      this.speed = 0.5;
      this.w = 2;
      this.h = 2;
      this.bone_length = 150;
    }
  }

  const generateJoints = (numb, worldWidth, worldHeight) => {
    const arr = new Array(numb).fill(0);
    arr.forEach((v, i) => {
      arr[i] = new Joint(
        {
          x: Math.random() * worldWidth,
          y: Math.random() * worldHeight,
        },
        {
          x: Math.random() * 2 - 1,
          y: Math.random() * 2 - 1,
        }
      );
    });
    return arr;
  };

  const moveJoints = (joints, world) => {
    joints.forEach((joint) => {
      joint.position.x += joint.vector.x * joint.speed;
      joint.position.y += joint.vector.y * joint.speed;

      if (joint.position.x < 0) joint.position.x = world.width;
      if (joint.position.x > world.width) joint.position.x = 0;
      if (joint.position.y < 0) joint.position.y = world.height;
      if (joint.position.y > world.height) joint.position.y = 0;
    });
  };

  const drawJoints = (ctx, joints, camera, view, theme) => {
    const len = joints.length;
    
    let lineColor, pointColor, backgroundColor;
    if (theme === 'dark') {
      backgroundColor = '#446a85'; 
      lineColor = '#FFFFFF'; 
      pointColor = '#F5EEE6'; 
    } else {
      backgroundColor = '#d3dde3'; 
      lineColor = '#131313'; 
      pointColor = '#041c40'; 
    }
    
    ctx.fillStyle = backgroundColor;
    ctx.fillRect(0, 0, view.width, view.height);
    
    for (let i = 0; i < len; i++) {
      for (let j = i + 1; j < len; j += 3) {
        const length = Math.hypot(
          joints[j].position.x - joints[i].position.x,
          joints[j].position.y - joints[i].position.y
        );
        
        if (length <= joints[i].bone_length) {
          ctx.beginPath();
          ctx.strokeStyle = lineColor;
          ctx.lineWidth = camera.zoom * (30 / length);
          ctx.moveTo(
            view.width / 2 + (joints[i].position.x - camera.position.x) * camera.zoom,
            view.height / 2 + (joints[i].position.y - camera.position.y) * camera.zoom
          );
          ctx.lineTo(
            view.width / 2 + (joints[j].position.x - camera.position.x) * camera.zoom,
            view.height / 2 + (joints[j].position.y - camera.position.y) * camera.zoom
          );
          ctx.stroke();
          ctx.closePath();
        }
      }
      
      ctx.fillStyle = pointColor;
      ctx.fillRect(
        view.width / 2 + ((joints[i].position.x - camera.position.x) - joints[i].w / 2) * camera.zoom,
        view.height / 2 + ((joints[i].position.y - camera.position.y) - joints[i].w / 2) * camera.zoom,
        joints[i].w * camera.zoom,
        joints[i].h * camera.zoom
      );
    }
  };

  const moveCamera = (camera, keys) => {
    if (keys[37]) camera.acceleration.x -= camera.speed; 
    if (keys[38]) camera.acceleration.y -= camera.speed; 
    if (keys[39]) camera.acceleration.x += camera.speed; 
    if (keys[40]) camera.acceleration.y += camera.speed; 
    if (keys[188]) camera.acceleration.z += 0.003;
    if (keys[190]) camera.acceleration.z -= 0.003; 

    camera.position.x += camera.acceleration.x;
    camera.position.y += camera.acceleration.y;
    camera.zoom += camera.acceleration.z;

    camera.acceleration.x *= 0.96;
    camera.acceleration.y *= 0.96;
    camera.acceleration.z *= 0.9;
  };

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

    const ctx = canvas.getContext('2d');
    const view = {
      width: window.innerWidth,
      height: window.innerHeight,
    };

    canvas.width = view.width;
    canvas.height = view.height;

    worldRef.current = {
      width: view.width * 2,
      height: view.height * 2,
    };

    cameraRef.current = new Camera(
      {
        x: worldRef.current.width / 2,
        y: worldRef.current.height / 2,
      },
      1
    );

    jointsRef.current = generateJoints(300, worldRef.current.width, worldRef.current.height);
  };

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

    const ctx = canvas.getContext('2d');
    const view = {
      width: canvas.width,
      height: canvas.height,
    };

    moveCamera(cameraRef.current, keysRef.current);
    moveJoints(jointsRef.current, worldRef.current);
    
    drawJoints(ctx, jointsRef.current, cameraRef.current, view, themeRef.current);

    animationRef.current = requestAnimationFrame(animate);
  };

  useEffect(() => {
    themeRef.current = theme;
  }, [theme]);

  useEffect(() => {
    const handleKeyDown = (e) => {
      keysRef.current[e.keyCode] = 1;
    };

    const handleKeyUp = (e) => {
      keysRef.current[e.keyCode] = 0;
    };

    window.addEventListener('keydown', handleKeyDown);
    window.addEventListener('keyup', handleKeyUp);

    return () => {
      window.removeEventListener('keydown', handleKeyDown);
      window.removeEventListener('keyup', handleKeyUp);
    };
  }, []);

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

      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;

      worldRef.current = {
        width: canvas.width * 2,
        height: canvas.height * 2,
      };
    };

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  useEffect(() => {
    initCanvas();
    animate();

    return () => {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, []); 

  return (
    <canvas
      ref={canvasRef}
      className="background-canvas"
      aria-hidden="true"
    />
  );
};

export default BackgroundCanvas;