// GlassRefract — transparent WebGL overlay for glass elements.
//
// alpha:true canvas sits at z-index:-1 inside the glass element.
// • Background is transparent → real page bg-orbs show through (glass is 通透).
// • In aurora-bright areas the canvas adds contracted + chromatic-aberration
//   aurora ON TOP of the real aurora, making the refraction distortion obvious.
// • Zero CSS compositing → zero white lines.
(function () {
  const { useEffect, useRef } = React;

  const ORB_COLOR = [
    [74/255,  222/255, 128/255],
    [45/255,  212/255, 191/255],
    [16/255,  185/255, 129/255],
    [163/255, 230/255,  53/255],
    [34/255,  211/255, 238/255],
  ];
  const ORB_STR = [0.18, 0.15, 0.12, 0.07, 0.10];

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

  // Transparent canvas that overlays contracted + aberrated aurora.
  // Non-aurora pixels → alpha 0 (real bg-orbs visible through).
  // Aurora pixels → strong chromatic colour overlay → obvious refraction.
  // GLSL ES 1.0: must NOT pass loop variable to a function that indexes
  // a uniform array (GPU driver rejects it). Orb loops are fully unrolled.
  const FRAG = `
    precision highp float;
    uniform vec2  u_size;
    uniform vec2  u_pos;
    uniform float u_k;
    uniform vec2  u_op[5];
    uniform vec2  u_os[5];
    uniform vec3  u_oc[5];
    uniform float u_ow[5];

    const float GAIN = 5.5; /* aurora multiplier inside glass  */
    const float SAT  = 3.0; /* saturation boost                */

    void main() {
      vec2 px       = vec2(gl_FragCoord.x, u_size.y - gl_FragCoord.y);
      vec2 h        = u_size * 0.5;
      vec2 vpPx     = u_pos + px;
      vec2 vpC      = u_pos + h;

      /* Lens contraction: each pixel samples aurora from k× further out */
      vec2 sC = vpC + (vpPx - vpC) * u_k;

      /* Chromatic aberration: R/B offset ±7 px perpendicular to radial */
      vec2 rad  = normalize(vpPx - vpC + vec2(0.0001));
      vec2 perp = vec2(-rad.y, rad.x);
      vec2 sR   = sC + perp * 7.0;
      vec2 sB   = sC - perp * 7.0;

      /* Unrolled orb sampling (avoids GLSL ES 1.0 indexing restriction) */
      float rc=0.,gc=0.,bc=0.;
      vec2 d; float v;

      d=(sR-u_op[0])/max(u_os[0],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[0]*GAIN; rc+=u_oc[0].r*v;
      d=(sC-u_op[0])/max(u_os[0],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[0]*GAIN; gc+=u_oc[0].g*v;
      d=(sB-u_op[0])/max(u_os[0],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[0]*GAIN; bc+=u_oc[0].b*v;

      d=(sR-u_op[1])/max(u_os[1],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[1]*GAIN; rc+=u_oc[1].r*v;
      d=(sC-u_op[1])/max(u_os[1],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[1]*GAIN; gc+=u_oc[1].g*v;
      d=(sB-u_op[1])/max(u_os[1],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[1]*GAIN; bc+=u_oc[1].b*v;

      d=(sR-u_op[2])/max(u_os[2],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[2]*GAIN; rc+=u_oc[2].r*v;
      d=(sC-u_op[2])/max(u_os[2],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[2]*GAIN; gc+=u_oc[2].g*v;
      d=(sB-u_op[2])/max(u_os[2],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[2]*GAIN; bc+=u_oc[2].b*v;

      d=(sR-u_op[3])/max(u_os[3],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[3]*GAIN; rc+=u_oc[3].r*v;
      d=(sC-u_op[3])/max(u_os[3],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[3]*GAIN; gc+=u_oc[3].g*v;
      d=(sB-u_op[3])/max(u_os[3],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[3]*GAIN; bc+=u_oc[3].b*v;

      d=(sR-u_op[4])/max(u_os[4],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[4]*GAIN; rc+=u_oc[4].r*v;
      d=(sC-u_op[4])/max(u_os[4],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[4]*GAIN; gc+=u_oc[4].g*v;
      d=(sB-u_op[4])/max(u_os[4],vec2(1.));v=exp(-dot(d,d)*1.0)*u_ow[4]*GAIN; bc+=u_oc[4].b*v;

      vec3 aurora = clamp(vec3(rc, gc, bc), 0.0, 1.0);

      /* Saturation boost for stronger colour shift */
      float lum = dot(aurora, vec3(0.299, 0.587, 0.114));
      aurora = clamp(lum + (aurora - lum) * SAT, 0.0, 1.0);

      /* Alpha: 0 where no aurora (show real bg-orbs through), high where aurora */
      float aAlpha = clamp(lum * 3.5, 0.0, 0.88);
      /* Tiny glass tint (0.06) so pill is visible even in dark areas */
      float alpha  = aAlpha + 0.06;

      /* Standard (non-premultiplied) alpha output */
      gl_FragColor = vec4(aurora + vec3(0.04), alpha);
    }
  `;

  function mkShader(gl, type, src) {
    const s = gl.createShader(type);
    gl.shaderSource(s, src);
    gl.compileShader(s);
    if (!gl.getShaderParameter(s, gl.COMPILE_STATUS))
      console.warn('[GlassRefract]', gl.getShaderInfoLog(s));
    return s;
  }

  function GlassRefract({ radius = 999, k = 1.5 }) {
    const ref = useRef(null);

    useEffect(() => {
      const canvas = ref.current;
      const gl = canvas.getContext('webgl', {
        alpha: true,              // transparent — bg-orbs show through
        premultipliedAlpha: false,
        antialias: false,
      });
      if (!gl) return;

      gl.enable(gl.BLEND);
      gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

      const prog = gl.createProgram();
      gl.attachShader(prog, mkShader(gl, gl.VERTEX_SHADER,   VERT));
      gl.attachShader(prog, mkShader(gl, gl.FRAGMENT_SHADER, FRAG));
      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]), gl.STATIC_DRAW);
      const aPos = gl.getAttribLocation(prog, 'a_pos');
      gl.enableVertexAttribArray(aPos);
      gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);

      const uSize = gl.getUniformLocation(prog, 'u_size');
      const uPos  = gl.getUniformLocation(prog, 'u_pos');
      const uK    = gl.getUniformLocation(prog, 'u_k');
      const uOp = Array.from({length:5},(_,i)=>gl.getUniformLocation(prog,`u_op[${i}]`));
      const uOs = Array.from({length:5},(_,i)=>gl.getUniformLocation(prog,`u_os[${i}]`));
      const uOc = Array.from({length:5},(_,i)=>gl.getUniformLocation(prog,`u_oc[${i}]`));
      const uOw = Array.from({length:5},(_,i)=>gl.getUniformLocation(prog,`u_ow[${i}]`));

      let raf, lw = 0, lh = 0;

      function tick() {
        const parent = ref.current && ref.current.parentElement;
        if (!parent) { raf = requestAnimationFrame(tick); return; }

        const rect = parent.getBoundingClientRect();
        const w = Math.round(rect.width), h = Math.round(rect.height);
        if (w < 1 || h < 1) { raf = requestAnimationFrame(tick); return; }

        if (w !== lw || h !== lh) {
          canvas.width = w; canvas.height = h;
          gl.viewport(0, 0, w, h);
          lw = w; lh = h;
        }

        gl.useProgram(prog);
        gl.uniform2f(uSize, w, h);
        gl.uniform2f(uPos,  rect.left, rect.top);
        gl.uniform1f(uK, k);

        const orbs = document.querySelectorAll('.bg-orb');
        for (let i = 0; i < 5; i++) {
          const orb = orbs[i];
          if (orb) {
            const or = orb.getBoundingClientRect();
            gl.uniform2f(uOp[i], or.left + or.width * .5, or.top + or.height * .5);
            gl.uniform2f(uOs[i], or.width * .5, or.height * .5);
          } else {
            gl.uniform2f(uOp[i], -99999, -99999);
            gl.uniform2f(uOs[i], 1, 1);
          }
          gl.uniform3f(uOc[i], ...ORB_COLOR[i]);
          gl.uniform1f(uOw[i], ORB_STR[i]);
        }

        gl.clearColor(0, 0, 0, 0); // transparent clear
        gl.clear(gl.COLOR_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

        raf = requestAnimationFrame(tick);
      }

      raf = requestAnimationFrame(tick);
      return () => cancelAnimationFrame(raf);
    }, [radius, k]);

    const br = (typeof radius === 'number' && radius >= 999)
      ? '999px'
      : `${radius}px`;

    return (
      <canvas ref={ref} aria-hidden="true" style={{
        position:      'absolute',
        inset:         0,
        width:         '100%',
        height:        '100%',
        borderRadius:  br,
        pointerEvents: 'none',
        zIndex:        -1,
        display:       'block',
      }} />
    );
  }

  window.GlassRefract = GlassRefract;
  window.buildGlassRefractFilters = function () {};
})();
