/* Billboard AR Experience — UI kit FX (hand-ported, no deps)
   Premium motion inspired by 21st.dev (shaders + tilt), implemented in
   plain WebGL + React. Everything degrades gracefully and respects
   prefers-reduced-motion. Loaded BEFORE the section files so <ShaderBG/>
   and <Tilt/> are available as globals (same pattern as Reveal/Section). */

const { useEffect: useFxEffect, useRef: useFxRef, useState: useFxState } = React;

const __fxReduce = () =>
  window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;

/* ============================================================
   ShaderBG — flowing azul→violeta→magenta gradient (WebGL).
   Sits behind the hero content, blended over the photo. If WebGL
   is unavailable the canvas simply renders nothing and the CSS
   bloom underneath carries the look.
   ============================================================ */
function ShaderBG({ opacity = 0.9, style }) {
  const ref = useFxRef(null);
  useFxEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const gl = canvas.getContext("webgl", { antialias: true, alpha: true, premultipliedAlpha: false });
    if (!gl) return;

    const VERT = "attribute vec2 p; void main(){ gl_Position = vec4(p, 0.0, 1.0); }";
    const FRAG = [
      "precision highp float;",
      "uniform vec2 u_res; uniform float u_t;",
      "vec3 BLUE  = vec3(0.176, 0.357, 1.000);",
      "vec3 VIOL  = vec3(0.545, 0.239, 1.000);",
      "vec3 MAG   = vec3(0.878, 0.129, 0.541);",
      "vec3 CORAL = vec3(1.000, 0.302, 0.427);",
      "float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); }",
      "float noise(vec2 p){",
      "  vec2 i = floor(p), f = fract(p);",
      "  vec2 u = f * f * (3.0 - 2.0 * f);",
      "  return mix(mix(hash(i + vec2(0.0,0.0)), hash(i + vec2(1.0,0.0)), u.x),",
      "             mix(hash(i + vec2(0.0,1.0)), hash(i + vec2(1.0,1.0)), u.x), u.y);",
      "}",
      "float fbm(vec2 p){ float v = 0.0, a = 0.5; for(int i = 0; i < 5; i++){ v += a * noise(p); p *= 2.0; a *= 0.5; } return v; }",
      "void main(){",
      "  vec2 uv = gl_FragCoord.xy / u_res.xy;",
      "  vec2 q = uv; q.x *= u_res.x / u_res.y;",
      "  float t = u_t * 0.05;",
      "  float n = fbm(q * 2.2 + vec2(t, t * 0.6));",
      "  float m = fbm(q * 1.3 - vec2(t * 0.4, t));",
      "  float g = uv.y * 0.55 + n * 0.85 + m * 0.45;",
      "  vec3 col = mix(BLUE, VIOL, smoothstep(0.10, 0.62, g));",
      "  col = mix(col, MAG,  smoothstep(0.45, 0.98, g));",
      "  col = mix(col, CORAL, smoothstep(0.82, 1.20, g) * 0.45);",
      "  float bloom = smoothstep(1.0, 0.0, uv.y);",      // brightest at the bottom
      "  col *= 0.50 + 0.95 * bloom;",
      "  float alpha = 0.30 + 0.70 * bloom;",
      "  gl_FragColor = vec4(col, alpha);",
      "}"
    ].join("\n");

    const compile = (type, src) => {
      const s = gl.createShader(type);
      gl.shaderSource(s, src);
      gl.compileShader(s);
      return s;
    };
    const prog = gl.createProgram();
    gl.attachShader(prog, compile(gl.VERTEX_SHADER, VERT));
    gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FRAG));
    gl.linkProgram(prog);
    if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) return;
    gl.useProgram(prog);

    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 loc = gl.getAttribLocation(prog, "p");
    gl.enableVertexAttribArray(loc);
    gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);

    const uRes = gl.getUniformLocation(prog, "u_res");
    const uT = gl.getUniformLocation(prog, "u_t");
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    const resize = () => {
      const w = canvas.clientWidth, h = canvas.clientHeight;
      if (!w || !h) return;
      canvas.width = Math.round(w * dpr);
      canvas.height = Math.round(h * dpr);
      gl.viewport(0, 0, canvas.width, canvas.height);
    };
    const draw = (t) => {
      gl.uniform2f(uRes, canvas.width, canvas.height);
      gl.uniform1f(uT, t);
      gl.drawArrays(gl.TRIANGLES, 0, 3);
    };

    let raf = null, start = null;
    resize();
    window.addEventListener("resize", resize);

    if (__fxReduce()) {
      draw(8.0); // a single, pleasant static frame
    } else {
      const loop = (ts) => {
        if (start === null) start = ts;
        draw((ts - start) / 1000);
        raf = requestAnimationFrame(loop);
      };
      raf = requestAnimationFrame(loop);
    }

    return () => {
      if (raf) cancelAnimationFrame(raf);
      window.removeEventListener("resize", resize);
    };
  }, []);

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

