// scenes-shader.jsx — WebGL shader background for AK Networks intro scenes
// Flowing organic FBM-noise field rendered on a canvas. White paper base,
// AK red streaks, deep red shadows. Animated via useSprite() localTime so it
// stays in sync with the scrubbable timeline.

const SHADER_VERT = `
attribute vec2 a_pos;
varying vec2 v_uv;
void main() {
  v_uv = (a_pos + 1.0) * 0.5;
  gl_Position = vec4(a_pos, 0.0, 1.0);
}
`;

// AK palette as vec3 (sRGB)
//   paper #FAFAF7 → 0.980, 0.980, 0.969
//   red   #E62321 → 0.902, 0.137, 0.129
//   redD  #B81B19 → 0.722, 0.106, 0.098
//   ink   #0A0A0A → 0.039, 0.039, 0.039
const SHADER_FRAG = `
precision highp float;
varying vec2 v_uv;
uniform vec2  u_res;
uniform float u_time;
uniform float u_intensity;

// — hash + value noise + fbm
float hash(vec2 p) {
  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}
float vnoise(vec2 p) {
  vec2 i = floor(p);
  vec2 f = fract(p);
  vec2 u = f*f*(3.0 - 2.0*f);
  float a = hash(i);
  float b = hash(i + vec2(1.0, 0.0));
  float c = hash(i + vec2(0.0, 1.0));
  float d = hash(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;
  float a = 0.5;
  for (int i = 0; i < 5; i++) {
    v += a * vnoise(p);
    p *= 2.05;
    a *= 0.5;
  }
  return v;
}

void main() {
  // Aspect-correct uv
  vec2 uv = v_uv;
  vec2 p = uv;
  p.x *= u_res.x / u_res.y;

  float t = u_time * 0.18;

  // — domain warp: two layers of fbm feeding into the third
  vec2 q = vec2(
    fbm(p * 1.4 + vec2(0.0, t * 0.6)),
    fbm(p * 1.4 + vec2(5.2, -t * 0.4))
  );
  vec2 r = vec2(
    fbm(p * 2.0 + 4.0 * q + vec2(1.7,  9.2) + t * 0.5),
    fbm(p * 2.0 + 4.0 * q + vec2(8.3,  2.8) - t * 0.3)
  );
  float n = fbm(p * 2.4 + 4.0 * r);

  // Shape the noise into red streaks — high-contrast band
  float redMask  = smoothstep(0.42, 0.78, n);
  float deepMask = smoothstep(0.65, 0.92, n);
  float inkMask  = smoothstep(0.88, 1.00, n) * 0.5;

  // AK palette
  vec3 paper = vec3(0.980, 0.980, 0.969);
  vec3 red   = vec3(0.902, 0.137, 0.129);
  vec3 redD  = vec3(0.722, 0.106, 0.098);
  vec3 ink   = vec3(0.039, 0.039, 0.039);

  vec3 col = paper;
  col = mix(col, red,  redMask  * 0.65 * u_intensity);
  col = mix(col, redD, deepMask * 0.45 * u_intensity);
  col = mix(col, ink,  inkMask  * 0.35 * u_intensity);

  // Subtle vignette so foreground type stays readable
  float vig = smoothstep(1.05, 0.45, length(uv - 0.5) * 1.4);
  col = mix(paper, col, 0.55 + vig * 0.45);

  // Soft white "glow" pass — lifts center
  float glow = smoothstep(0.7, 0.0, length(uv - 0.5) * 1.3);
  col = mix(col, paper, glow * 0.18);

  // Tiny film grain
  float g = (hash(uv * u_res + u_time * 30.0) - 0.5) * 0.018;
  col += g;

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

// Component — driven by useSprite localTime
function BrandShaderBG({ opacity = 1, intensity = 1 }) {
  const { localTime } = useSprite();
  const canvasRef = React.useRef(null);
  const glStateRef = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const gl = canvas.getContext('webgl', { alpha: true, antialias: true, premultipliedAlpha: false })
            || canvas.getContext('experimental-webgl');
    if (!gl) return;

    function compile(type, src) {
      const sh = gl.createShader(type);
      gl.shaderSource(sh, src);
      gl.compileShader(sh);
      if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
        console.error('Shader error:', gl.getShaderInfoLog(sh), src);
        gl.deleteShader(sh);
        return null;
      }
      return sh;
    }
    const vs = compile(gl.VERTEX_SHADER, SHADER_VERT);
    const fs = compile(gl.FRAGMENT_SHADER, SHADER_FRAG);
    if (!vs || !fs) return;

    const prog = gl.createProgram();
    gl.attachShader(prog, vs);
    gl.attachShader(prog, fs);
    gl.linkProgram(prog);
    if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
      console.error('Link error:', gl.getProgramInfoLog(prog));
      return;
    }
    gl.useProgram(prog);

    // Fullscreen quad
    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,  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 uRes  = gl.getUniformLocation(prog, 'u_res');
    const uTime = gl.getUniformLocation(prog, 'u_time');
    const uInt  = gl.getUniformLocation(prog, 'u_intensity');

    glStateRef.current = { gl, prog, uRes, uTime, uInt };

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

    return () => {
      ro.disconnect();
      gl.deleteProgram(prog);
      gl.deleteShader(vs);
      gl.deleteShader(fs);
      gl.deleteBuffer(buf);
    };
  }, []);

  // Render frame whenever localTime ticks
  React.useEffect(() => {
    const s = glStateRef.current;
    if (!s) return;
    const { gl, uRes, uTime, uInt } = s;
    gl.uniform2f(uRes, gl.canvas.width, gl.canvas.height);
    gl.uniform1f(uTime, localTime);
    gl.uniform1f(uInt, intensity);
    gl.clearColor(0.980, 0.980, 0.969, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 6);
  }, [localTime, intensity]);

  return (
    <div style={{
      position: 'absolute', inset: 0, overflow: 'hidden',
      pointerEvents: 'none', opacity,
    }}>
      <canvas ref={canvasRef} style={{
        position: 'absolute', inset: 0,
        width: '100%', height: '100%', display: 'block',
      }}/>
    </div>
  );
}

window.BrandShaderBG = BrandShaderBG;

// ─────────────────────────────────────────────────────────────────────────
// BrandLinesBG — flowing line shader. Warped sinusoidal isolines on white.
// Lines bend, drift, and breathe. AK red on paper.
// ─────────────────────────────────────────────────────────────────────────
const LINES_FRAG = `
precision highp float;
varying vec2 v_uv;
uniform vec2  u_res;
uniform float u_time;
uniform float u_intensity;

