'use client';

import * as React from 'react';

type ConfettiProps = {
  active?: boolean;
  duration?: number;
  particleCount?: number;
  className?: string;
};

type Particle = {
  x: number;
  y: number;
  w: number;
  h: number;
  vx: number;
  vy: number;
  rot: number;
  vr: number;
  color: string;
  alive: boolean;
};

const DEFAULT_COLORS = ['#111827', '#22C55E', '#3B82F6', '#F97316', '#E11D48', '#FACC15'];

function createParticle(width: number, height: number, colors: string[]): Particle {
  return {
    x: Math.random() * width,
    y: -Math.random() * height * 0.2 - 20,
    w: 6 + Math.random() * 6,
    h: 8 + Math.random() * 10,
    vx: -1 + Math.random() * 2,
    vy: 1 + Math.random() * 3,
    rot: Math.random() * Math.PI,
    vr: -0.1 + Math.random() * 0.2,
    color: colors[(Math.random() * colors.length) | 0],
    alive: true,
  };
}

function Confetti({ active = true, duration = 2800, particleCount = 120, className }: ConfettiProps) {
  const canvasRef = React.useRef<HTMLCanvasElement | null>(null);

  React.useEffect(() => {
    if (!active) return;

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

    const reduceMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches;
    if (reduceMotion) return;

    let rafId = 0;
    let running = true;
    const colors = DEFAULT_COLORS;
    const dpr = window.devicePixelRatio || 1;
    let width = window.innerWidth;
    let height = window.innerHeight;

    const resize = () => {
      width = window.innerWidth;
      height = window.innerHeight;
      canvas.width = Math.floor(width * dpr);
      canvas.height = Math.floor(height * dpr);
      canvas.style.width = `${width}px`;
      canvas.style.height = `${height}px`;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };

    resize();
    window.addEventListener('resize', resize);

    const maxParticles = Math.max(40, Math.min(particleCount, Math.floor((width * height) / 15000)));
    const particles = Array.from({ length: maxParticles }, () => createParticle(width, height, colors));
    const start = performance.now();
    const stopSpawningAt = start + duration;
    const hardStopAt = stopSpawningAt + 3000;
    const gravity = 0.02;
    let lastTime = start;

    const tick = (time: number) => {
      if (!running) return;
      if (document.hidden) {
        rafId = requestAnimationFrame(tick);
        return;
      }

      const elapsed = time - start;
      const spawnActive = time < stopSpawningAt;
      if (!spawnActive && time > hardStopAt) {
        running = false;
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        return;
      }

      const dt = Math.min(32, time - lastTime) / 16.67;
      lastTime = time;

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

      let aliveCount = 0;
      for (const p of particles) {
        if (!p.alive) {
          continue;
        }

        p.x += p.vx * dt;
        p.y += p.vy * dt;
        p.vy += gravity * dt;
        p.rot += p.vr * dt;

        if (p.y > height + 30) {
          if (spawnActive) {
            p.y = -20;
            p.x = Math.random() * width;
            p.vy = 1 + Math.random() * 3;
          } else {
            p.alive = false;
            continue;
          }
        }

        ctx.save();
        ctx.translate(p.x, p.y);
        ctx.rotate(p.rot);
        ctx.fillStyle = p.color;
        ctx.fillRect(-p.w / 2, -p.h / 2, p.w, p.h);
        ctx.restore();
        aliveCount += 1;
      }

      if (!spawnActive && aliveCount === 0) {
        running = false;
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        return;
      }

      rafId = requestAnimationFrame(tick);
    };

    rafId = requestAnimationFrame(tick);

    return () => {
      running = false;
      cancelAnimationFrame(rafId);
      window.removeEventListener('resize', resize);
    };
  }, [active, duration, particleCount]);

  if (!active) return null;

  return (
    <canvas
      ref={canvasRef}
      className={`pointer-events-none fixed inset-0 z-50 ${className ?? ''}`}
      aria-hidden="true"
    />
  );
}

export { Confetti };
