// Animated background: volumetric fog + signal constellation (drifting 3D points
// with dynamic nearest-neighbor connections and occasional bright signal fires)
function BackgroundScene({ accent = '#7ED4EF', intensity = 7, mode = 'shader' }) {
  const canvasRef = React.useRef(null);
  const rafRef = React.useRef(0);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
    const resize = () => {
      w = window.innerWidth;
      h = window.innerHeight;
      canvas.style.width = w + 'px';
      canvas.style.height = h + 'px';
      canvas.width = w * dpr;
      canvas.height = h * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    resize();
    window.addEventListener('resize', resize);

    // Accent rgb
    const hex = accent.replace('#','');
    const ar = parseInt(hex.slice(0,2),16);
    const ag = parseInt(hex.slice(2,4),16);
    const ab = parseInt(hex.slice(4,6),16);

    // --- Constellation stars (3D points in a softly bounded volume)
    const STAR_COUNT = 90;
    const stars = [];
    for (let i = 0; i < STAR_COUNT; i++) {
      stars.push({
        x: (Math.random() - 0.5) * 2.2,
        y: (Math.random() - 0.5) * 1.6,
        z: (Math.random() - 0.5) * 2.2,
        vx: (Math.random() - 0.5) * 0.015,
        vy: (Math.random() - 0.5) * 0.010,
        vz: (Math.random() - 0.5) * 0.015,
        // Size weight — a few brighter ones
        weight: Math.pow(Math.random(), 3),
        // Phase for subtle twinkle
        phase: Math.random() * Math.PI * 2,
        // Flare cooldown timer — some stars occasionally flare as "signals"
        flareAt: 2 + Math.random() * 12,
        flareT: -1, // inactive
      });
    }

    // Fires — when a star flares, cascade to nearby stars as connected signal
    // We'll detect nearest neighbors on the fly each frame.

    let t0 = performance.now();
    let mouseX = 0.5, mouseY = 0.5;
    const onMove = (e) => {
      mouseX = e.clientX / window.innerWidth;
      mouseY = e.clientY / window.innerHeight;
    };
    window.addEventListener('mousemove', onMove);

    // Project 3D -> 2D with rotation and perspective
    const project = (x, y, z, rotY, rotX, cx, cy, scale) => {
      const x1 = x * Math.cos(rotY) - z * Math.sin(rotY);
      const z1 = x * Math.sin(rotY) + z * Math.cos(rotY);
      const y2 = y * Math.cos(rotX) - z1 * Math.sin(rotX);
      const z2 = y * Math.sin(rotX) + z1 * Math.cos(rotX);
      const persp = 3.0 / (3.0 + z2);
      return [cx + x1 * scale * persp, cy + y2 * scale * persp, z2, persp];
    };

    const draw = (now) => {
      const t = (now - t0) / 1000;
      const dt = 1 / 60;
      ctx.clearRect(0, 0, w, h);

      // --- Volumetric fog layers
      const fogCount = 3;
      for (let i = 0; i < fogCount; i++) {
        const phase = t * 0.04 + i * 2.1;
        const fx = w * (0.5 + Math.sin(phase) * 0.3);
        const fy = h * (0.5 + Math.cos(phase * 0.7) * 0.3);
        const rad = Math.max(w, h) * (0.5 + i * 0.15);
        const g = ctx.createRadialGradient(fx, fy, 0, fx, fy, rad);
        const a = (0.04 + i * 0.02) * (intensity / 10);
        g.addColorStop(0, `rgba(${ar}, ${ag}, ${ab}, ${a})`);
        g.addColorStop(1, 'rgba(0,0,0,0)');
        ctx.fillStyle = g;
        ctx.fillRect(0, 0, w, h);
      }

      // Constellation centered on right side of hero
      const cx = w * 0.68;
      const cy = h * 0.5;
      const scale = Math.min(w, h) * 0.38;
      const rotY = t * 0.06 + (mouseX - 0.5) * 0.3;
      const rotX = 0.1 + (mouseY - 0.5) * 0.2;

      // Drift + bounds
      for (const s of stars) {
        s.x += s.vx * dt * 3;
        s.y += s.vy * dt * 3;
        s.z += s.vz * dt * 3;
        // Soft bounds
        if (Math.abs(s.x) > 1.3) s.vx *= -0.7;
        if (Math.abs(s.y) > 0.95) s.vy *= -0.7;
        if (Math.abs(s.z) > 1.3) s.vz *= -0.7;

        // Flare schedule
        if (s.flareT < 0) {
          s.flareAt -= dt;
          if (s.flareAt <= 0) {
            s.flareT = 0;
            s.flareAt = 6 + Math.random() * 18; // next flare
          }
        } else {
          s.flareT += dt;
          if (s.flareT > 1.6) s.flareT = -1;
        }
      }

      // Project
      const proj = stars.map(s => {
        const p = project(s.x, s.y, s.z, rotY, rotX, cx, cy, scale);
        return { x: p[0], y: p[1], z: p[2], persp: p[3] };
      });

      // Halo glow behind the constellation
      const halo = ctx.createRadialGradient(cx, cy, scale * 0.3, cx, cy, scale * 1.8);
      halo.addColorStop(0, `rgba(${ar}, ${ag}, ${ab}, ${0.08 * intensity / 10})`);
      halo.addColorStop(1, 'rgba(0,0,0,0)');
      ctx.globalCompositeOperation = 'screen';
      ctx.fillStyle = halo;
      ctx.fillRect(0, 0, w, h);
      ctx.globalCompositeOperation = 'source-over';

      // --- Dynamic nearest-neighbor connections
      // For each star, connect to its 2-3 nearest neighbors if within threshold.
      // Lines fade with distance and depth.
      const MAX_DIST_SQ = 0.55 * 0.55; // in 3D unit space
      const MAX_CONN = 3;
      ctx.lineWidth = 0.5;
      for (let i = 0; i < stars.length; i++) {
        const a = stars[i];
        // Compute distances to others
        const candidates = [];
        for (let j = i + 1; j < stars.length; j++) {
          const b = stars[j];
          const dx = a.x - b.x, dy = a.y - b.y, dz = a.z - b.z;
          const d2 = dx * dx + dy * dy + dz * dz;
          if (d2 < MAX_DIST_SQ) candidates.push({ j, d2 });
        }
        candidates.sort((p, q) => p.d2 - q.d2);
        const kept = candidates.slice(0, MAX_CONN);
        for (const { j, d2 } of kept) {
          const A = proj[i], B = proj[j];
          const dist = Math.sqrt(d2);
          const norm = 1 - dist / Math.sqrt(MAX_DIST_SQ); // 1 = close
          const avgZ = (A.z + B.z) / 2;
          const depthAlpha = Math.max(0.05, 0.25 - avgZ * 0.2);
          // Brighter when either endpoint is flaring
          const flareBoost = Math.max(
            stars[i].flareT >= 0 ? (1 - stars[i].flareT / 1.6) : 0,
            stars[j].flareT >= 0 ? (1 - stars[j].flareT / 1.6) : 0,
          );
          const alpha = Math.min(0.9, depthAlpha * norm * 1.2 + flareBoost * 0.5);
          ctx.strokeStyle = `rgba(${ar}, ${ag}, ${ab}, ${alpha})`;
          ctx.beginPath();
          ctx.moveTo(A.x, A.y);
          ctx.lineTo(B.x, B.y);
          ctx.stroke();
        }
      }

      // --- Draw stars (sorted back-to-front for correct overlap)
      const idx = proj.map((_, i) => i).sort((a, b) => proj[b].z - proj[a].z);
      for (const i of idx) {
        const s = stars[i];
        const p = proj[i];
        const depthAlpha = Math.max(0.4, 1 - p.z * 0.35);
        const twinkle = 0.7 + 0.3 * Math.sin(t * 1.5 + s.phase);

        // Flare intensity (0..1)
        const flare = s.flareT >= 0 ? Math.max(0, 1 - s.flareT / 1.6) : 0;

        const baseR = (0.8 + s.weight * 2.6) * p.persp * twinkle;
        // Outer bloom
        const bloomR = baseR * (3 + flare * 6);
        const bloomA = (0.06 + flare * 0.4) * depthAlpha;
        ctx.fillStyle = `rgba(${ar}, ${ag}, ${ab}, ${bloomA})`;
        ctx.beginPath();
        ctx.arc(p.x, p.y, bloomR, 0, Math.PI * 2);
        ctx.fill();

        // Bright core
        const coreA = (0.5 + 0.5 * s.weight) * depthAlpha + flare * 0.4;
        ctx.fillStyle = `rgba(${ar}, ${ag}, ${ab}, ${Math.min(1, coreA)})`;
        ctx.beginPath();
        ctx.arc(p.x, p.y, baseR, 0, Math.PI * 2);
        ctx.fill();

        // Expanding ring for flares
        if (flare > 0) {
          const ringR = baseR + (1 - flare) * 24;
          ctx.strokeStyle = `rgba(${ar}, ${ag}, ${ab}, ${flare * 0.55})`;
          ctx.lineWidth = 0.9;
          ctx.beginPath();
          ctx.arc(p.x, p.y, ringR, 0, Math.PI * 2);
          ctx.stroke();
        }
      }

      // --- Faint grid backdrop
      ctx.strokeStyle = 'rgba(237,237,239,0.025)';
      ctx.lineWidth = 1;
      const gs = 80;
      const offset = (t * 10) % gs;
      for (let x = -offset; x < w; x += gs) {
        ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, h); ctx.stroke();
      }
      for (let y = -offset; y < h; y += gs) {
        ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke();
      }

      rafRef.current = requestAnimationFrame(draw);
    };
    rafRef.current = requestAnimationFrame(draw);
    return () => {
      cancelAnimationFrame(rafRef.current);
      window.removeEventListener('resize', resize);
      window.removeEventListener('mousemove', onMove);
    };
  }, [accent, intensity, mode]);

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

Object.assign(window, { BackgroundScene });
