/*
  hero-frames.jsx — Hero "frame-by-frame on scroll" (técnica tipo Apple AirPods)
  ----------------------------------------------------------------------------
  - Una sección alta (≈400vh) crea la "pista" de scroll.
  - Un <canvas> sticky ocupa la pantalla.
  - GSAP ScrollTrigger mapea el progreso de scroll → índice de frame (0…N-1)
    y dibuja ese frame en el canvas. Como las imágenes están precargadas, el
    scrubbing es perfecto (sin saltos ni dependencia de <video>).
  - Encima va el texto del hero, que se desvanece conforme avanzas.
*/

const HF_FRAME_COUNT = 110;

// ── Día / Noche automático según la hora local del visitante ──
// Noche = 19:00–06:59. Cambia HF_NIGHT_ENABLED a true cuando exista el set
// nocturno en assets/frames-night/frame-000.jpg … frame-109.jpg.
const HF_NIGHT_ENABLED = true;
const hfIsNight = () => { const h = new Date().getHours(); return h >= 19 || h < 7; };
const HF_FRAME_DIR = (HF_NIGHT_ENABLED && hfIsNight()) ? 'assets/frames-night' : 'assets/frames';
const HF_FRAME_PATH = (i) => `${HF_FRAME_DIR}/frame-${String(i).padStart(3, '0')}.jpg`;

