/* global React */
const { useEffect, useRef } = React;

/* Pollen / honey atmosphere — performance-tuned.
   Cheap version: pre-rendered pollen sprites (no per-frame gradients),
   ~30fps throttle, DPR-capped, and paused whenever the tab is hidden or the
   hero is scrolled off-screen. Same drifting-golden-pollen look, far less GPU/CPU. */
function Atmosphere() {
  const canvasRef = useRef(null);
  const videoRef = useRef(null);

  // Robust autoplay + pause when tab hidden (saves GPU/CPU).
  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    const tryPlay = () => { const p = v.play(); if (p && p.catch) p.catch(() => {}); };
    tryPlay();
    v.addEventListener("canplay", tryPlay, { once: true });
    const onVis = () => { if (document.hidden) v.pause(); else tryPlay(); };
    document.addEventListener("visibilitychange", onVis);
    return () => document.removeEventListener("visibilitychange", onVis);
  }, []);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d");
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    let raf, w, h, dpr;
    const motes = [];

    const TINT = [[255,224,138], [255,200,87], [240,169,43], [169,190,134]];

    /* Pre-render each tint (and a sparkle) once into a small sprite canvas.
       Drawing a cached bitmap is dramatically cheaper than building a radial
       gradient for every particle on every frame. */
    function makeSprite([r, g, b], spark) {
      const s = 64;
      const c = document.createElement("canvas");
      c.width = c.height = s;
      const cx = c.getContext("2d");
      const grad = cx.createRadialGradient(s/2, s/2, 0, s/2, s/2, s/2);
      grad.addColorStop(0, `rgba(${r},${g},${b},1)`);
      grad.addColorStop(0.4, `rgba(${r},${g},${b},0.5)`);
      grad.addColorStop(1, `rgba(${r},${g},${b},0)`);
      cx.fillStyle = grad;
      cx.fillRect(0, 0, s, s);
      if (spark) {
        cx.fillStyle = "rgba(255,245,210,1)";
        cx.beginPath(); cx.arc(s/2, s/2, s*0.09, 0, Math.PI*2); cx.fill();
      }
      return c;
    }
    const sprites = TINT.map(t => makeSprite(t, false));
    const sparkSprite = makeSprite([255,224,138], true);

    function resize() {
      dpr = Math.min(window.devicePixelRatio || 1, 1.25);
      w = canvas.clientWidth; h = canvas.clientHeight;
      canvas.width = Math.round(w * dpr); canvas.height = Math.round(h * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    }
    resize();
    window.addEventListener("resize", resize);

    const COUNT = Math.round(Math.min(60, (w * h) / 26000));
    for (let i = 0; i < COUNT; i++) {
      const depth = Math.random();
      const spark = Math.random() < 0.14;
      motes.push({
        x: Math.random() * w,
        y: Math.random() * h,
        r: 0.7 + depth * 3.2,
        sp: 0.10 + depth * 0.5,
        sway: 16 + Math.random() * 44,
        swaySp: 0.0006 + Math.random() * 0.0013,
        phase: Math.random() * Math.PI * 2,
        a: 0.2 + depth * 0.5,
        tw: Math.random() * Math.PI * 2,
        tws: 0.012 + Math.random() * 0.026,
        spark,
        sprite: spark ? sparkSprite : sprites[(Math.random() * (i % 7 === 0 ? 4 : 3)) | 0],
      });
    }

    function draw(t) {
      ctx.clearRect(0, 0, w, h);
      ctx.globalCompositeOperation = "lighter";
      for (const m of motes) {
        const x = m.x + Math.sin(t * m.swaySp + m.phase) * m.sway;
        const tws = m.spark ? (0.35 + 0.65 * Math.pow(Math.max(0, Math.sin(m.tw)), 6))
                            : (0.55 + 0.45 * Math.sin(m.tw));
        const rad = m.r * (m.spark ? 5 : 3.6);
        ctx.globalAlpha = Math.min(1, m.a * tws);
        ctx.drawImage(m.sprite, x - rad, m.y - rad, rad * 2, rad * 2);
      }
      ctx.globalAlpha = 1;
      ctx.globalCompositeOperation = "source-over";
    }

    // Static single frame for reduced-motion users.
    if (reduce) {
      draw(0);
      return () => window.removeEventListener("resize", resize);
    }

    // ~30fps throttle + pause when hidden / off-screen.
    let last = 0, t = 0, running = true;
    const FRAME = 1000 / 30;
    function loop(now) {
      raf = requestAnimationFrame(loop);
      if (!running) return;
      if (now - last < FRAME) return;
      const dt = Math.min(2, (now - last) / FRAME || 1);
      last = now;
      t += 16 * dt;
      for (const m of motes) {
        m.y -= m.sp * dt; m.tw += m.tws * dt;
        if (m.y < -12) { m.y = h + 12; m.x = Math.random() * w; }
      }
      draw(t);
    }
    raf = requestAnimationFrame(loop);

    const onVis = () => { running = !document.hidden; last = 0; };
    document.addEventListener("visibilitychange", onVis);

    let io;
    if ("IntersectionObserver" in window) {
      io = new IntersectionObserver(
        es => { running = es[0].isIntersecting && !document.hidden; last = 0; },
        { threshold: 0 }
      );
      io.observe(canvas);
    }

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("resize", resize);
      document.removeEventListener("visibilitychange", onVis);
      if (io) io.disconnect();
    };
  }, []);

  return (
    <div className="atmos" aria-hidden="true">
      <video ref={videoRef} className="bg-video" src="assets/bg-loop.mp4"
             autoPlay muted loop playsInline preload="auto" />
      <div className="atmos-wash" />
      <div className="atmos-shafts" />
      <div className="atmos-glow atmos-glow--center" />
      <div className="atmos-glow atmos-glow--tl" />
      <div className="atmos-glow atmos-glow--br" />
      <div className="bokeh bokeh--1" />
      <div className="bokeh bokeh--2" />
      <div className="bokeh bokeh--3" />
      <canvas ref={canvasRef} className="atmos-canvas" />
      <div className="atmos-grain" />
    </div>
  );
}

window.Atmosphere = Atmosphere;
