// shader-bg.jsx — WebGL plasma/nebula shader for WhiteSpace background.
// Subtle, mouse-reactive. Sits behind the grid but above the black base.

function ShaderBackground({ active = true, intensity = 1 }) {
  const canvasRef = React.useRef(null);
  const rafRef = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
    if (!gl) return;

    // Resize to device pixel ratio
    const resize = () => {
      const w = canvas.clientWidth;
      const h = canvas.clientHeight;
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      canvas.width = w * dpr;
      canvas.height = h * dpr;
      gl.viewport(0, 0, canvas.width, canvas.height);
    };

    const vs = `
      attribute vec2 p;
      void main() { gl_Position = vec4(p, 0.0, 1.0); }
    `;

    // Plasma/nebula: domain-warped FBM producing drifting clouds.
    // Mouse creates a soft warp in the field.
    const fs = `
      precision highp float;
      uniform vec2 uRes;
      uniform float uTime;
      uniform vec2 uMouse; // 0..1
      uniform float uMouseActive;

      // hash + noise
      float hash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123); }
      float noise(vec2 p) {
        vec2 i = floor(p), f = fract(p);
        float a = hash(i), b = hash(i + vec2(1.0, 0.0));
        float c = hash(i + vec2(0.0, 1.0)), d = hash(i + vec2(1.0, 1.0));
        vec2 u = f * f * (3.0 - 2.0 * f);
        return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
      }
      float fbm(vec2 p) {
        float v = 0.0, a = 0.5;
        for (int i = 0; i < 5; i++) {
          v += a * noise(p);
          p *= 2.02;
          a *= 0.5;
        }
        return v;
      }

      void main() {
        vec2 uv = gl_FragCoord.xy / uRes.xy;
        vec2 p = uv - 0.5;
        p.x *= uRes.x / uRes.y;

        // Mouse warp: attract field toward mouse pos
        vec2 m = uMouse - 0.5;
        m.x *= uRes.x / uRes.y;
        vec2 dm = p - m;
        float md = length(dm);
        float warp = uMouseActive * exp(-md * 3.0) * 0.25;
        p -= normalize(dm + 0.001) * warp;

        // Two-layer domain warp for cloud feel
        float t = uTime * 0.08;
        vec2 q = vec2(fbm(p + vec2(0.0, t)), fbm(p + vec2(5.2, -t)));
        vec2 r = vec2(fbm(p + 1.7 * q + vec2(1.7, 9.2) + t * 0.5),
                      fbm(p + 1.7 * q + vec2(8.3, 2.8) - t * 0.5));
        float f = fbm(p + 2.5 * r);

        // Palette: deep blue-violet → warm orange highlight (matches brand)
        vec3 cDeep = vec3(0.03, 0.04, 0.07);
        vec3 cBlue = vec3(0.08, 0.11, 0.22);
        vec3 cViolet = vec3(0.18, 0.10, 0.28);
        vec3 cAmber = vec3(0.55, 0.30, 0.12);

        vec3 col = mix(cDeep, cBlue, smoothstep(0.2, 0.7, f));
        col = mix(col, cViolet, smoothstep(0.55, 0.9, length(r)));
        col += cAmber * smoothstep(0.75, 1.0, f) * 0.7;

        // Radial vignette for focus
        float vig = smoothstep(1.1, 0.2, length(uv - 0.5) * 1.4);
        col *= 0.35 + 0.9 * vig;

        // Extra glow near mouse
        col += vec3(0.5, 0.3, 0.12) * exp(-md * 4.0) * 0.35 * uMouseActive;

        gl_FragColor = vec4(col, 1.0);
      }
    `;

    const compile = (type, src) => {
      const sh = gl.createShader(type);
      gl.shaderSource(sh, src);
      gl.compileShader(sh);
      if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
        console.error(gl.getShaderInfoLog(sh));
      }
      return sh;
    };
    const prog = gl.createProgram();
    gl.attachShader(prog, compile(gl.VERTEX_SHADER, vs));
    gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, fs));
    gl.linkProgram(prog);
    gl.useProgram(prog);

    const buf = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buf);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, -1,1, 1,-1, 1,1]), gl.STATIC_DRAW);
    const loc = gl.getAttribLocation(prog, 'p');
    gl.enableVertexAttribArray(loc);
    gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);

    const uRes = gl.getUniformLocation(prog, 'uRes');
    const uTime = gl.getUniformLocation(prog, 'uTime');
    const uMouse = gl.getUniformLocation(prog, 'uMouse');
    const uMouseActive = gl.getUniformLocation(prog, 'uMouseActive');

    // Mouse state with damping
    let mx = 0.5, my = 0.5, tmx = 0.5, tmy = 0.5, active = 0, tActive = 0;
    const onMove = (e) => {
      const r = canvas.getBoundingClientRect();
      tmx = (e.clientX - r.left) / r.width;
      tmy = 1 - (e.clientY - r.top) / r.height;
      tActive = 1;
    };
    const onLeave = () => { tActive = 0; };
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseleave', onLeave);

    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);

    const start = performance.now();
    const loop = () => {
      const t = (performance.now() - start) / 1000;
      // damp mouse
      mx += (tmx - mx) * 0.08;
      my += (tmy - my) * 0.08;
      active += (tActive - active) * 0.05;

      gl.uniform2f(uRes, canvas.width, canvas.height);
      gl.uniform1f(uTime, t);
      gl.uniform2f(uMouse, mx, my);
      gl.uniform1f(uMouseActive, active);
      gl.drawArrays(gl.TRIANGLES, 0, 6);
      rafRef.current = requestAnimationFrame(loop);
    };
    loop();

    return () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
      ro.disconnect();
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseleave', onLeave);
    };
  }, []);

  return (
    <canvas ref={canvasRef} style={{
      position: 'absolute', inset: 0,
      width: '100%', height: '100%',
      opacity: active ? intensity : 0,
      transition: 'opacity 400ms',
      pointerEvents: 'none',
    }}/>
  );
}

Object.assign(window, { ShaderBackground });
