// hero-video.jsx — HeroPromoVideo: plays the promo mp4 through a WebGL
// "unmult" pass that converts the black background to true transparency
// (alpha = brightness), so the laptop floats on the emerald field while its
// halo/glow survives as soft translucency. CSS blend modes can't do this here
// because ancestor stacking contexts (hero dolly transform, container
// z-index) isolate the blend; a keyed canvas needs none of that.
//
// Fallbacks: no WebGL → plain <video> with mix-blend-mode: screen.
// Reduced motion → a single keyed frame, no playback.

function HeroPromoVideo() {
  const holderRef = React.useRef(null);

  React.useEffect(() => {
    const holder = holderRef.current;
    if (!holder) return;
    const reduced = window.matchMedia &&
      window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    const video = document.createElement('video');
    video.src = 'uploads/promo-raw.mp4';
    video.muted = true;
    video.loop = true;
    video.playsInline = true;
    video.setAttribute('playsinline', '');
    video.preload = 'auto';
    video.crossOrigin = 'anonymous';

    const canvas = document.createElement('canvas');
    canvas.width = 1920; canvas.height = 1080;
    canvas.setAttribute('aria-label', 'Insurify product demonstration video');
    canvas.setAttribute('role', 'img');
    Object.assign(canvas.style, {
      width: '100%', height: 'auto', aspectRatio: '16 / 9', display: 'block'
    });

    const glOpts = { alpha: true, premultipliedAlpha: true, preserveDrawingBuffer: true };
    const gl = canvas.getContext('webgl', glOpts) ||
               canvas.getContext('experimental-webgl', glOpts);

    // ── Fallback: no WebGL → screen-blended <video> (approximate) ──
    if (!gl) {
      Object.assign(video.style, {
        width: '100%', height: 'auto', aspectRatio: '16 / 9',
        display: 'block', mixBlendMode: 'screen'
      });
      holder.appendChild(video);
      video.play().catch(function () {});
      return function () { video.pause(); video.removeAttribute('src'); video.load(); video.remove(); };
    }

    holder.appendChild(canvas);

    // ── Shaders: unmult (luma → alpha, premultiplied output) ──
    var vsSrc = [
      'attribute vec2 p;',
      'varying vec2 uv;',
      'void main(){ uv = vec2(p.x, 1.0 - p.y); gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0); }'
    ].join('\n');
    var fsSrc = [
      'precision mediump float;',
      'uniform sampler2D tex;',
      'varying vec2 uv;',
      'void main(){',
      '  vec4 c = texture2D(tex, uv);',
      '  float m = max(c.r, max(c.g, c.b));',
      // The background sits at ~0.05 luma, the laptop/content at ≥0.14.
      // Key ONLY that background band: below 0.065 fully clear, above 0.125
      // fully opaque, smooth ramp between (keeps the halo falloff soft).
      '  float a = smoothstep(0.065, 0.125, m);',
      // Recolor the halo band light green: strongest mid-ramp, faded out by
      // the time pixels reach solid laptop brightness.
      '  float halo = a * (1.0 - smoothstep(0.125, 0.24, m));',
      '  vec3 haloCol = vec3(0.50, 0.89, 0.67) * clamp(m * 4.0, 0.0, 1.0);',
      '  vec3 col = mix(c.rgb, haloCol, halo);',
      // premultiplied output
      '  gl_FragColor = vec4(col * a, a);',
      '}'
    ].join('\n');

    function mkShader(type, src) {
      var s = gl.createShader(type);
      gl.shaderSource(s, src);
      gl.compileShader(s);
      return s;
    }
    var prog = gl.createProgram();
    gl.attachShader(prog, mkShader(gl.VERTEX_SHADER, vsSrc));
    gl.attachShader(prog, mkShader(gl.FRAGMENT_SHADER, fsSrc));
    gl.linkProgram(prog);
    gl.useProgram(prog);

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

    var tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

    gl.clearColor(0, 0, 0, 0);
    gl.viewport(0, 0, canvas.width, canvas.height);

    var raf = 0;
    var drawnOnce = false;
    function draw() {
      raf = requestAnimationFrame(draw);
      if (video.readyState < 2) return;
      if (reduced && drawnOnce) return;
      gl.bindTexture(gl.TEXTURE_2D, tex);
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);
      gl.clear(gl.COLOR_BUFFER_BIT);
      gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
      drawnOnce = true;
      if (reduced) video.pause();
    }

    if (reduced) {
      // show a single representative keyed frame
      video.addEventListener('loadeddata', function () {
        video.currentTime = Math.min(3, (video.duration || 6) / 2);
      }, { once: true });
      video.addEventListener('seeked', function () { draw(); }, { once: true });
      video.load();
    } else {
      video.play().catch(function () {});
      draw();
    }

    // Pause offscreen / in hidden tabs; resume cleanly on return
    var io = new IntersectionObserver(function (es) {
      if (reduced) return;
      if (es[0].isIntersecting) video.play().catch(function () {});
      else video.pause();
    }, { threshold: 0.1 });
    io.observe(canvas);
    var onVis = function () {
      if (reduced) return;
      if (document.hidden) video.pause();
      else video.play().catch(function () {});
    };
    document.addEventListener('visibilitychange', onVis);

    return function () {
      cancelAnimationFrame(raf);
      io.disconnect();
      document.removeEventListener('visibilitychange', onVis);
      video.pause();
      video.removeAttribute('src');
      video.load();
      canvas.remove();
      video.remove();
    };
  }, []);

  return (
    <div ref={holderRef} style={{ width: '100%' }}></div>
  );
}

Object.assign(window, { HeroPromoVideo });
