/* ============================================================
   CSL Landing — Interactive shader "wallpaper" for the hero.
   5 WebGL fragment shaders that react to mouse position + clicks.
   Brand-tinted (periwinkle / ink). Unique top-level names so it
   never collides with the other Babel scripts' global lexicals.
   ============================================================ */
const { useRef: useShaderRef, useState: useShaderState, useEffect: useShaderEffect } = React;

const SHADER_NAMES = ["Aurora"];

/* Single Aurora shader — flowing domain-warped periwinkle haze that glows
   toward the cursor, with a click ripple. */
const SHADER_BODY = `void main(){ vec2 uv=gl_FragCoord.xy/u_res; vec2 asp=vec2(u_res.x/u_res.y,1.0);
    float t=u_time*0.06; vec2 q=uv*3.0;
    q += 1.1*vec2(fbm(q + t + u_mouse*2.2), fbm(q*1.1 - t + 4.0));
    float n=fbm(q + u_mouse*1.4);
    float d=distance(uv*asp, u_mouse*asp);
    vec3 col=mix(vec3(0.96,0.97,1.0), PERI, smoothstep(0.15,0.95,n));
    col=mix(col, PERI_L, smoothstep(0.55,0.0,d)*0.45);
    col += PERI*ripple(uv)*0.35;
    gl_FragColor=vec4(col,1.0); }`;

const SHADER_PRELUDE = `precision highp float;
uniform vec2 u_res; uniform float u_time; uniform vec2 u_mouse; uniform vec3 u_click;
const vec3 PERI = vec3(0.384,0.435,1.0);
const vec3 PERI_L = vec3(0.671,0.694,1.0);
const vec3 PERI_D = vec3(0.184,0.204,0.62);
const vec3 INK = vec3(0.039,0.039,0.071);
float hash21(vec2 p){ p=fract(p*vec2(123.34,456.21)); p+=dot(p,p+45.32); return fract(p.x*p.y); }
float vnoise(vec2 p){ vec2 i=floor(p),f=fract(p); vec2 u=f*f*(3.0-2.0*f);
  float a=hash21(i),b=hash21(i+vec2(1.0,0.0)),c=hash21(i+vec2(0.0,1.0)),d=hash21(i+vec2(1.0,1.0));
  return mix(mix(a,b,u.x),mix(c,d,u.x),u.y); }
float fbm(vec2 p){ float v=0.0,a=0.5; for(int i=0;i<5;i++){ v+=a*vnoise(p); p*=2.02; a*=0.5; } return v; }
float ripple(vec2 uv){ float ca=u_click.z; if(ca>3.0) return 0.0; float cd=distance(uv,u_click.xy);
  return sin(cd*38.0 - ca*9.0)*exp(-ca*2.4)*smoothstep(0.45,0.0,cd); }
`;

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

function cslCompile(gl, type, src) {
  const sh = gl.createShader(type);
  gl.shaderSource(sh, src);
  gl.compileShader(sh);
  if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
    console.warn("Shader compile:", gl.getShaderInfoLog(sh));
    gl.deleteShader(sh); return null;
  }
  return sh;
}
function cslBuildProgram(gl, frag) {
  const vs = cslCompile(gl, gl.VERTEX_SHADER, SHADER_VERT);
  const fs = cslCompile(gl, gl.FRAGMENT_SHADER, SHADER_PRELUDE + frag);
  if (!vs || !fs) return null;
  const p = gl.createProgram();
  gl.attachShader(p, vs); gl.attachShader(p, fs); gl.linkProgram(p);
  gl.deleteShader(vs); gl.deleteShader(fs);
  if (!gl.getProgramParameter(p, gl.LINK_STATUS)) { console.warn("Link:", gl.getProgramInfoLog(p)); return null; }
  return p;
}

