// starfield.jsx — Universe background with twinkling stars + occasional comets
// Performance: ~150 stars max, pauses when tab hidden, devicePixelRatio-aware.

function Starfield() {
  const ref = React.useRef(null);

  React.useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');

    let stars = [];
    let comets = [];
    let nebulae = [];
    let lastCometAt = performance.now() + 2500; // first comet ~2.5s in
    let raf = 0;
    let running = true;

    const palette = () => {
      const css = getComputedStyle(document.documentElement);
      return {
        a1: (css.getPropertyValue('--a1') || '#22e6ff').trim(),
        a2: (css.getPropertyValue('--a2') || '#7c5cff').trim(),
        dark: document.documentElement.getAttribute('data-theme') !== 'light',
      };
    };

    const resize = () => {
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const w = window.innerWidth;
      const h = window.innerHeight;
      canvas.width = w * dpr;
      canvas.height = h * dpr;
      canvas.style.width = w + 'px';
      canvas.style.height = h + 'px';
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);

      // Regenerate stars proportional to area
      const target = Math.min(180, Math.floor((w * h) / 9000));
      stars = new Array(target).fill(0).map(() => {
        const depth = Math.random();
        return {
          x: Math.random() * w,
          y: Math.random() * h,
          r: 0.3 + Math.pow(depth, 2.2) * 1.4,
          a: 0.25 + Math.random() * 0.65,
          twinkS: 0.0005 + Math.random() * 0.0018,
          twinkP: Math.random() * Math.PI * 2,
          depth,
          color: Math.random() < 0.12 ? 'accent' : 'white',
          vx: (Math.random() - 0.5) * 0.02 * depth,
          vy: (Math.random() - 0.5) * 0.02 * depth,
        };
      });

      // Soft nebula blobs for color depth
      nebulae = [
        { x: w * 0.15, y: h * 0.25, r: Math.max(180, w * 0.18), c: 'a1', a: 0.05 },
        { x: w * 0.85, y: h * 0.55, r: Math.max(220, w * 0.22), c: 'a2', a: 0.05 },
        { x: w * 0.45, y: h * 0.9,  r: Math.max(160, w * 0.16), c: 'a1', a: 0.04 },
      ];
    };

    const spawnComet = () => {
      // Diagonal trajectory, varies side & angle
      const fromLeft = Math.random() > 0.5;
      const speed = 6 + Math.random() * 4;
      const angleDeg = 18 + Math.random() * 24; // 18°–42° down
      const angle = (angleDeg * Math.PI) / 180;
      const yStart = Math.random() * (window.innerHeight * 0.6);
      comets.push({
        x: fromLeft ? -120 : window.innerWidth + 120,
        y: yStart,
        vx: (fromLeft ? 1 : -1) * Math.cos(angle) * speed,
        vy: Math.sin(angle) * speed,
        life: 0,
        maxLife: 260,
        trail: [],
        hue: Math.random() < 0.5 ? 'a1' : 'a2',
        size: 1.6 + Math.random() * 1.4,
      });
    };

    const draw = (t) => {
      if (!running) { raf = requestAnimationFrame(draw); return; }
      const w = window.innerWidth;
      const h = window.innerHeight;
      const p = palette();
      ctx.clearRect(0, 0, w, h);

      // Nebulae (radial-gradient blobs via canvas)
      nebulae.forEach(n => {
        const grd = ctx.createRadialGradient(n.x, n.y, 0, n.x, n.y, n.r);
        const col = n.c === 'a1' ? p.a1 : p.a2;
        grd.addColorStop(0, hexA(col, n.a));
        grd.addColorStop(1, hexA(col, 0));
        ctx.fillStyle = grd;
        ctx.fillRect(n.x - n.r, n.y - n.r, n.r * 2, n.r * 2);
      });

      // Stars
      ctx.save();
      stars.forEach(s => {
        s.x += s.vx; s.y += s.vy;
        if (s.x < 0) s.x = w; else if (s.x > w) s.x = 0;
        if (s.y < 0) s.y = h; else if (s.y > h) s.y = 0;
        const tw = (Math.sin(t * s.twinkS + s.twinkP) + 1) * 0.5;
        const alpha = s.a * (0.45 + 0.55 * tw);
        const color = s.color === 'accent' ? p.a1 : (p.dark ? '#e8f1ff' : '#3a4566');
        ctx.beginPath();
        ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
        ctx.fillStyle = hexA(color, alpha);
        ctx.fill();
        // Halo on brighter stars
        if (s.r > 1.05) {
          const halo = ctx.createRadialGradient(s.x, s.y, 0, s.x, s.y, s.r * 5);
          halo.addColorStop(0, hexA(color, alpha * 0.4));
          halo.addColorStop(1, hexA(color, 0));
          ctx.fillStyle = halo;
          ctx.fillRect(s.x - s.r * 5, s.y - s.r * 5, s.r * 10, s.r * 10);
        }
      });
      ctx.restore();

      // Comet spawning
      if (t - lastCometAt > 4500 + Math.random() * 6500) {
        spawnComet();
        lastCometAt = t;
      }
      // Occasionally a double comet for delight
      if (Math.random() < 0.0003 && comets.length < 2) spawnComet();

      // Comets
      comets.forEach(c => {
        c.life++;
        c.trail.push({ x: c.x, y: c.y });
        if (c.trail.length > 32) c.trail.shift();
        c.x += c.vx;
        c.y += c.vy;

        const color = c.hue === 'a1' ? p.a1 : p.a2;
        // Trail
        for (let i = 0; i < c.trail.length - 1; i++) {
          const a = (i / c.trail.length) * 0.85;
          const p0 = c.trail[i];
          const p1 = c.trail[i + 1];
          ctx.strokeStyle = hexA(color, a);
          ctx.lineWidth = (i / c.trail.length) * c.size * 1.4 + 0.2;
          ctx.lineCap = 'round';
          ctx.beginPath();
          ctx.moveTo(p0.x, p0.y);
          ctx.lineTo(p1.x, p1.y);
          ctx.stroke();
        }
        // Head — bright white core with colored glow
        const headGrad = ctx.createRadialGradient(c.x, c.y, 0, c.x, c.y, c.size * 6);
        headGrad.addColorStop(0, hexA('#ffffff', 1));
        headGrad.addColorStop(0.3, hexA(color, 0.7));
        headGrad.addColorStop(1, hexA(color, 0));
        ctx.fillStyle = headGrad;
        ctx.fillRect(c.x - c.size * 6, c.y - c.size * 6, c.size * 12, c.size * 12);
        ctx.beginPath();
        ctx.arc(c.x, c.y, c.size, 0, Math.PI * 2);
        ctx.fillStyle = '#ffffff';
        ctx.fill();
      });
      comets = comets.filter(c => c.life < c.maxLife && c.x > -200 && c.x < w + 200 && c.y < h + 200);

      raf = requestAnimationFrame(draw);
    };

    const onVisibility = () => { running = !document.hidden; };

    resize();
    window.addEventListener('resize', resize);
    document.addEventListener('visibilitychange', onVisibility);
    raf = requestAnimationFrame(draw);

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener('resize', resize);
      document.removeEventListener('visibilitychange', onVisibility);
    };
  }, []);

  return <canvas ref={ref} className="starfield" aria-hidden="true" />;
}

// hexA — convert #rgb / #rrggbb to rgba(..., a). Used by starfield.
function hexA(hex, a) {
  hex = (hex || '').trim();
  if (hex.startsWith('rgb')) return hex.replace(/rgba?\(([^)]+)\)/, (_, m) => `rgba(${m.split(',').slice(0,3).map(s=>s.trim()).join(',')},${a})`);
  let h = hex.replace('#','');
  if (h.length === 3) h = h.split('').map(c => c+c).join('');
  const r = parseInt(h.substring(0,2), 16) || 0;
  const g = parseInt(h.substring(2,4), 16) || 0;
  const b = parseInt(h.substring(4,6), 16) || 0;
  return `rgba(${r},${g},${b},${a})`;
}

window.Starfield = Starfield;
