// Reusable abstract/generative visual components
// Each one is a self-contained "AI-feeling" piece of art

const { useEffect, useRef } = React;

// 1) Mesh gradient blob — soft organic color field
function MeshGradient({ colors = ['#a8c8a0', '#e8d8b0', '#7a9a72'], style }) {
  const id = React.useId().replace(/:/g, '');
  return (
    <svg viewBox="0 0 600 600" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%', display: 'block', ...style }}>
      <defs>
        <radialGradient id={`g1-${id}`} cx="30%" cy="30%" r="60%">
          <stop offset="0%" stopColor={colors[0]} stopOpacity="0.95" />
          <stop offset="100%" stopColor={colors[0]} stopOpacity="0" />
        </radialGradient>
        <radialGradient id={`g2-${id}`} cx="80%" cy="20%" r="60%">
          <stop offset="0%" stopColor={colors[1]} stopOpacity="0.9" />
          <stop offset="100%" stopColor={colors[1]} stopOpacity="0" />
        </radialGradient>
        <radialGradient id={`g3-${id}`} cx="60%" cy="85%" r="70%">
          <stop offset="0%" stopColor={colors[2]} stopOpacity="0.95" />
          <stop offset="100%" stopColor={colors[2]} stopOpacity="0" />
        </radialGradient>
        <filter id={`blur-${id}`}>
          <feGaussianBlur stdDeviation="40" />
        </filter>
      </defs>
      <rect width="600" height="600" fill={colors[0]} opacity="0.3" />
      <g filter={`url(#blur-${id})`}>
        <rect width="600" height="600" fill={`url(#g1-${id})`} />
        <rect width="600" height="600" fill={`url(#g2-${id})`} />
        <rect width="600" height="600" fill={`url(#g3-${id})`} />
      </g>
    </svg>
  );
}

// 2) Animated flow field — organic moving lines (canvas)
function FlowField({ color = '#3a5a3a', density = 60, style }) {
  const ref = useRef(null);
  useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let raf;
    let t = 0;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    function resize() {
      const r = canvas.getBoundingClientRect();
      canvas.width = r.width * dpr;
      canvas.height = r.height * dpr;
      ctx.scale(dpr, dpr);
    }
    resize();
    const points = Array.from({ length: density }, () => ({
      x: Math.random(),
      y: Math.random(),
      seed: Math.random() * 1000,
    }));
    function draw() {
      const r = canvas.getBoundingClientRect();
      ctx.clearRect(0, 0, r.width, r.height);
      ctx.strokeStyle = color;
      ctx.lineWidth = 0.6;
      ctx.globalAlpha = 0.55;
      points.forEach((p) => {
        ctx.beginPath();
        let x = p.x * r.width;
        let y = p.y * r.height;
        ctx.moveTo(x, y);
        for (let i = 0; i < 50; i++) {
          const angle = Math.sin((x + t) * 0.005 + p.seed) * Math.cos((y + t) * 0.005) * Math.PI * 2;
          x += Math.cos(angle) * 2;
          y += Math.sin(angle) * 2;
          ctx.lineTo(x, y);
        }
        ctx.stroke();
      });
      t += 0.3;
      raf = requestAnimationFrame(draw);
    }
    draw();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, [color, density]);
  return <canvas ref={ref} style={{ width: '100%', height: '100%', display: 'block', ...style }} />;
}

// 3) Concentric rings — calm, geometric, "system" feeling
function ConcentricRings({ color = '#3a5a3a', style }) {
  const id = React.useId().replace(/:/g, '');
  return (
    <svg viewBox="0 0 400 400" style={{ width: '100%', height: '100%', display: 'block', ...style }}>
      <defs>
        <radialGradient id={`fade-${id}`}>
          <stop offset="0%" stopColor={color} stopOpacity="0.9" />
          <stop offset="100%" stopColor={color} stopOpacity="0" />
        </radialGradient>
      </defs>
      {Array.from({ length: 24 }).map((_, i) => (
        <circle
          key={i}
          cx="200"
          cy="200"
          r={10 + i * 8}
          fill="none"
          stroke={color}
          strokeOpacity={0.05 + (i / 60)}
          strokeWidth="0.5"
        />
      ))}
      <circle cx="200" cy="200" r="200" fill={`url(#fade-${id})`} opacity="0.15" />
    </svg>
  );
}