float hash(vec2 p) {
  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}
float vnoise(vec2 p) {
  vec2 i = floor(p);
  vec2 f = fract(p);
  vec2 u = f*f*(3.0 - 2.0*f);
  return mix(mix(hash(i), hash(i+vec2(1.,0.)), u.x),
             mix(hash(i+vec2(0.,1.)), hash(i+vec2(1.,1.)), u.x), u.y);
}
float fbm(vec2 p) {
  float v = 0.0; float a = 0.5;
  for (int i = 0; i < 4; i++) { v += a*vnoise(p); p *= 2.05; a *= 0.5; }
  return v;
}

void main() {
  vec2 uv = v_uv;
  vec2 p = uv;
  p.x *= u_res.x / u_res.y;

  float t = u_time * 0.25;

  // Two warp fields drive the line distortion
  float w1 = fbm(p * 1.6 + vec2(0.0, t));
  float w2 = fbm(p * 2.2 + vec2(5.0, -t * 0.7) + w1 * 1.5);

  // Warped y-coordinate forms the "stripe" function
  float y = p.y * 18.0 + w2 * 6.0 + sin(p.x * 1.4 + t * 0.6) * 1.2;

  // Take fractional part — gives stripes of period 1
  float stripe = fract(y);

  // Make a thin line at the boundary using anti-aliased threshold
  float lineWidth = 0.06;
  float aa = fwidth(y) * 1.2;
  float line = 1.0 - smoothstep(lineWidth, lineWidth + aa, abs(stripe - 0.5) - (0.5 - lineWidth));
  line = clamp(line, 0.0, 1.0);

  // Per-line opacity variation — some lines fade, simulating distance/parallax
  float band = floor(y);
  float bandSeed = hash(vec2(band, 1.0));
  float bandAlpha = 0.35 + 0.65 * bandSeed;

  // Soft envelope by row — lines near "middle" warp band are bolder
  float envelope = smoothstep(0.05, 0.4, w2) * smoothstep(0.95, 0.6, w2);
  envelope = 0.4 + 0.6 * envelope;

  // Color per line — most ink-gray, ~1 in 5 is AK red
  vec3 paper = vec3(0.980, 0.980, 0.969);
  vec3 ink   = vec3(0.039, 0.039, 0.039);
  vec3 red   = vec3(0.902, 0.137, 0.129);
  float redPick = step(0.82, bandSeed);
  vec3 lineCol = mix(ink, red, redPick);

  // Sparse extra accent: deep glow on a ~few highlighted lines, slowly cycling
  float glowPick = step(0.92, hash(vec2(band, floor(t * 0.3))));
  float glow = glowPick * (0.4 + 0.6 * sin(t * 2.0 + band));
  lineCol = mix(lineCol, red, glow * 0.7);

  // Combine
  float alpha = line * bandAlpha * envelope * u_intensity;
  vec3 col = mix(paper, lineCol, alpha);

  // Vignette
  float vig = smoothstep(1.05, 0.45, length(uv - 0.5) * 1.4);
  col = mix(paper, col, 0.5 + vig * 0.5);

  // Tiny grain
  col += (hash(uv * u_res + u_time * 30.0) - 0.5) * 0.012;

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

function BrandLinesBG({ opacity = 1, intensity = 1 }) {
  const { localTime } = useSprite();
  const canvasRef = React.useRef(null);
  const stateRef = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const gl = canvas.getContext('webgl', { alpha: true, antialias: true })
            || canvas.getContext('experimental-webgl');
    if (!gl) return;
    // Enable derivatives extension for fwidth()
    const ext = gl.getExtension('OES_standard_derivatives');
    const fragSrc = (ext ? '#extension GL_OES_standard_derivatives : enable\n' : '') + LINES_FRAG;

    function compile(type, src) {
      const sh = gl.createShader(type);
      gl.shaderSource(sh, src); gl.compileShader(sh);
      if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
        console.error('Shader err:', gl.getShaderInfoLog(sh)); return null;
      }
      return sh;
    }
    const vs = compile(gl.VERTEX_SHADER, SHADER_VERT);
    const fs = compile(gl.FRAGMENT_SHADER, fragSrc);
    if (!vs || !fs) return;

    const prog = gl.createProgram();
    gl.attachShader(prog, vs); gl.attachShader(prog, fs); 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, 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 uRes  = gl.getUniformLocation(prog, 'u_res');
    const uTime = gl.getUniformLocation(prog, 'u_time');
    const uInt  = gl.getUniformLocation(prog, 'u_intensity');

    stateRef.current = { gl, prog, uRes, uTime, uInt };

    function resize() {
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const w = canvas.clientWidth * dpr, h = canvas.clientHeight * dpr;
      if (canvas.width !== w || canvas.height !== h) {
        canvas.width = w; canvas.height = h; gl.viewport(0, 0, w, h);
      }
    }
    resize();
    const ro = new ResizeObserver(resize); ro.observe(canvas);
    return () => { ro.disconnect(); };
  }, []);

  React.useEffect(() => {
    const s = stateRef.current; if (!s) return;
    const { gl, uRes, uTime, uInt } = s;
    gl.uniform2f(uRes, gl.canvas.width, gl.canvas.height);
    gl.uniform1f(uTime, localTime);
    gl.uniform1f(uInt, intensity);
    gl.clearColor(0.980, 0.980, 0.969, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 6);
  }, [localTime, intensity]);

  return (
    <div style={{ position:'absolute', inset:0, overflow:'hidden', pointerEvents:'none', opacity }}>
      <canvas ref={canvasRef} style={{ position:'absolute', inset:0, width:'100%', height:'100%', display:'block' }}/>
    </div>
  );
}
window.BrandLinesBG = BrandLinesBG;

