/* global React, window */
/* CartoonForChrist — fun FX layer
 * Mounts once at the app root. Provides:
 *   - cursor sparkle trail (throttled to ~28fps)
 *   - click burst of 10 emojis radiating from the click point
 *   - drifting emojis (clouds, balloons, stars, butterflies) crossing the
 *     viewport at random intervals
 *   - scroll-triggered pop-in for anything with class .pop-in
 *
 * All driven by class names + CSS keyframes so it stays cheap. Disable via
 * <FxLayer enabled={false} />.
 */

const { useEffect: useEFx, useRef: useRFx, useState: useSFx } = React;

const TRAIL_EMOJIS  = ["✨", "⭐", "💫", "🌟", "✦", "·"];
const BURST_EMOJIS  = ["✨", "💛", "💗", "💜", "💙", "💚", "🧡", "⭐", "🎉", "🌈"];
const DRIFT_EMOJIS  = ["☁️", "🎈", "⭐", "✨", "🌈", "🦋", "🐦", "🌟", "💫", "🎵", "🎶", "💝"];

function FxLayer({ enabled = true, intensity = 1 }) {
  const [trails,   setTrails]   = useSFx([]);
  const [bursts,   setBursts]   = useSFx([]);
  const [drifters, setDrifters] = useSFx([]);
  const lastTrailTime = useRFx(0);
  const idRef = useRFx(0);

  // Cursor sparkle trail + click bursts
  useEFx(() => {
    if (!enabled) return;

    const onMove = (e) => {
      const now = performance.now();
      const throttle = 60 / intensity;
      if (now - lastTrailTime.current < throttle) return;
      lastTrailTime.current = now;
      const id = ++idRef.current;
      const emoji = TRAIL_EMOJIS[Math.floor(Math.random() * TRAIL_EMOJIS.length)];
      const dx = (Math.random() - 0.5) * 26;
      const dy = (Math.random() - 0.5) * 26;
      const size = 10 + Math.random() * 12;
      const newTrail = { id, x: e.clientX + dx, y: e.clientY + dy, emoji, size };
      setTrails(prev => [...prev.slice(-24), newTrail]);
      setTimeout(() => setTrails(prev => prev.filter(t => t.id !== id)), 750);
    };

    const onClick = (e) => {
      // Ignore clicks on the tweaks panel chrome itself so we don't burst
      // sparkles into the panel — easy way to detect: walk up looking for [class*=twk]
      let n = e.target;
      while (n && n !== document.body) {
        if (n.classList && [...n.classList].some(c => c.startsWith("twk-"))) return;
        n = n.parentElement;
      }

      const count = Math.round(10 * intensity);
      const burst = [];
      for (let i = 0; i < count; i++) {
        const angle = (i / count) * Math.PI * 2 + Math.random() * 0.4;
        const dist  = 50 + Math.random() * 70;
        const id = ++idRef.current;
        burst.push({
          id,
          x: e.clientX, y: e.clientY,
          tx: Math.cos(angle) * dist,
          ty: Math.sin(angle) * dist,
          rot: (Math.random() - 0.5) * 720,
          size: 16 + Math.random() * 14,
          emoji: BURST_EMOJIS[Math.floor(Math.random() * BURST_EMOJIS.length)],
        });
      }
      setBursts(prev => [...prev, ...burst]);
      const ids = burst.map(b => b.id);
      setTimeout(() => setBursts(prev => prev.filter(b => !ids.includes(b.id))), 950);
    };

    window.addEventListener("pointermove", onMove);
    window.addEventListener("click", onClick);
    return () => {
      window.removeEventListener("pointermove", onMove);
      window.removeEventListener("click", onClick);
    };
  }, [enabled, intensity]);

  // Drifting emojis crossing the viewport
  useEFx(() => {
    if (!enabled) return;
    const spawn = () => {
      if (document.hidden) return;
      const id = ++idRef.current;
      const fromLeft = Math.random() < 0.5;
      const y = 80 + Math.random() * Math.max(0, window.innerHeight - 220);
      const dur = 20 + Math.random() * 14;
      const size = 26 + Math.random() * 30;
      const emoji = DRIFT_EMOJIS[Math.floor(Math.random() * DRIFT_EMOJIS.length)];
      const wobble = (Math.random() - 0.5) * 30;
      const drifter = { id, y, dur, size, emoji, fromLeft, wobble };
      setDrifters(prev => [...prev, drifter]);
      setTimeout(() => setDrifters(prev => prev.filter(d => d.id !== id)), dur * 1000 + 500);
    };
    spawn();
    const interval = setInterval(spawn, (3200 + Math.random() * 2400) / intensity);
    return () => clearInterval(interval);
  }, [enabled, intensity]);

  // Scroll-triggered pop-in
  useEFx(() => {
    const els = document.querySelectorAll(".pop-in");
    if (!("IntersectionObserver" in window) || els.length === 0) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(en => {
        if (en.isIntersecting) {
          en.target.classList.add("is-in");
          io.unobserve(en.target);
        }
      });
    }, { threshold: 0.15 });
    els.forEach(el => io.observe(el));
    return () => io.disconnect();
  });

  if (!enabled) return null;

  return (
    <div className="fx-layer" aria-hidden="true">
      {trails.map(t => (
        <span key={t.id} className="fx-trail"
              style={{ left: t.x, top: t.y, fontSize: t.size }}>{t.emoji}</span>
      ))}
      {bursts.map(b => (
        <span key={b.id} className="fx-burst"
              style={{
                left: b.x, top: b.y,
                fontSize: b.size,
                "--tx": `${b.tx}px`,
                "--ty": `${b.ty}px`,
                "--rot": `${b.rot}deg`,
              }}>{b.emoji}</span>
      ))}
      {drifters.map(d => (
        <span key={d.id}
              className={`fx-drift ${d.fromLeft ? "from-left" : "from-right"}`}
              style={{
                top: d.y,
                fontSize: d.size,
                animationDuration: `${d.dur}s`,
                "--wobble": `${d.wobble}px`,
              }}>{d.emoji}</span>
      ))}
    </div>
  );
}

window.FxLayer = FxLayer;