// 4) Particle constellation — networked nodes
function Constellation({ color = '#3a5a3a', count = 40, style }) {
  const ref = useRef(null);
  useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let raf;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    function resize() {
      const r = canvas.getBoundingClientRect();
      canvas.width = r.width * dpr;
      canvas.height = r.height * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    }
    resize();
    const nodes = Array.from({ length: count }, () => ({
      x: Math.random(),
      y: Math.random(),
      vx: (Math.random() - 0.5) * 0.0006,
      vy: (Math.random() - 0.5) * 0.0006,
    }));
    function draw() {
      const r = canvas.getBoundingClientRect();
      ctx.clearRect(0, 0, r.width, r.height);
      nodes.forEach((n) => {
        n.x += n.vx; n.y += n.vy;
        if (n.x < 0 || n.x > 1) n.vx *= -1;
        if (n.y < 0 || n.y > 1) n.vy *= -1;
      });
      ctx.strokeStyle = color;
      ctx.lineWidth = 0.5;
      for (let i = 0; i < nodes.length; i++) {
        for (let j = i + 1; j < nodes.length; j++) {
          const a = nodes[i], b = nodes[j];
          const dx = (a.x - b.x) * r.width;
          const dy = (a.y - b.y) * r.height;
          const d = Math.hypot(dx, dy);
          if (d < 140) {
            ctx.globalAlpha = (1 - d / 140) * 0.4;
            ctx.beginPath();
            ctx.moveTo(a.x * r.width, a.y * r.height);
            ctx.lineTo(b.x * r.width, b.y * r.height);
            ctx.stroke();
          }
        }
      }
      ctx.globalAlpha = 1;
      ctx.fillStyle = color;
      nodes.forEach((n) => {
        ctx.beginPath();
        ctx.arc(n.x * r.width, n.y * r.height, 1.5, 0, Math.PI * 2);
        ctx.fill();
      });
      raf = requestAnimationFrame(draw);
    }
    draw();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, [color, count]);
  return <canvas ref={ref} style={{ width: '100%', height: '100%', display: 'block', ...style }} />;
}

// 5) Vertical stripes — placeholder pattern
function StripedPlaceholder({ label = 'visual', color = '#3a5a3a', style }) {
  return (
    <div style={{
      width: '100%', height: '100%',
      backgroundImage: `repeating-linear-gradient(45deg, ${color}10, ${color}10 8px, transparent 8px, transparent 16px)`,
      border: `1px solid ${color}30`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      fontFamily: 'JetBrains Mono, monospace', fontSize: 11, letterSpacing: '0.1em',
      color: color, opacity: 0.7, textTransform: 'uppercase',
      ...style,
    }}>{label}</div>
  );
}

