/* global React */
const { useEffect, useRef } = React;

/**
 * ZemplooGroundBackground
 * Procedural WebGL ground featuring topographic neon lines tinted in Zemploo's
 * brand palette: magenta (#E91E78), electric blue (#2D7DFF), amber (#F2C14E),
 * over graphite (#16181D). Adapted from the procedural-ground reference.
 */
function ZemplooGroundBackground({ accent = "brand", intensity = 1, paused = false, theme = "dark" }) {
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const gl = canvas.getContext("webgl", { antialias: true, premultipliedAlpha: false });
    if (!gl) return;

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

    // Accent palettes mapped to brand tokens. Two themes per accent so the
    // ripples stay legible against the page surface (dark = graphite, light = paper).
    //   base   = page-tone background
    //   mid    = secondary wash
    //   neon   = topo line glow
    const palettes = {
      dark: {
        brand:   { base: [0.057, 0.062, 0.078], mid: [0.176, 0.490, 1.000], neon: [0.913, 0.117, 0.470] },
        magenta: { base: [0.067, 0.043, 0.078], mid: [0.913, 0.117, 0.470], neon: [0.949, 0.756, 0.305] },
        blue:    { base: [0.043, 0.054, 0.094], mid: [0.176, 0.490, 1.000], neon: [0.913, 0.117, 0.470] },
        calm:    { base: [0.057, 0.062, 0.078], mid: [0.353, 0.388, 0.467], neon: [0.949, 0.756, 0.305] },
      },
      light: {
        // Bone/paper base; saturated brand neons read against it without crushing the page.
        brand:   { base: [0.957, 0.957, 0.945], mid: [0.700, 0.820, 1.000], neon: [0.913, 0.117, 0.470] },
        magenta: { base: [0.980, 0.945, 0.960], mid: [0.949, 0.756, 0.305], neon: [0.913, 0.117, 0.470] },
        blue:    { base: [0.945, 0.957, 0.980], mid: [0.700, 0.820, 1.000], neon: [0.176, 0.490, 1.000] },
        calm:    { base: [0.957, 0.957, 0.945], mid: [0.820, 0.860, 0.920], neon: [0.176, 0.490, 1.000] },
      },
    };
    const themeKey = theme === "light" ? "light" : "dark";
    const p = (palettes[themeKey] || palettes.dark)[accent] || palettes[themeKey].brand;

    const fsSource = `
      precision highp float;
      uniform float u_time;
      uniform float u_intensity;
      uniform float u_invert;     // 0 = dark theme (additive lines); 1 = light theme (overlay lines)
      uniform vec2  u_resolution;
      uniform vec3  u_base;
      uniform vec3  u_mid;
      uniform vec3  u_neon;

      float hash(vec2 p) {
        return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
      }
      float noise(vec2 p) {
        vec2 i = floor(p);
        vec2 f = fract(p);
        vec2 u = f * f * (3.0 - 2.0 * f);
        return mix(mix(hash(i + vec2(0.0, 0.0)), hash(i + vec2(1.0, 0.0)), u.x),
                   mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x), u.y);
      }

      void main() {
        vec2 uv = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / min(u_resolution.x, u_resolution.y);

        // Ground perspective simulation
        float depth = 1.0 / (uv.y + 1.15);
        vec2 gridUv = vec2(uv.x * depth, depth + u_time * 0.12);

        // Layered procedural noise for terrain
        float n = noise(gridUv * 3.5);
        float ripples = sin(gridUv.y * 18.0 + n * 8.0 + u_time * 0.45);

        // Neon topographic lines
        float topoLine = smoothstep(0.035, 0.0, abs(ripples));

        vec3 finalColor;

        if (u_invert > 0.5) {
          // LIGHT THEME - paper base, lines painted darker over the surface
          vec3 baseTone = mix(u_base, u_mid, n * 0.45);
          finalColor = mix(baseTone, u_neon, topoLine * 0.72 * u_intensity * depth * 0.9);

          // Soft secondary line set for depth
          float gridFade = smoothstep(0.06, 0.0, abs(ripples * 0.55));
          finalColor = mix(finalColor, u_mid, gridFade * 0.18 * u_intensity);

          // Vignette fades toward base (paper), not black
          float fade = smoothstep(0.0, -1.0, uv.y);
          finalColor = mix(finalColor, u_base, fade * 0.55);
          finalColor = mix(finalColor, u_base, smoothstep(0.6, 1.4, length(uv)) * 0.55);
        } else {
          // DARK THEME - original additive path
          finalColor = mix(u_base, u_mid, n * 0.55);
          finalColor += topoLine * u_neon * depth * 0.45 * u_intensity;

          // Subtle amber-ish horizon kiss
          float horizon = smoothstep(0.0, 0.55, 1.0 / (abs(uv.y + 0.05) * 4.0 + 1.0));
          finalColor += horizon * vec3(0.95, 0.75, 0.30) * 0.035 * u_intensity;

          // Horizon fog / fade
          float fade = smoothstep(0.1, -1.0, uv.y);
          finalColor *= (1.0 - length(uv) * 0.42) * (1.0 - fade * 0.8);
        }

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

    const compile = (type, src) => {
      const s = gl.createShader(type);
      gl.shaderSource(s, src);
      gl.compileShader(s);
      return s;
    };
    const program = gl.createProgram();
    gl.attachShader(program, compile(gl.VERTEX_SHADER, vsSource));
    gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fsSource));
    gl.linkProgram(program);
    gl.useProgram(program);

    const buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
      -1, -1,  1, -1, -1,  1,
      -1,  1,  1, -1,  1,  1,
    ]), gl.STATIC_DRAW);

    const posAttrib = gl.getAttribLocation(program, "position");
    gl.enableVertexAttribArray(posAttrib);
    gl.vertexAttribPointer(posAttrib, 2, gl.FLOAT, false, 0, 0);

    const timeLoc = gl.getUniformLocation(program, "u_time");
    const resLoc  = gl.getUniformLocation(program, "u_resolution");
    const intLoc  = gl.getUniformLocation(program, "u_intensity");
    const invLoc  = gl.getUniformLocation(program, "u_invert");
    const baseLoc = gl.getUniformLocation(program, "u_base");
    const midLoc  = gl.getUniformLocation(program, "u_mid");
    const neonLoc = gl.getUniformLocation(program, "u_neon");

    gl.uniform3fv(baseLoc, p.base);
    gl.uniform3fv(midLoc,  p.mid);
    gl.uniform3fv(neonLoc, p.neon);
    gl.uniform1f(invLoc, themeKey === "light" ? 1.0 : 0.0);

    let animationFrameId;
    let startTime = performance.now();
    let pauseTime = 0;

    const render = () => {
      const dpr = Math.min(window.devicePixelRatio || 1, 1.5);
      const w = Math.floor(window.innerWidth * dpr);
      const h = Math.floor(window.innerHeight * dpr);
      if (canvas.width !== w || canvas.height !== h) {
        canvas.width = w;
        canvas.height = h;
        gl.viewport(0, 0, w, h);
      }
      const t = paused ? pauseTime : (performance.now() - startTime) * 0.001;
      if (!paused) pauseTime = t;
      gl.uniform1f(timeLoc, t);
      gl.uniform1f(intLoc, intensity);
      gl.uniform2f(resLoc, w, h);
      gl.drawArrays(gl.TRIANGLES, 0, 6);
      animationFrameId = requestAnimationFrame(render);
    };

    animationFrameId = requestAnimationFrame(render);
    return () => cancelAnimationFrame(animationFrameId);
  }, [accent, intensity, paused, theme]);

  return (
    <div className="zemploo-bg" aria-hidden="true">
      <canvas ref={canvasRef} />
      <div className="zemploo-bg__grain"></div>
      <div className="zemploo-bg__vignette"></div>
    </div>
  );
}

window.ZemplooGroundBackground = ZemplooGroundBackground;