// ─────────────────────────────────────────────────────────────────────────
// BrandGooBG — port of 21st.dev BackgroundGradientAnimation, AK palette,
// white paper base. Five blurred radial blobs animated via CSS keyframes,
// merged through an SVG goo filter for organic edge cohesion.
// ─────────────────────────────────────────────────────────────────────────
function BrandGooBG({ opacity = 1, size = '60%', blendingValue = 'multiply' }) {
  // AK red family + ink as r,g,b triplets so they slot into rgba()
  const COLORS = {
    first:  '230, 35, 33',     // AK red
    second: '184, 27, 25',     // redDeep
    third:  '255, 90, 80',     // coral
    fourth: '10, 10, 10',      // ink
    fifth:  '255, 140, 130',   // warm pink-red
  };

  const styleId = 'ak-goo-bg-styles';
  React.useEffect(() => {
    if (document.getElementById(styleId)) return;
    const tag = document.createElement('style');
    tag.id = styleId;
    tag.textContent = `
      @keyframes akGooFirst  { 0%,100% { transform: translate(0,0) } 50% { transform: translate(-6%, 8%) } }
      @keyframes akGooSecond { 0%,100% { transform: rotate(0deg)  } 50% { transform: rotate(180deg) } }
      @keyframes akGooThird  { 0%,100% { transform: rotate(0deg)  } 50% { transform: rotate(-180deg) } }
      @keyframes akGooFourth { 0%,100% { transform: translate(0,0) } 50% { transform: translate(8%, -6%) } }
      @keyframes akGooFifth  { 0%,100% { transform: translate(0,0) scale(1) } 50% { transform: translate(-4%, -4%) scale(1.15) } }
      .ak-goo-1 { animation: akGooFirst  30s ease-in-out infinite; }
      .ak-goo-2 { animation: akGooSecond 22s ease-in-out infinite; }
      .ak-goo-3 { animation: akGooThird  26s ease-in-out infinite; }
      .ak-goo-4 { animation: akGooFourth 34s ease-in-out infinite; }
      .ak-goo-5 { animation: akGooFifth  18s ease-in-out infinite; }
    `;
    document.head.appendChild(tag);
  }, []);

  // Detect Safari to avoid the goo filter (it's heavy + sometimes broken there)
  const [isSafari, setIsSafari] = React.useState(false);
  React.useEffect(() => {
    setIsSafari(/^((?!chrome|android).)*safari/i.test(navigator.userAgent));
  }, []);

  const blobBase = {
    position: 'absolute',
    width: size, height: size,
    top: `calc(50% - ${parseFloat(size)/2}%)`,
    left: `calc(50% - ${parseFloat(size)/2}%)`,
    mixBlendMode: blendingValue,
    transformOrigin: 'center center',
    pointerEvents: 'none',
  };

  return (
    <div style={{
      position: 'absolute', inset: 0, overflow: 'hidden',
      pointerEvents: 'none',
      background: AK.paper,
      opacity,
    }}>
      {/* SVG goo filter — merges blob edges into one organic shape */}
      <svg style={{ position: 'absolute', width: 0, height: 0 }}>
        <defs>
          <filter id="akGooFilter">
            <feGaussianBlur in="SourceGraphic" stdDeviation="14" result="blur"/>
            <feColorMatrix in="blur" mode="matrix"
              values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -8" result="goo"/>
            <feBlend in="SourceGraphic" in2="goo"/>
          </filter>
        </defs>
      </svg>

      {/* Gradients container — goo filter applied here */}
      <div style={{
        position: 'absolute', inset: 0, width: '100%', height: '100%',
        filter: isSafari ? 'blur(40px)' : 'url(#akGooFilter) blur(30px)',
      }}>
        {/* Blob 1 — AK red, full opacity */}
        <div className="ak-goo-1" style={{
          ...blobBase,
          background: `radial-gradient(circle at center, rgb(${COLORS.first}) 0%, rgba(${COLORS.first},0) 50%) no-repeat`,
          opacity: 1,
        }}/>

        {/* Blob 2 — redDeep, rotates around offset center */}
        <div className="ak-goo-2" style={{
          ...blobBase,
          transformOrigin: 'calc(50% - 400px) center',
          background: `radial-gradient(circle at center, rgba(${COLORS.second},0.85) 0%, rgba(${COLORS.second},0) 50%) no-repeat`,
          opacity: 1,
        }}/>

        {/* Blob 3 — coral, counter-rotates */}
        <div className="ak-goo-3" style={{
          ...blobBase,
          transformOrigin: 'calc(50% + 400px) center',
          background: `radial-gradient(circle at center, rgba(${COLORS.third},0.75) 0%, rgba(${COLORS.third},0) 50%) no-repeat`,
          opacity: 1,
        }}/>

        {/* Blob 4 — ink, low opacity, drifts */}
        <div className="ak-goo-4" style={{
          ...blobBase,
          transformOrigin: 'calc(50% - 200px) center',
          background: `radial-gradient(circle at center, rgba(${COLORS.fourth},0.45) 0%, rgba(${COLORS.fourth},0) 50%) no-repeat`,
          opacity: 0.55,
        }}/>

        {/* Blob 5 — warm pink-red, scales+drifts */}
        <div className="ak-goo-5" style={{
          ...blobBase,
          transformOrigin: 'calc(50% - 800px) calc(50% + 800px)',
          background: `radial-gradient(circle at center, rgba(${COLORS.fifth},0.7) 0%, rgba(${COLORS.fifth},0) 50%) no-repeat`,
          opacity: 1,
        }}/>
      </div>

      {/* Subtle vignette for cinematic frame + foreground readability */}
      <div style={{
        position: 'absolute', inset: 0,
        background: `radial-gradient(ellipse at center, transparent 45%, ${AK.paper}CC 100%)`,
      }}/>
    </div>
  );
}
window.BrandGooBG = BrandGooBG;