/* ============================================================
   Tilt — pointer-driven 3D tilt + accent glow wrapper.
   Wraps any card; composes with the card's own hover state.
   No-op (flat) under reduced-motion or on coarse pointers.
   ============================================================ */
function Tilt({ children, max = 7, style, className, ...rest }) {
  const ref = useFxRef(null);
  useFxEffect(() => {
    const el = ref.current;
    if (!el || __fxReduce()) return;
    if (window.matchMedia && window.matchMedia("(pointer: coarse)").matches) return;

    let raf = null;
    const move = (e) => {
      const r = el.getBoundingClientRect();
      const px = (e.clientX - r.left) / r.width;
      const py = (e.clientY - r.top) / r.height;
      const rx = (0.5 - py) * max * 2;
      const ry = (px - 0.5) * max * 2;
      if (raf) cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        el.style.transform = "perspective(820px) rotateX(" + rx.toFixed(2) + "deg) rotateY(" + ry.toFixed(2) + "deg)";
      });
    };
    const leave = () => {
      if (raf) cancelAnimationFrame(raf);
      el.style.transform = "";
    };
    el.addEventListener("pointermove", move);
    el.addEventListener("pointerleave", leave);
    return () => {
      el.removeEventListener("pointermove", move);
      el.removeEventListener("pointerleave", leave);
    };
  }, []);

  return (
    <div
      ref={ref}
      className={"kit-tilt" + (className ? " " + className : "")}
      style={{ height: "100%", transition: "transform 260ms var(--ease-out), box-shadow 320ms var(--ease-out)", transformStyle: "preserve-3d", willChange: "transform", ...style }}
      {...rest}
    >
      {children}
    </div>
  );
}

/* ============================================================
   DoorReveal — a pair of doors that swing open in 3D to reveal
   the children, on scroll into view. Built for the "la marca que
   te abre la puerta" section. No-JS / reduced-motion → starts open.
   ============================================================ */
function DoorReveal({ children, style }) {
  const ref = useFxRef(null);
  const [open, setOpen] = useFxState(false);

  useFxEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (__fxReduce() || !("IntersectionObserver" in window)) { setOpen(true); return; }
    const io = new IntersectionObserver(
      (entries) => entries.forEach((e) => { if (e.isIntersecting) { setOpen(true); io.disconnect(); } }),
      { threshold: 0.4 }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);

  const door = (isLeft) => ({
    position: "absolute", top: 0, bottom: 0, width: "50%",
    [isLeft ? "left" : "right"]: 0,
    transformOrigin: isLeft ? "left center" : "right center",
    transform: open ? "rotateY(" + (isLeft ? -115 : 115) + "deg)" : "rotateY(0deg)",
    transition: "transform 1.5s cubic-bezier(0.77, 0, 0.18, 1)",
    backfaceVisibility: "hidden",
    background: "linear-gradient(135deg, #0B1020 0%, #07080F 72%)",
    boxShadow: open ? "none" : "0 40px 90px -20px rgba(0,0,0,0.55)",
    borderRadius: isLeft ? "var(--radius-lg) 0 0 var(--radius-lg)" : "0 var(--radius-lg) var(--radius-lg) 0",
    pointerEvents: open ? "none" : "auto",
    overflow: "hidden",
    willChange: "transform",
  });

  const Door = (isLeft) => (
    <div aria-hidden="true" style={door(isLeft)}>
      {/* sheen from the top */}
      <div style={{ position: "absolute", inset: 0, background: "radial-gradient(130% 60% at 50% 0%, rgba(255,255,255,0.06), transparent 60%)" }} />
      {/* center seam accent (inner edge where both doors meet) */}
      <div style={{ position: "absolute", top: 0, bottom: 0, [isLeft ? "right" : "left"]: 0, width: "2px", background: "var(--grad-accent)", opacity: 0.9 }} />
      {/* handle */}
      <div style={{ position: "absolute", top: "50%", [isLeft ? "right" : "left"]: "18px", transform: "translateY(-50%)", width: "6px", height: "58px", borderRadius: "999px", background: "linear-gradient(180deg, var(--violet), var(--magenta))", boxShadow: "0 0 20px rgba(139,61,255,0.65)" }} />
    </div>
  );

  return (
    <div ref={ref} style={{ position: "relative", perspective: "1700px", overflow: "hidden", ...style }}>
      {children}
      {Door(true)}
      {Door(false)}
    </div>
  );
}

Object.assign(window, { ShaderBG, Tilt, DoorReveal });
