/* ShaderAnimation — Three.js radial-lines fragment shader.
 * Adapted from the supplied component to tint output via brand colors
 * (uColorA → uColorB), composited over a dark background (uColorBg).
 * Brand colors are read from CSS vars set by Tweaks so the shader stays in sync.
 */

const VERTEX = `
  void main() {
    gl_Position = vec4(position, 1.0);
  }
`;

const FRAGMENT = `
  #define PI 3.14159265359
  precision highp float;
  uniform vec2  resolution;
  uniform float time;
  uniform vec3  colorA;
  uniform vec3  colorB;
  uniform vec3  colorBg;
  uniform float intensity;

  float random(in float x){ return fract(sin(x) * 1e4); }

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

    // Coarse mosaic — keeps the look chunky/editorial
    vec2 fMosaicScal = vec2(4.0, 2.0);
    vec2 vScreenSize = vec2(256.0, 256.0);
    uv.x = floor(uv.x * vScreenSize.x / fMosaicScal.x) / (vScreenSize.x / fMosaicScal.x);
    uv.y = floor(uv.y * vScreenSize.y / fMosaicScal.y) / (vScreenSize.y / fMosaicScal.y);

    float t = time * 0.06 + random(uv.x) * 0.4;
    float lineWidth = 0.0008;

    // Compute three time-offset intensities, then collapse to luminance + hue mix
    float ch[3];
    ch[0] = 0.0; ch[1] = 0.0; ch[2] = 0.0;
    for (int j = 0; j < 3; j++) {
      for (int i = 0; i < 5; i++) {
        ch[j] += lineWidth * float(i*i) /
                 abs(fract(t - 0.01 * float(j) + float(i) * 0.01) * 1.0 - length(uv));
      }
    }
    float lum   = clamp((ch[0] + ch[1] + ch[2]) / 3.0, 0.0, 1.0);
    float shift = clamp((ch[2] - ch[0]) * 0.6 + 0.5, 0.0, 1.0);

    vec3 lineColor  = mix(colorA, colorB, shift);
    vec3 finalColor = mix(colorBg, lineColor, lum * intensity);
    gl_FragColor    = vec4(finalColor, 1.0);
  }
`;

// Convert "#rrggbb" → [r,g,b] in 0..1
function hexToRgb(hex) {
  const h = String(hex || '#000').replace('#', '');
  const x = h.length === 3 ? h.replace(/./g, (c) => c + c) : h.padEnd(6, '0');
  const n = parseInt(x.slice(0, 6), 16);
  return [((n >> 16) & 255) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255];
}

function ShaderAnimation({ colorA = '#6a5bdc', colorB = '#0065bd', colorBg = '#07060d', intensity = 0.95 }) {
  const containerRef = React.useRef(null);
  const sceneRef = React.useRef({ renderer: null, uniforms: null, raf: null });

  React.useEffect(() => {
    let cancelled = false;
    let scriptEl = null;

    const ensureThree = () => new Promise((resolve, reject) => {
      if (window.THREE) return resolve(window.THREE);
      scriptEl = document.createElement('script');
      scriptEl.src = 'https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.min.js';
      scriptEl.onload = () => resolve(window.THREE);
      scriptEl.onerror = reject;
      document.head.appendChild(scriptEl);
    });

    ensureThree().then((THREE) => {
      if (cancelled || !containerRef.current) return;
      const container = containerRef.current;
      container.innerHTML = '';

      const camera = new THREE.Camera();
      camera.position.z = 1;
      const scene = new THREE.Scene();
      const geometry = new THREE.PlaneBufferGeometry(2, 2);

      const uniforms = {
        time:       { value: 1.0 },
        resolution: { value: new THREE.Vector2() },
        colorA:     { value: new THREE.Vector3(...hexToRgb(colorA)) },
        colorB:     { value: new THREE.Vector3(...hexToRgb(colorB)) },
        colorBg:    { value: new THREE.Vector3(...hexToRgb(colorBg)) },
        intensity:  { value: intensity },
      };

      const material = new THREE.ShaderMaterial({
        uniforms, vertexShader: VERTEX, fragmentShader: FRAGMENT,
      });
      const mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);

      const renderer = new THREE.WebGLRenderer({ antialias: false });
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
      container.appendChild(renderer.domElement);
      Object.assign(renderer.domElement.style, {
        position: 'absolute', inset: '0', width: '100%', height: '100%', display: 'block',
      });

      const resize = () => {
        const r = container.getBoundingClientRect();
        renderer.setSize(r.width, r.height, false);
        uniforms.resolution.value.x = renderer.domElement.width;
        uniforms.resolution.value.y = renderer.domElement.height;
      };
      resize();
      window.addEventListener('resize', resize, { passive: true });

      const tick = () => {
        sceneRef.current.raf = requestAnimationFrame(tick);
        uniforms.time.value += 0.05;
        renderer.render(scene, camera);
      };
      tick();

      sceneRef.current = { renderer, uniforms, raf: sceneRef.current.raf, resize };
    }).catch(() => { /* silent — shader is decorative */ });

    return () => {
      cancelled = true;
      const s = sceneRef.current;
      if (s.raf) cancelAnimationFrame(s.raf);
      if (s.resize) window.removeEventListener('resize', s.resize);
      if (s.renderer) {
        s.renderer.dispose();
        if (s.renderer.domElement?.parentNode) s.renderer.domElement.parentNode.removeChild(s.renderer.domElement);
      }
    };
  }, []);

  // Live-update colors when Tweaks change (without re-creating the renderer)
  React.useEffect(() => {
    const u = sceneRef.current?.uniforms;
    if (!u) return;
    u.colorA.value.set(...hexToRgb(colorA));
    u.colorB.value.set(...hexToRgb(colorB));
    u.colorBg.value.set(...hexToRgb(colorBg));
    u.intensity.value = intensity;
  }, [colorA, colorB, colorBg, intensity]);

  return (
    <div
      ref={containerRef}
      aria-hidden="true"
      style={{
        position: 'absolute', inset: 0, width: '100%', height: '100%',
        overflow: 'hidden', pointerEvents: 'none', background: colorBg,
      }}
    />
  );
}

window.ShaderAnimation = ShaderAnimation;