// ─────────────────────────────────────────────────────────────────────────
// BrandSoftBG — editorial drift. Two giant blurred AK-red washes plus one
// ink shadow, all moving on slow sinusoids driven by Stage time. No goo,
// no grain — just atmosphere that doesn't compete with type.
// ─────────────────────────────────────────────────────────────────────────
function BrandSoftBG({ opacity = 1, intensity = 0.22 }) {
  const { localTime } = useSprite();
  const t = localTime;

  // Two warm washes drifting, plus an ink shadow. Slow but not glacial.
  const ax = 30 + Math.sin(t * 0.18) * 18;       // %
  const ay = 40 + Math.cos(t * 0.14) * 14;
  const bx = 70 + Math.sin(t * 0.13 + 2) * 16;
  const by = 65 + Math.cos(t * 0.16 + 1) * 12;
  const cx = 50 + Math.sin(t * 0.10 + 3) * 24;
  const cy = 55 + Math.cos(t * 0.09 + 2) * 18;

  const aAlpha = Math.round(intensity * 255).toString(16).padStart(2, '0');
  const bAlpha = Math.round(intensity * 0.85 * 255).toString(16).padStart(2, '0');
  const cAlpha = Math.round(intensity * 0.4 * 255).toString(16).padStart(2, '0');

  return (
    <div style={{
      position: 'absolute', inset: 0, overflow: 'hidden',
      pointerEvents: 'none', opacity,
    }}>
      {/* Wash A — AK red, large soft */}
      <div style={{
        position: 'absolute', inset: '-20%',
        background: `radial-gradient(40% 35% at ${ax}% ${ay}%, ${AK.red}${aAlpha} 0%, transparent 70%)`,
        filter: 'blur(40px)',
      }}/>

      {/* Wash B — redDeep, smaller, opposite drift */}
      <div style={{
        position: 'absolute', inset: '-20%',
        background: `radial-gradient(35% 30% at ${bx}% ${by}%, ${AK.redDeep}${bAlpha} 0%, transparent 70%)`,
        filter: 'blur(50px)',
      }}/>

      {/* Shadow C — ink, subtle warmth/depth */}
      <div style={{
        position: 'absolute', inset: '-20%',
        background: `radial-gradient(50% 40% at ${cx}% ${cy}%, ${AK.ink}${cAlpha} 0%, transparent 75%)`,
        filter: 'blur(80px)',
        mixBlendMode: 'multiply',
      }}/>
    </div>
  );
}
window.BrandSoftBG = BrandSoftBG;
