/* GravityStarsBackground — canvas particle field with mouse-gravity and
   a proximity brighten effect: stars near the cursor pulse brighter, scale up,
   and bloom — like the animate-ui demo. */

function GravityStarsBackground({
  starsCount = 80,
  starsSize = 1.8,
  starsOpacity = 0.75,
  glowIntensity = 14,
  movementSpeed = 0.12,
  mouseInfluence = 160,
  mouseGravity = "attract",  // 'attract' | 'repel'
  gravityStrength = 0.04,
  brightenOnHover = true,
  brightenStrength = 1.4,
  className = "",
  starColor,
  glowColor,
}) {
  const canvasRef = React.useRef(null);
  const wrapRef = React.useRef(null);
  const starsRef = React.useRef([]);
  const mouseRef = React.useRef({ x: -9999, y: -9999, active: false });
  const rafRef = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    const wrap = wrapRef.current;
    if (!canvas || !wrap) return;
    const ctx = canvas.getContext("2d");

    // Resolve color from CSS variable so it follows accent tweaks
    const css = getComputedStyle(document.documentElement);
    const resolvedStar = starColor || "rgba(255,255,255,0.95)";
    const resolvedGlow = glowColor || (css.getPropertyValue("--accent").trim() || "#7a5bff");

    let width = 0, height = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);

    const resize = () => {
      const rect = wrap.getBoundingClientRect();
      width = Math.max(1, Math.floor(rect.width));
      height = Math.max(1, Math.floor(rect.height));
      canvas.width = width * dpr;
      canvas.height = height * dpr;
      canvas.style.width = width + "px";
      canvas.style.height = height + "px";
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);

      // (re)seed stars if missing or count changed
      if (starsRef.current.length !== starsCount) {
        starsRef.current = Array.from({ length: starsCount }, () => makeStar());
      }
    };

    const rand = (a, b) => a + Math.random() * (b - a);
    const makeStar = () => ({
      x: Math.random() * width,
      y: Math.random() * height,
      vx: rand(-1, 1) * movementSpeed,
      vy: rand(-1, 1) * movementSpeed,
      r: starsSize * rand(0.5, 1.6),
      tw: rand(0, Math.PI * 2),  // twinkle phase
      ts: rand(0.4, 1.2),        // twinkle speed
    });

    const onMove = (e) => {
      const r = wrap.getBoundingClientRect();
      mouseRef.current.x = e.clientX - r.left;
      mouseRef.current.y = e.clientY - r.top;
      mouseRef.current.active = true;
    };
    const onLeave = () => { mouseRef.current.active = false; };

    // Listen on the parent section so gravity works even when the cursor is
    // hovering over content (chips, code editor) that sits above the canvas.
    const target = wrap.parentElement || wrap;
    target.addEventListener("mousemove", onMove);
    target.addEventListener("mouseleave", onLeave);
    window.addEventListener("resize", resize);
    resize();

    const direction = mouseGravity === "repel" ? -1 : 1;
    const influenceSq = mouseInfluence * mouseInfluence;

    let last = performance.now();
    const tick = (now) => {
      const dt = Math.min(40, now - last);
      last = now;

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

      const m = mouseRef.current;
      const stars = starsRef.current;

      for (let i = 0; i < stars.length; i++) {
        const s = stars[i];

        // Distance to cursor — drives both gravity and the brighten effect
        let proximity = 0; // 0..1, 1 = right under the cursor
        if (m.active) {
          const dx = m.x - s.x;
          const dy = m.y - s.y;
          const dSq = dx * dx + dy * dy;
          if (dSq < influenceSq && dSq > 0.5) {
            const d = Math.sqrt(dSq);
            proximity = 1 - d / mouseInfluence;
            // Mouse gravity
            const force = proximity * gravityStrength * direction;
            s.vx += (dx / d) * force;
            s.vy += (dy / d) * force;
          }
        }

        // Damping
        s.vx *= 0.985;
        s.vy *= 0.985;

        s.x += s.vx;
        s.y += s.vy;
        s.tw += s.ts * 0.02;

        // Wrap edges
        if (s.x < -10) s.x = width + 10;
        if (s.x > width + 10) s.x = -10;
        if (s.y < -10) s.y = height + 10;
        if (s.y > height + 10) s.y = -10;

        // Subtle twinkle (0.6 → 1.0)
        const tw = 0.6 + Math.sin(s.tw) * 0.4;

        // Proximity brighten — boost alpha, radius and glow.
        // Quadratic easing so only really-near stars pop hard.
        const prox = brightenOnHover ? proximity * proximity : 0;
        const alpha = Math.min(1, starsOpacity * tw + prox * brightenStrength);
        const radius = s.r * (1 + prox * 0.9);
        const glow   = glowIntensity + prox * 22;

        // Glow
        if (glow > 0) {
          ctx.shadowBlur = glow;
          ctx.shadowColor = resolvedGlow;
        }
        ctx.beginPath();
        ctx.arc(s.x, s.y, radius, 0, Math.PI * 2);
        ctx.fillStyle = resolvedStar.replace(/[\d.]+\)$/, alpha.toFixed(3) + ")");
        ctx.fill();
      }
      ctx.shadowBlur = 0;

      rafRef.current = requestAnimationFrame(tick);
    };
    rafRef.current = requestAnimationFrame(tick);

    return () => {
      cancelAnimationFrame(rafRef.current);
      const target = wrap.parentElement || wrap;
      target.removeEventListener("mousemove", onMove);
      target.removeEventListener("mouseleave", onLeave);
      window.removeEventListener("resize", resize);
    };
  }, [starsCount, starsSize, starsOpacity, glowIntensity, movementSpeed, mouseInfluence, mouseGravity, gravityStrength, brightenOnHover, brightenStrength, starColor, glowColor]);

  return (
    <div ref={wrapRef} aria-hidden="true" className={`gravity-stars ${className}`}>
      <canvas ref={canvasRef} />
    </div>
  );
}

window.GravityStarsBackground = GravityStarsBackground;