// 6) QuantumField — cellular / quantum-physics inspired field
// Pulsing nodes (cells/particles) connected by probability filaments;
// soft orbital rings around each cell suggesting electron shells or membrane fields.
// Reads as "structure that lives" — calm, scientific, alive.
function NightSky({
  bg = '#0a1410',
  starColor = '#e8ede4',
  lineColor = '#c4b06a',
  glyphColor = '#e8d99a',
  starCount = 180,
  style,
}) {
  const ref = useRef(null);
  useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let raf;
    let t = 0;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    function resize() {
      const r = canvas.getBoundingClientRect();
      canvas.width = r.width * dpr;
      canvas.height = r.height * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    }
    resize();

    // Cells: large nodes drifting slowly with orbital rings
    const cells = [
      { x: 0.20, y: 0.30, r: 38, phase: 0.2, drift: 0.0005 },
      { x: 0.55, y: 0.22, r: 28, phase: 1.1, drift: 0.0007 },
      { x: 0.78, y: 0.40, r: 44, phase: 2.0, drift: 0.0004 },
      { x: 0.32, y: 0.62, r: 32, phase: 0.6, drift: 0.0006 },
      { x: 0.65, y: 0.72, r: 36, phase: 1.7, drift: 0.0005 },
      { x: 0.14, y: 0.82, r: 22, phase: 2.4, drift: 0.0008 },
      { x: 0.88, y: 0.78, r: 26, phase: 0.9, drift: 0.0006 },
    ];

    // Particles drifting between cells (probability cloud)
    const particles = Array.from({ length: 60 }, () => ({
      x: Math.random(),
      y: Math.random(),
      vx: (Math.random() - 0.5) * 0.0003,
      vy: (Math.random() - 0.5) * 0.0003,
      r: 0.6 + Math.random() * 1.4,
      phase: Math.random() * Math.PI * 2,
    }));

    // Connection edges between cells (always-on, like field interactions)
    const cellEdges = [
      [0,1],[1,2],[0,3],[1,3],[2,4],[3,4],[3,5],[4,6],[5,4],[2,6],
    ];

    function getCellPos(c, i) {
      const wob = Math.sin(t * c.drift + c.phase) * 0.012;
      const wob2 = Math.cos(t * c.drift * 1.3 + c.phase) * 0.012;
      return [c.x + wob, c.y + wob2];
    }

    function draw() {
      const r = canvas.getBoundingClientRect();
      ctx.clearRect(0, 0, r.width, r.height);

      // Background
      ctx.fillStyle = bg;
      ctx.fillRect(0, 0, r.width, r.height);

      // Drifting probability particles
      particles.forEach((p) => {
        p.x += p.vx; p.y += p.vy;
        if (p.x < 0 || p.x > 1) p.vx *= -1;
        if (p.y < 0 || p.y > 1) p.vy *= -1;
        const tw = (Math.sin(t * 0.001 + p.phase) + 1) * 0.5;
        ctx.globalAlpha = 0.25 + tw * 0.4;
        ctx.fillStyle = starColor;
        ctx.beginPath();
        ctx.arc(p.x * r.width, p.y * r.height, p.r, 0, Math.PI * 2);
        ctx.fill();
      });

      // Resolve current cell positions
      const positions = cells.map((c, i) => getCellPos(c, i));

      // Edges between cells — soft glowing field lines
      ctx.strokeStyle = lineColor;
      ctx.lineCap = 'round';
      ctx.globalAlpha = 0.10;
      ctx.lineWidth = 4;
      ctx.beginPath();
      cellEdges.forEach(([a, b]) => {
        const pa = positions[a], pb = positions[b];
        ctx.moveTo(pa[0] * r.width, pa[1] * r.height);
        ctx.lineTo(pb[0] * r.width, pb[1] * r.height);
      });
      ctx.stroke();

      ctx.globalAlpha = 0.45;
      ctx.lineWidth = 0.6;
      ctx.beginPath();
      cellEdges.forEach(([a, b]) => {
        const pa = positions[a], pb = positions[b];
        ctx.moveTo(pa[0] * r.width, pa[1] * r.height);
        ctx.lineTo(pb[0] * r.width, pb[1] * r.height);
      });
      ctx.stroke();

      // Cells with orbital rings
      cells.forEach((c, i) => {
        const [cx, cy] = positions[i];
        const x = cx * r.width, y = cy * r.height;
        const breath = (Math.sin(t * 0.0008 + c.phase) + 1) * 0.5;

        // Outer halo
        const halo = ctx.createRadialGradient(x, y, 0, x, y, c.r * 2);
        halo.addColorStop(0, glyphColor + 'cc');
        halo.addColorStop(0.4, glyphColor + '40');
        halo.addColorStop(1, glyphColor + '00');
        ctx.fillStyle = halo;
        ctx.globalAlpha = 0.55 + breath * 0.25;
        ctx.beginPath();
        ctx.arc(x, y, c.r * 2, 0, Math.PI * 2);
        ctx.fill();

        // Orbital rings (3 ellipses at varied tilts)
        ctx.strokeStyle = lineColor;
        ctx.globalAlpha = 0.35 + breath * 0.2;
        ctx.lineWidth = 0.6;
        for (let k = 0; k < 3; k++) {
          ctx.save();
          ctx.translate(x, y);
          ctx.rotate(t * 0.0003 * (k + 1) + c.phase + k);
          ctx.beginPath();
          ctx.ellipse(0, 0, c.r * (0.9 + k * 0.25), c.r * (0.4 + k * 0.15), 0, 0, Math.PI * 2);
          ctx.stroke();
          ctx.restore();
        }

        // Bright core
        ctx.globalAlpha = 1;
        ctx.fillStyle = '#ffffff';
        ctx.beginPath();
        ctx.arc(x, y, 2.2, 0, Math.PI * 2);
        ctx.fill();

        // Pulse ring
        const pulse = (t * 0.0006 + c.phase) % 1;
        ctx.globalAlpha = (1 - pulse) * 0.4;
        ctx.strokeStyle = glyphColor;
        ctx.lineWidth = 0.8;
        ctx.beginPath();
        ctx.arc(x, y, c.r * 0.4 + pulse * c.r * 1.6, 0, Math.PI * 2);
        ctx.stroke();
      });

      ctx.globalAlpha = 1;
      t += 16;
      raf = requestAnimationFrame(draw);
    }
    draw();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, [bg, starColor, lineColor, glyphColor, starCount]);
  return <canvas ref={ref} style={{ width: '100%', height: '100%', display: 'block', ...style }} />;
}

Object.assign(window, { MeshGradient, FlowField, ConcentricRings, Constellation, NightSky, StripedPlaceholder });
