import React, { useEffect, useRef } from 'react';
import styled, { useTheme } from 'styled-components';

const Canvas = styled.canvas`
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  background: ${({ theme }) => theme.darkMode ? 'linear-gradient(to bottom, #000000, #1a1a2e)' : 'linear-gradient(to bottom, #f0f2f5, #e0e5ec)'};
  transition: background 0.5s ease;
`;

const ParticleBackground = () => {
    const canvasRef = useRef<HTMLCanvasElement>(null);
    const theme = useTheme();

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

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

        let particles: Particle[] = [];
        let animationFrameId: number | null = null;
        const prefersReducedMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false;

        const resizeCanvas = () => {
            const nextWidth = Math.max(1, window.innerWidth);
            const nextHeight = Math.max(1, window.innerHeight);
            if (canvas.width === nextWidth && canvas.height === nextHeight) {
                return;
            }
            canvas.width = nextWidth;
            canvas.height = nextHeight;
            init();
        };

        class Particle {
            x: number;
            y: number;
            vx: number;
            vy: number;
            size: number;
            color: string;

            constructor() {
                this.x = Math.random() * canvas!.width;
                this.y = Math.random() * canvas!.height;
                this.vx = (Math.random() - 0.5) * 0.5;
                this.vy = (Math.random() - 0.5) * 0.5;
                this.size = Math.random() * 2 + 1;
                // Use theme main color or fallback
                this.color = theme?.main
                    ? `${theme.main}${Math.floor((Math.random() * 0.5 + 0.2) * 255).toString(16).padStart(2, '0')}`
                    : `rgba(100, 149, 237, ${Math.random() * 0.5 + 0.2})`;
            }

            update() {
                this.x += this.vx;
                this.y += this.vy;

                if (this.x < 0 || this.x > canvas!.width) this.vx *= -1;
                if (this.y < 0 || this.y > canvas!.height) this.vy *= -1;
            }

            draw() {
                if (!ctx) return;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.fill();
            }
        }

        const init = () => {
            particles = [];
            // Cap the count so the O(n^2) link pass stays cheap on phones.
            const numberOfParticles = Math.min(
                Math.floor((canvas.width * canvas.height) / 15000),
                90,
            );
            for (let i = 0; i < numberOfParticles; i++) {
                particles.push(new Particle());
            }
        };

        const render = (advance: boolean) => {
            if (!ctx) return;
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            particles.forEach((particle) => {
                if (advance) {
                    particle.update();
                }
                particle.draw();
            });

            // Draw connections
            for (let i = 0; i < particles.length; i++) {
                for (let j = i + 1; j < particles.length; j++) {
                    const dx = particles[i].x - particles[j].x;
                    const dy = particles[i].y - particles[j].y;
                    const distance = Math.sqrt(dx * dx + dy * dy);

                    if (distance < 100) {
                        ctx.beginPath();
                        // Use theme main color for connections too
                        const opacity = 1 - distance / 100;
                        const hexOpacity = Math.floor(opacity * 255).toString(16).padStart(2, '0');
                        ctx.strokeStyle = theme?.main
                            ? `${theme.main}${hexOpacity}`
                            : `rgba(100, 149, 237, ${opacity})`;

                        ctx.lineWidth = 0.5;
                        ctx.moveTo(particles[i].x, particles[i].y);
                        ctx.lineTo(particles[j].x, particles[j].y);
                        ctx.stroke();
                    }
                }
            }
        };

        const animate = () => {
            render(true);
            animationFrameId = requestAnimationFrame(animate);
        };

        const stop = () => {
            if (animationFrameId !== null) {
                cancelAnimationFrame(animationFrameId);
                animationFrameId = null;
            }
        };

        const start = () => {
            if (animationFrameId !== null || prefersReducedMotion) {
                return;
            }
            animate();
        };

        // A backgrounded tab keeps burning battery otherwise, which matters most on phones.
        const handleVisibilityChange = () => {
            if (document.hidden) {
                stop();
            } else {
                start();
            }
        };

        resizeCanvas();
        init();
        if (prefersReducedMotion) {
            render(false);
        } else {
            start();
        }

        window.addEventListener('resize', resizeCanvas);
        document.addEventListener('visibilitychange', handleVisibilityChange);

        return () => {
            window.removeEventListener('resize', resizeCanvas);
            document.removeEventListener('visibilitychange', handleVisibilityChange);
            stop();
        };
    }, [theme]); // Re-run when theme changes

    return <Canvas ref={canvasRef} />;
};

export default ParticleBackground;