function HeroFrames({ t }) {
  const sectionRef = React.useRef(null);
  const canvasRef = React.useRef(null);
  const textRef = React.useRef(null);
  const cueRef = React.useRef(null);
  const tagRef = React.useRef(null);
  const [loaded, setLoaded] = React.useState(0);
  const [revealed, setRevealed] = React.useState(false);
  const imagesRef = React.useRef([]);

  // ---- Precarga de todos los frames ----
  React.useEffect(() => {
    let alive = true;
    const imgs = new Array(HF_FRAME_COUNT);
    let count = 0;
    for (let i = 0; i < HF_FRAME_COUNT; i++) {
      const img = new Image();
      img.decoding = 'async';
      img.onload = img.onerror = () => {
        if (!alive) return;
        count++;
        setLoaded(count);
      };
      img.src = HF_FRAME_PATH(i);
      imgs[i] = img;
    }
    imagesRef.current = imgs;
    return () => {alive = false;};
  }, []);

  // ---- Canvas: tamaño (DPR) + dibujo "cover" ----
  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d', { alpha: false });
    let curFrame = -1;
    let drewOnce = false;

    const sizeCanvas = () => {
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const w = canvas.clientWidth,h = canvas.clientHeight;
      canvas.width = Math.round(w * dpr);
      canvas.height = Math.round(h * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };

    const drawCover = (img) => {
      if (!img || !img.complete || !img.naturalWidth) return;
      const cw = canvas.clientWidth,ch = canvas.clientHeight;
      const iw = img.naturalWidth,ih = img.naturalHeight;
      const scale = Math.max(cw / iw, ch / ih);
      const w = iw * scale,h = ih * scale;
      ctx.drawImage(img, (cw - w) / 2, (ch - h) / 2, w, h);
    };

    const render = (frame) => {
      const target = Math.max(0, Math.min(HF_FRAME_COUNT - 1, frame));
      const imgs = imagesRef.current;
      // Busca el frame cargado más cercano (evita huecos negros si aún no precarga)
      let pick = -1;
      for (let d = 0; d < HF_FRAME_COUNT; d++) {
        const a = target - d,b = target + d;
        if (a >= 0 && imgs[a] && imgs[a].complete && imgs[a].naturalWidth) {pick = a;break;}
        if (b < HF_FRAME_COUNT && imgs[b] && imgs[b].complete && imgs[b].naturalWidth) {pick = b;break;}
      }
      if (pick >= 0) {
        drawCover(imgs[pick]);
        curFrame = target;
        if (!drewOnce) {drewOnce = true;setRevealed(true);}
      }
    };

    // expuesto para el ScrollTrigger
    canvas.__render = render;
    canvas.__redraw = () => render(curFrame < 0 ? 0 : curFrame);

    sizeCanvas();
    render(0);

    const onResize = () => {sizeCanvas();canvas.__redraw();};
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);

  // Redibuja el primer frame en cuanto carga (si aún no había nada)
  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (canvas && canvas.__redraw && loaded >= 1) canvas.__redraw();
  }, [loaded]);

  // ---- Driver de scroll → frame (nativo + rAF + suavizado lerp) ----
  // Mismo resultado que GSAP ScrollTrigger scrub, sin dependencias externas.
  React.useEffect(() => {
    const section = sectionRef.current;
    const canvas = canvasRef.current;
    if (!section || !canvas) return;

    let raf = 0;
    let curF = 0; // frame mostrado (suavizado)
    let targetF = 0; // frame objetivo según scroll
    let running = false;

    const setOverlays = (p) => {
      const o = 1 - Math.max(0, Math.min(1, (p - 0.08) / 0.37));
      if (textRef.current) {
        textRef.current.style.opacity = o;
        textRef.current.style.transform = `translate3d(0, ${-p * 60}px, 0)`;
      }
      if (cueRef.current) cueRef.current.style.opacity = Math.max(0, 1 - p * 6);
      if (tagRef.current) tagRef.current.style.opacity = Math.max(0, 1 - p * 3);
    };

    const computeProgress = () => {
      const rect = section.getBoundingClientRect();
      const range = section.offsetHeight - window.innerHeight;
      const scrolled = -rect.top;
      return range > 0 ? Math.max(0, Math.min(1, scrolled / range)) : 0;
    };

    const tick = () => {
      // lerp hacia el objetivo → scrubbing suave con inercia
      curF += (targetF - curF) * 0.18;
      if (Math.abs(targetF - curF) < 0.05) curF = targetF;
      const frame = Math.round(curF);
      if (canvas.__render) canvas.__render(frame);
      if (Math.abs(targetF - curF) > 0.01) {
        raf = requestAnimationFrame(tick);
      } else {
        running = false;
      }
    };

    const onScroll = () => {
      const p = computeProgress();
      targetF = p * (HF_FRAME_COUNT - 1);
      setOverlays(p);
      if (!running) {running = true;raf = requestAnimationFrame(tick);}
    };

    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', onScroll);
    // estado inicial
    const p0 = computeProgress();
    targetF = curF = p0 * (HF_FRAME_COUNT - 1);
    setOverlays(p0);
    if (canvas.__render) canvas.__render(Math.round(curF));

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

  // Revela en cuanto el canvas dibuja su primer frame con éxito (independiente
  // del contador de precarga). render() usa el frame cargado más cercano, así
  // que nunca hay hueco negro; el resto de frames sigue precargando en 2.º plano.
  const pct = Math.round(loaded / HF_FRAME_COUNT * 100);

  return (
    <section className="hero-frames" id="hero" ref={sectionRef} data-screen-label="01 Hero">
      <div className="hf-stage">
        <canvas className="hf-canvas" ref={canvasRef} />
        <div className="hf-vignette" />

        {/* Loader mientras precargan los frames */}
        <div className="hf-loader" style={{ opacity: revealed ? 0 : 1, pointerEvents: revealed ? 'none' : 'auto' }}>
          <div className="hf-loader-bar"><i style={{ width: Math.min(100, pct) + '%' }} /></div>
          <span>Cargando vista aérea</span>
        </div>

        {/* Texto del hero (mismas clases que el hero original) */}
        <div className="hero-text" ref={textRef}>
          <div className="hero-eyebrow">{t.hero.eyebrow}</div>
          <h1 className="hero-title">
            {t.hero.title1} <em>{t.hero.titleEm}</em><br />
            {t.hero.title2}
          </h1>
          <a href="propiedades.html" className="hero-cta" style={{ backgroundColor: 'rgb(52, 201, 255)' }}>
            {t.hero.cta}
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
              <path d="M2.5 8h11m0 0L9 3.5M13.5 8 9 12.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </a>
        </div>

        <div className="hero-tag" ref={tagRef}>
          <span className="hero-tag-dot" />
          <div>
            <small>Vista aérea</small>
            <b>Guadalajara · Zona Financiera</b>
          </div>
        </div>

        <div className="hero-scroll-cue" ref={cueRef} style={{ lineHeight: "1.55", letterSpacing: "2.7px" }}>{t.hero.scroll}</div>
      </div>
    </section>);

}

window.HeroFrames = HeroFrames;