import React, { useEffect, useRef } from "react";
import { TRUNK_TOP_CSS } from "./Tree";

interface Leaf {
  x: number;
  y: number;
  size: number;
  speed: number;
  drift: number;
  rotation: number;
  rotationSpeed: number;
  opacity: number;
  sway: number;
  swaySpeed: number;
  phase: number;
}

export default function FallingLeaves({ treeRef }: { treeRef: React.RefObject<HTMLCanvasElement | null> }) {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    const canvas = canvasRef.current!;
    const ctx = canvas.getContext("2d")!;
    let animId: number;
    const leaves: Leaf[] = [];
    const MAX_LEAVES = 36;
    const frameInterval = 1000 / 30;
    let lastFrame = 0;
    let isVisible = true;
    let isRunning = false;
    let treeBounds = { left: 0, top: 0, width: 0 };
    let canvasBounds = { left: 0, top: 0 };
    const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

    function measure() {
      const parent = canvas.parentElement;
      const rect = parent?.getBoundingClientRect();
      canvas.width = Math.max(1, Math.round(rect?.width || window.innerWidth));
      canvas.height = Math.max(1, Math.round(rect?.height || window.innerHeight));
      const treeRect = treeRef.current?.getBoundingClientRect();
      const canvasRect = canvas.getBoundingClientRect();
      treeBounds = treeRect
        ? { left: treeRect.left, top: treeRect.top, width: treeRect.width }
        : { left: canvasRect.left + canvas.width * 0.2, top: canvasRect.top + canvas.height * 0.4, width: canvas.width * 0.6 };
      canvasBounds = { left: canvasRect.left, top: canvasRect.top };
    }
    measure();
    const resizeObserver = new ResizeObserver(measure);
    if (canvas.parentElement) resizeObserver.observe(canvas.parentElement);
    if (treeRef.current) resizeObserver.observe(treeRef.current);

    function spawnLeaf(): Leaf {
      const spawnY = treeBounds.top - canvasBounds.top + TRUNK_TOP_CSS;
      const spawnX = treeBounds.left - canvasBounds.left + Math.random() * treeBounds.width * 0.8 + treeBounds.width * 0.1;
      return {
        x: spawnX,
        y: spawnY,
        size: Math.random() * 4 + 2,
        speed: Math.random() * 0.3 + 0.15,
        drift: Math.random() * 0.5 - 0.25,
        rotation: Math.random() * Math.PI * 2,
        rotationSpeed: (Math.random() - 0.5) * 0.02,
        opacity: Math.random() * 0.25 + 0.08,
        sway: Math.random() * 30 + 15,
        swaySpeed: Math.random() * 0.008 + 0.003,
        phase: Math.random() * Math.PI * 2,
      };
    }

    let spawnTimer = 0;

    function draw(timestamp: number) {
      if (!isRunning) return;
      animId = requestAnimationFrame(draw);
      if (timestamp - lastFrame < frameInterval) return;
      lastFrame = timestamp;
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      spawnTimer++;
      if (spawnTimer > 30 && leaves.length < MAX_LEAVES) {
        leaves.push(spawnLeaf());
        spawnTimer = 0;
      }

      for (let i = leaves.length - 1; i >= 0; i--) {
        const l = leaves[i];
        l.y += l.speed;
        l.x += l.drift + Math.sin(l.phase) * l.swaySpeed * l.sway * 0.05;
        l.phase += l.swaySpeed;
        l.rotation += l.rotationSpeed;

        ctx.save();
        ctx.translate(l.x, l.y);
        ctx.rotate(l.rotation);
        ctx.globalAlpha = l.opacity;
        ctx.fillStyle = "#fdb068";

        const s = Math.round(l.size);
        ctx.fillRect(-s / 2, -s / 2, s, s);

        ctx.restore();

        if (l.y > canvas.height + 10) {
          leaves.splice(i, 1);
        }
      }

    }

    function start() {
      if (reducedMotion || isRunning || !isVisible || document.hidden) return;
      isRunning = true;
      animId = requestAnimationFrame(draw);
    }

    function stop() {
      isRunning = false;
      if (animId) cancelAnimationFrame(animId);
    }

    const intersectionObserver = new IntersectionObserver(([entry]) => {
      isVisible = entry.isIntersecting;
      if (isVisible) start();
      else stop();
    });
    const onVisibilityChange = () => {
      if (document.hidden) stop();
      else start();
    };
    intersectionObserver.observe(canvas);
    document.addEventListener("visibilitychange", onVisibilityChange);
    start();

    return () => {
      stop();
      intersectionObserver.disconnect();
      resizeObserver.disconnect();
      document.removeEventListener("visibilitychange", onVisibilityChange);
    };
  }, []);

  return <canvas ref={canvasRef} className="falling-leaves" />;
}
