"use client";

import { useEffect, useRef } from "react";
import { useReducedMotion } from "motion/react";

/* ============================================================
   Fond animé du hero : image fractale + particules lumineuses.
   Écho du visuel : filaments cyan dérivant le long d'un champ de
   flux, étincelles chaudes près du vortex, parallaxe à la souris.
   ~90 particules, pause hors écran / onglet caché, coupé sous
   prefers-reduced-motion.
   ============================================================ */

type Particle = {
  x: number; y: number; px: number; py: number;
  life: number; maxLife: number; speed: number; size: number; warm: boolean;
};

const COUNT = 90;

export default function HeroBackground() {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const bgRef = useRef<HTMLDivElement>(null);
  const reduce = useReducedMotion();

  useEffect(() => {
    if (reduce) return;
    const canvas = canvasRef.current;
    const bg = bgRef.current;
    const hero = canvas?.parentElement;
    if (!canvas || !hero) return;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;

    const dpr = Math.min(window.devicePixelRatio || 1, 1.75);
    let W = 0;
    let H = 0;
    let running = false;
    let rafId = 0;
    let t = 0;

    const particles: Particle[] = [];

    /* Parallaxe : cibles mises à jour au mousemove, interpolées dans frame() */
    const parallax = window.matchMedia("(pointer: fine)").matches;
    let targetX = 0, targetY = 0, curX = 0, curY = 0;

    const resize = () => {
      W = hero.clientWidth;
      H = hero.clientHeight;
      canvas.width = W * dpr;
      canvas.height = H * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };

    /* Champ de flux léger : pseudo-bruit par sinus combinés */
    const flowAngle = (x: number, y: number, time: number) =>
      Math.sin(x * 0.0016 + time * 0.00022) * 1.6 +
      Math.cos(y * 0.0021 - time * 0.00017) * 1.4;

    const spawn = (p: Particle) => {
      if (Math.random() < 0.7) {
        /* 70 % naissent près du vortex (bas-gauche) */
        p.x = W * (0.18 + Math.random() * 0.3);
        p.y = H * (0.55 + Math.random() * 0.35);
        p.warm = Math.random() < 0.35;
      } else {
        p.x = Math.random() * W;
        p.y = Math.random() * H;
        p.warm = false;
      }
      p.px = p.x;
      p.py = p.y;
      p.life = 0;
      p.maxLife = 220 + Math.random() * 260;
      p.speed = 0.35 + Math.random() * 0.75;
      p.size = 0.6 + Math.random() * 1.3;
      return p;
    };

    const frame = () => {
      if (!running) return;
      t += 16;

      if (parallax && bg) {
        curX += (targetX - curX) * 0.045;
        curY += (targetY - curY) * 0.045;
        bg.style.transform = `translate3d(${(-curX).toFixed(2)}px,${(-curY).toFixed(2)}px,0) scale(1.04)`;
      }

      ctx.clearRect(0, 0, W, H);
      ctx.globalCompositeOperation = "lighter";

      for (const p of particles) {
        p.life++;
        if (p.life > p.maxLife || p.x < -20 || p.x > W + 20 || p.y < -20 || p.y > H + 20) {
          spawn(p);
          continue;
        }
        const a = flowAngle(p.x, p.y, t);
        p.px = p.x;
        p.py = p.y;
        p.x += Math.cos(a) * p.speed;
        p.y += Math.sin(a) * p.speed - 0.22; /* dérive ascendante, comme la fumée */

        const fade = Math.min(p.life / 40, 1, (p.maxLife - p.life) / 60);
        const alpha = 0.5 * fade;

        ctx.strokeStyle = p.warm
          ? `rgba(255, 168, 60, ${alpha * 0.85})`
          : `rgba(96, 210, 255, ${alpha})`;
        ctx.lineWidth = p.size;
        ctx.lineCap = "round";
        ctx.beginPath();
        ctx.moveTo(p.px, p.py);
        ctx.lineTo(p.x, p.y);
        ctx.stroke();
      }
      rafId = requestAnimationFrame(frame);
    };

    const start = () => {
      if (!running) {
        running = true;
        rafId = requestAnimationFrame(frame);
      }
    };
    const stop = () => {
      running = false;
      cancelAnimationFrame(rafId);
    };

    resize();
    for (let i = 0; i < COUNT; i++) {
      const p = spawn({} as Particle);
      p.life = Math.random() * p.maxLife; /* désynchronise le départ */
      particles.push(p);
    }

    const onResize = () => resize();
    const onVisibility = () => (document.hidden ? stop() : start());
    const onMove = (e: MouseEvent) => {
      const r = hero.getBoundingClientRect();
      targetX = ((e.clientX - r.left) / r.width - 0.5) * 18;
      targetY = ((e.clientY - r.top) / r.height - 0.5) * 12;
    };

    window.addEventListener("resize", onResize);
    document.addEventListener("visibilitychange", onVisibility);
    if (parallax) hero.addEventListener("mousemove", onMove);

    const io = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting && !document.hidden) start();
      else stop();
    });
    io.observe(hero);

    return () => {
      stop();
      io.disconnect();
      window.removeEventListener("resize", onResize);
      document.removeEventListener("visibilitychange", onVisibility);
      if (parallax) hero.removeEventListener("mousemove", onMove);
    };
  }, [reduce]);

  return (
    <>
      <div ref={bgRef} className="hero-bg" aria-hidden="true" />
      <canvas ref={canvasRef} className="hero-canvas" aria-hidden="true" />
    </>
  );
}
