// K-DNA animated backgrounds — Helix + Grid layers, canvas-based
// Two variants. Both respect `intensity` (0..1) and `hue` (css color).

function HelixBackground({ intensity = 0.6, hue = '#00e5ff', hueAlt = '#ff2bd6', style }) {
  const canvasRef = React.useRef(null);
  const rafRef = React.useRef(0);
  const mouseRef = React.useRef({ x: 0.5, y: 0.5 });

  React.useEffect(() => {
    const c = canvasRef.current;
    if (!c) return;
    const ctx = c.getContext('2d');
    let w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);

    const resize = () => {
      const r = c.getBoundingClientRect();
      w = r.width; h = r.height;
      c.width = w * dpr; c.height = h * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(c);

    const onMove = (e) => {
      const r = c.getBoundingClientRect();
      mouseRef.current.x = (e.clientX - r.left) / r.width;
      mouseRef.current.y = (e.clientY - r.top) / r.height;
    };
    window.addEventListener('mousemove', onMove);

    let t0 = performance.now();
    const draw = (tNow) => {
      const t = (tNow - t0) / 1000;
      ctx.clearRect(0, 0, w, h);

      // Radial vignette
      const grd = ctx.createRadialGradient(w * 0.5, h * 0.45, 0, w * 0.5, h * 0.5, Math.max(w, h) * 0.7);
      grd.addColorStop(0, 'rgba(255,255,255,0.02)');
      grd.addColorStop(1, 'rgba(0,0,0,0)');
      ctx.fillStyle = grd;
      ctx.fillRect(0, 0, w, h);

      // Grid
      ctx.strokeStyle = 'rgba(255,255,255,0.035)';
      ctx.lineWidth = 1;
      const gridSize = 64;
      const ox = (t * 6) % gridSize;
      const oy = (t * 4) % gridSize;
      ctx.beginPath();
      for (let x = -gridSize + ox; x < w + gridSize; x += gridSize) {
        ctx.moveTo(x, 0); ctx.lineTo(x, h);
      }
      for (let y = -gridSize + oy; y < h + gridSize; y += gridSize) {
        ctx.moveTo(0, y); ctx.lineTo(w, y);
      }
      ctx.stroke();

      // Helix — two strands
      const cx = w * 0.5 + (mouseRef.current.x - 0.5) * 40;
      const amp = Math.min(w, h) * 0.22 * (0.6 + 0.4 * intensity);
      const steps = 80;
      const vStep = h / steps;
      const speed = 0.6 * (0.5 + intensity);

      const drawStrand = (phase, color) => {
        for (let i = 0; i < steps; i++) {
          const y = i * vStep;
          const n = i / steps;
          const ang = n * Math.PI * 3 + t * speed + phase;
          const x = cx + Math.sin(ang) * amp;
          const z = Math.cos(ang); // depth -1..1
          const r = 1.6 + (z + 1) * 1.6;
          const a = 0.15 + (z + 1) * 0.22 * intensity;
          ctx.fillStyle = withAlpha(color, a);
          ctx.beginPath();
          ctx.arc(x, y, r, 0, Math.PI * 2);
          ctx.fill();

          // Rungs (every 3rd step)
          if (i % 3 === 0) {
            const angOther = n * Math.PI * 3 + t * speed + phase + Math.PI;
            const x2 = cx + Math.sin(angOther) * amp;
            ctx.strokeStyle = withAlpha(color, 0.06 + (z + 1) * 0.08 * intensity);
            ctx.lineWidth = 0.8;
            ctx.beginPath();
            ctx.moveTo(x, y); ctx.lineTo(x2, y);
            ctx.stroke();
          }
        }
      };
      drawStrand(0, hue);
      drawStrand(Math.PI, hueAlt);

      // Soft glow pass
      ctx.globalCompositeOperation = 'lighter';
      const g2 = ctx.createRadialGradient(cx, h * 0.5, 0, cx, h * 0.5, amp * 2.2);
      g2.addColorStop(0, withAlpha(hue, 0.08 * intensity));
      g2.addColorStop(1, 'rgba(0,0,0,0)');
      ctx.fillStyle = g2;
      ctx.fillRect(0, 0, w, h);
      ctx.globalCompositeOperation = 'source-over';

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

    return () => {
      cancelAnimationFrame(rafRef.current);
      ro.disconnect();
      window.removeEventListener('mousemove', onMove);
    };
  }, [intensity, hue, hueAlt]);

  return (
    <canvas
      ref={canvasRef}
      style={{
        position: 'absolute', inset: 0, width: '100%', height: '100%',
        display: 'block', ...style,
      }}
    />
  );
}

function ParticleGridBackground({ intensity = 0.6, hue = '#00e5ff', hueAlt = '#ff2bd6', style }) {
  const canvasRef = React.useRef(null);
  const rafRef = React.useRef(0);
  const particlesRef = React.useRef([]);

  React.useEffect(() => {
    const c = canvasRef.current;
    if (!c) return;
    const ctx = c.getContext('2d');
    let w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
    const count = Math.round(70 * (0.5 + intensity));

    const resize = () => {
      const r = c.getBoundingClientRect();
      w = r.width; h = r.height;
      c.width = w * dpr; c.height = h * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      particlesRef.current = new Array(count).fill(0).map(() => ({
        x: Math.random() * w,
        y: Math.random() * h,
        vx: (Math.random() - 0.5) * 0.25,
        vy: (Math.random() - 0.5) * 0.25,
        r: Math.random() * 1.4 + 0.3,
        alt: Math.random() < 0.2,
      }));
    };
    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(c);

    let t0 = performance.now();
    const draw = (tNow) => {
      const t = (tNow - t0) / 1000;
      ctx.clearRect(0, 0, w, h);

      // Grid
      ctx.strokeStyle = 'rgba(255,255,255,0.04)';
      ctx.lineWidth = 1;
      const gridSize = 48;
      ctx.beginPath();
      for (let x = 0; x < w; x += gridSize) { ctx.moveTo(x, 0); ctx.lineTo(x, h); }
      for (let y = 0; y < h; y += gridSize) { ctx.moveTo(0, y); ctx.lineTo(w, y); }
      ctx.stroke();

      // Scan line
      const scanY = ((t * 80) % (h + 200)) - 100;
      const sg = ctx.createLinearGradient(0, scanY - 60, 0, scanY + 60);
      sg.addColorStop(0, 'rgba(0,0,0,0)');
      sg.addColorStop(0.5, withAlpha(hue, 0.06 * intensity));
      sg.addColorStop(1, 'rgba(0,0,0,0)');
      ctx.fillStyle = sg;
      ctx.fillRect(0, scanY - 60, w, 120);

      // Particles + links
      const ps = particlesRef.current;
      for (const p of ps) {
        p.x += p.vx; p.y += p.vy;
        if (p.x < 0) p.x = w; if (p.x > w) p.x = 0;
        if (p.y < 0) p.y = h; if (p.y > h) p.y = 0;
        ctx.fillStyle = withAlpha(p.alt ? hueAlt : hue, 0.55 * intensity);
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
        ctx.fill();
      }
      // Links
      for (let i = 0; i < ps.length; i++) {
        for (let j = i + 1; j < ps.length; j++) {
          const a = ps[i], b = ps[j];
          const dx = a.x - b.x, dy = a.y - b.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < 110 * 110) {
            const al = (1 - Math.sqrt(d2) / 110) * 0.18 * intensity;
            ctx.strokeStyle = withAlpha(hue, al);
            ctx.lineWidth = 0.7;
            ctx.beginPath();
            ctx.moveTo(a.x, a.y); ctx.lineTo(b.x, b.y);
            ctx.stroke();
          }
        }
      }

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

    return () => {
      cancelAnimationFrame(rafRef.current);
      ro.disconnect();
    };
  }, [intensity, hue, hueAlt]);

  return (
    <canvas
      ref={canvasRef}
      style={{
        position: 'absolute', inset: 0, width: '100%', height: '100%',
        display: 'block', ...style,
      }}
    />
  );
}

function withAlpha(hex, a) {
  // hex like #rrggbb
  if (!hex || hex[0] !== '#' || hex.length !== 7) return `rgba(0,229,255,${a})`;
  const r = parseInt(hex.slice(1, 3), 16);
  const g = parseInt(hex.slice(3, 5), 16);
  const b = parseInt(hex.slice(5, 7), 16);
  return `rgba(${r},${g},${b},${a})`;
}

Object.assign(window, { HelixBackground, ParticleGridBackground, withAlpha });