function HeroShader() {
  const wrapRef = useShaderRef(null);
  const canvasRef = useShaderRef(null);
  const glRef = useShaderRef(null);
  const progRef = useShaderRef(null);
  const uRef = useShaderRef({});
  const mouseRef = useShaderRef({ x: 0.5, y: 0.62, tx: 0.5, ty: 0.62 });
  const clickRef = useShaderRef({ x: 0.5, y: 0.5, t: -1e9 });
  const startRef = useShaderRef(0);

  /* gl setup, program build + render loop (runs once) */
  useShaderEffect(() => {
    const canvas = canvasRef.current;
    const gl = canvas.getContext("webgl", { antialias: true, premultipliedAlpha: false })
      || canvas.getContext("experimental-webgl");
    if (!gl) { wrapRef.current && wrapRef.current.classList.add("shader--nogl"); return; }
    glRef.current = gl;
    startRef.current = performance.now();

    const prog = cslBuildProgram(gl, SHADER_BODY);
    if (prog) {
      progRef.current = prog;
      uRef.current = {
        res: gl.getUniformLocation(prog, "u_res"),
        time: gl.getUniformLocation(prog, "u_time"),
        mouse: gl.getUniformLocation(prog, "u_mouse"),
        click: gl.getUniformLocation(prog, "u_click"),
      };
    }

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

    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const tScale = reduce ? 0.18 : 1.0;

    const resize = () => {
      const r = canvas.getBoundingClientRect();
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const w = Math.max(1, Math.round(r.width * dpr));
      const h = Math.max(1, Math.round(r.height * dpr));
      if (canvas.width !== w || canvas.height !== h) { canvas.width = w; canvas.height = h; }
      gl.viewport(0, 0, canvas.width, canvas.height);
    };
    const ro = new ResizeObserver(resize); ro.observe(canvas); resize();

    const host = canvas.closest(".hero") || canvas.parentElement;
    const norm = (e) => { const r = canvas.getBoundingClientRect(); return { x: (e.clientX - r.left) / r.width, y: 1 - (e.clientY - r.top) / r.height }; };
    const onMove = (e) => { const l = norm(e); const m = mouseRef.current; m.tx = l.x; m.ty = l.y; };
    const onDown = (e) => { if (e.target.closest && e.target.closest(".hero__hud")) return; const l = norm(e); clickRef.current = { x: l.x, y: l.y, t: performance.now() }; };
    host.addEventListener("pointermove", onMove, { passive: true });
    host.addEventListener("pointerdown", onDown, { passive: true });

    let raf;
    const draw = () => {
      raf = requestAnimationFrame(draw);
      const prog = progRef.current; if (!prog) return;
      const m = mouseRef.current; m.x += (m.tx - m.x) * 0.12; m.y += (m.ty - m.y) * 0.12;
      gl.useProgram(prog);
      const loc = gl.getAttribLocation(prog, "a_pos");
      gl.bindBuffer(gl.ARRAY_BUFFER, buf);
      gl.enableVertexAttribArray(loc);
      gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
      const u = uRef.current;
      gl.uniform2f(u.res, canvas.width, canvas.height);
      gl.uniform1f(u.time, ((performance.now() - startRef.current) / 1000) * tScale);
      gl.uniform2f(u.mouse, m.x, m.y);
      gl.uniform3f(u.click, clickRef.current.x, clickRef.current.y, (performance.now() - clickRef.current.t) / 1000);
      gl.drawArrays(gl.TRIANGLES, 0, 3);
    };
    draw();

    return () => { cancelAnimationFrame(raf); ro.disconnect(); host.removeEventListener("pointermove", onMove); host.removeEventListener("pointerdown", onDown); };
  }, []);

  return (
    <React.Fragment>
      <div className="hero-shader" ref={wrapRef} aria-hidden="true">
        <canvas className="shader__canvas" ref={canvasRef}></canvas>
        <div className="shader__fallback"></div>
        <div className="hero-shader__scrim"></div>
      </div>

    </React.Fragment>
  );
}

window.HeroShader = HeroShader;
