/* HeroGlobe.jsx — "la baliza: señal desde Mexicali."
   Reemplaza el fondo del hero por una BALIZA / radar: anillos punteados
   concéntricos que emanan de un punto sienna que late, pings de sonar que se
   expanden, un barrido giratorio y el reloj vivo de Mexicali + coordenadas.
   Es un canvas FIJO (persiste del hero hasta que se asienta la línea punteada
   del manifiesto) que se aleja y se desvanece — la señal antes del despegue.
   (Conserva el nombre window.HeroGlobe para no tocar el resto del cableado.) */
(function () {
  function HeroGlobe() {
    React.useEffect(() => {
      const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
      const SIENNA = '#BA6849';
      const PAPER = '#f5f4ef';
      // los 4 colores de categoría — la señal ya no es monocromática
      const AZURE = '#477AB3', VERDE = '#618E48', YELLOW = '#D2B440';
      const CATS = [AZURE, VERDE, SIENNA, YELLOW];   // azul · verde · sienna · amarillo
      const DEG = Math.PI / 180;
      const clamp = (v, a, b) => Math.max(a, Math.min(b, v));

      // canvas fijo, detrás del contenido (.page es z-index 1), sobre el starfield
      const cv = document.createElement('canvas');
      cv.setAttribute('aria-hidden', 'true');
      Object.assign(cv.style, {
        position: 'fixed', inset: '0', width: '100%', height: '100%',
        zIndex: '0', pointerEvents: 'none', display: 'block',
        opacity: '0', transition: 'opacity 0.6s ease'
      });
      document.body.appendChild(cv);
      const ctx = cv.getContext('2d');

      let W = 0, H = 0, dpr = 1, cx = 0, cy = 0, maxR = 1;
      function resize() {
        dpr = Math.min(2, window.devicePixelRatio || 1);
        W = cv.width = Math.max(1, Math.round(window.innerWidth * dpr));
        H = cv.height = Math.max(1, Math.round(window.innerHeight * dpr));
        cx = W / 2; cy = H * 0.46;
        maxR = Math.min(W, H) * 0.60;
      }
      resize();

      // ── fade: la baliza dura hasta que la LÍNEA PUNTEADA del manifiesto se asienta ──
      let fade = 0;
      function onScroll() {
        const vh = window.innerHeight;
        const div = document.querySelector('#manifiesto .dot-divider') || document.getElementById('manifiesto');
        if (!div) { fade = 0; return; }
        const dtop = div.getBoundingClientRect().top;
        // 0 mientras la línea está abajo · 1 cuando sube a ~0.45vh (su reposo al fijarse)
        fade = clamp((vh - dtop) / (vh * 0.55), 0, 1);
      }
      window.addEventListener('scroll', onScroll, { passive: true });
      onScroll();

      function hexA(hex, a) {
        const n = parseInt(hex.slice(1), 16);
        return 'rgba(' + ((n >> 16) & 255) + ',' + ((n >> 8) & 255) + ',' + (n & 255) + ',' + clamp(a, 0, 1) + ')';
      }
      const fmt = (() => {
        try {
          return new Intl.DateTimeFormat('en-GB', { timeZone: 'America/Tijuana', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false });
        } catch (e) { return null; }
      })();
      function mxTime() {
        if (fmt) return fmt.format(new Date());
        const d = new Date(Date.now() - 8 * 3600 * 1000);
        return d.toISOString().slice(11, 19);
      }

      // dibuja un anillo PUNTEADO (en vez de stroke continuo — lenguaje de la casa)
      function dottedRing(r, col, a, dotR, gap) {
        if (r < 2) return;
        const circ = 2 * Math.PI * r;
        const n = Math.max(12, Math.round(circ / (gap * dpr)));
        ctx.fillStyle = hexA(col, a);
        for (let i = 0; i < n; i++) {
          const ang = (i / n) * Math.PI * 2;
          ctx.beginPath();
          ctx.arc(cx + Math.cos(ang) * r, cy + Math.sin(ang) * r, dotR * dpr, 0, 7);
          ctx.fill();
        }
      }

      let raf = 0, t0 = performance.now(), hasEntered = false, paused = false;
      function frame(now) {
        if (paused) return;
        const entered = document.body.classList.contains('entered');
        cv.style.opacity = entered ? '1' : '0';
        if (!entered) {
          t0 = now; // keep timer at zero until entered
          ctx.clearRect(0, 0, W, H);
          raf = requestAnimationFrame(frame);
          return;
        }
        if (!hasEntered) {
          t0 = now; // ensure clean start
          hasEntered = true;
        }
        const t = (now - t0) / 1000;
        const vis = 1 - fade;
        ctx.clearRect(0, 0, W, H);
        if (vis <= 0.002) { raf = requestAnimationFrame(frame); return; }

        // el radar EMANA del punto de "dot.com" (#heroDot) para que todo encaje
        const dotEl = document.getElementById('heroDot');
        if (dotEl) {
          const dr = dotEl.getBoundingClientRect();
          if (dr.width > 0) { cx = (dr.left + dr.width / 2) * dpr; cy = (dr.top + dr.height / 2) * dpr; }
        }
        const hudX = W / 2;   // el HUD se queda centrado en el viewport

        // zoom-out suave al alejarnos (la señal se encoge, centrada)
        const recede = 1 - fade * 0.34;
        const R = maxR * recede;

        // halo de la señal
        const hg = ctx.createRadialGradient(cx, cy, R * 0.04, cx, cy, R * 1.05);
        hg.addColorStop(0, hexA(SIENNA, 0.10 * vis));
        hg.addColorStop(0.6, hexA(SIENNA, 0.04 * vis));
        hg.addColorStop(1, hexA(SIENNA, 0));
        ctx.fillStyle = hg;
        ctx.beginPath(); ctx.arc(cx, cy, R * 1.05, 0, 7); ctx.fill();

        // retícula de anillos punteados fijos (cada anillo, un color de categoría)
        const RINGS = 5;
        for (let k = 1; k <= RINGS; k++) {
          const r = (k / RINGS) * R;
          const col = CATS[(k - 1) % CATS.length];
          dottedRing(r, col, (0.13 + 0.05 * (RINGS - k)) * vis, 0.9, 13);
        }
        // ejes punteados (cruz de coordenadas)
        ctx.fillStyle = hexA(SIENNA, 0.12 * vis);
        for (let d = -RINGS; d <= RINGS; d++) {
          if (d === 0) continue;
          const r = (d / RINGS) * R;
          [[cx + r, cy], [cx, cy + r]].forEach(([px, py]) => {
            ctx.beginPath(); ctx.arc(px, py, 0.9 * dpr, 0, 7); ctx.fill();
          });
        }
        // ticks N/E/S/O fuera del anillo (cada uno, un color de categoría)
        ['N', 'E', 'S', 'O'].forEach((lb, i) => {
          const ang = -Math.PI / 2 + i * Math.PI / 2;
          const px = cx + Math.cos(ang) * (R + 16 * dpr), py = cy + Math.sin(ang) * (R + 16 * dpr);
          ctx.fillStyle = hexA(CATS[i % CATS.length], 0.6 * vis);
          ctx.font = '600 ' + (9 * dpr) + 'px "Cera Pro", system-ui, sans-serif';
          ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
          ctx.fillText(lb, px, py);
        });

        // ── pings de sonar (cada ping, un color de categoría) ──
        const PINGS = 3;
        for (let k = 0; k < PINGS; k++) {
          const ph = reduce ? 0.5 : ((t * 0.22 + k / PINGS) % 1);
          const r = ph * R;
          const a = (1 - ph) * 0.55 * vis;
          const col = CATS[(k + (reduce ? 0 : Math.floor(t * 0.22 + k / PINGS))) % CATS.length];
          dottedRing(r, col, a, 1.1, 11);
        }

        // ── barrido del radar (línea giratoria con estela) ──
        if (!reduce) {
          const sweep = t * 0.9;
          for (let s = 0; s < 26; s++) {
            const ang = sweep - s * 0.05;
            const a = (1 - s / 26) * 0.20 * vis;
            const r = R;
            ctx.strokeStyle = hexA(SIENNA, a);
            ctx.lineWidth = 1 * dpr;
            ctx.beginPath(); ctx.moveTo(cx, cy); ctx.lineTo(cx + Math.cos(ang) * r, cy + Math.sin(ang) * r); ctx.stroke();
          }
        }

        // ── punto central que late (el origen · la marca) ──
        const breathe = reduce ? 0.7 : (0.5 + 0.5 * Math.sin(t * (Math.PI * 2 / 5)));
        const cr = (5.5 + breathe * 2.5) * dpr;
        ctx.fillStyle = hexA(SIENNA, 0.22 * vis);
        ctx.beginPath(); ctx.arc(cx, cy, cr * 3.0, 0, 7); ctx.fill();
        ctx.fillStyle = hexA(SIENNA, vis);
        ctx.beginPath(); ctx.arc(cx, cy, cr, 0, 7); ctx.fill();
        ctx.fillStyle = hexA(PAPER, 0.85 * vis);
        ctx.beginPath(); ctx.arc(cx, cy, cr * 0.34, 0, 7); ctx.fill();

        // ── HUD: transmitiendo desde Mexicali + reloj vivo (verde) + coords ──
        const baseY = Math.min(cy + R + 40 * dpr, H - 132 * dpr);
        ctx.textAlign = 'center'; ctx.textBaseline = 'alphabetic';
        if (ctx.letterSpacing !== undefined) ctx.letterSpacing = (3 * dpr) + 'px';
        ctx.font = '600 ' + (9.5 * dpr) + 'px "Cera Pro", system-ui, sans-serif';
        ctx.fillStyle = hexA(PAPER, 0.42 * vis);
        ctx.fillText('TRANSMITIENDO DESDE MEXICALI', hudX, baseY);
        if (ctx.letterSpacing !== undefined) ctx.letterSpacing = (2 * dpr) + 'px';
        ctx.font = '700 ' + (15 * dpr) + 'px "Cera Pro", system-ui, sans-serif';
        ctx.fillStyle = hexA(SIENNA, 0.95 * vis);
        ctx.fillText(mxTime() + ' PST', hudX, baseY + 22 * dpr);
        ctx.font = '500 ' + (9 * dpr) + 'px "Cera Pro", system-ui, sans-serif';
        ctx.fillStyle = hexA(PAPER, 0.34 * vis);
        ctx.fillText('32.6°N · 115.5°O', hudX, baseY + 38 * dpr);
        if (ctx.letterSpacing !== undefined) ctx.letterSpacing = '0px';

        raf = requestAnimationFrame(frame);
      }
      raf = requestAnimationFrame(frame);

      let rt;
      const onResize = () => { clearTimeout(rt); rt = setTimeout(resize, 150); };
      window.addEventListener('resize', onResize);

      // pestana oculta (in-app de IG/Meta en background) -> congelar el radar
      // 2D: deja de quemar main-thread/bateria mientras no se ve.
      const onVis = () => {
        if (document.hidden) { paused = true; cancelAnimationFrame(raf); }
        else if (paused) { paused = false; t0 = performance.now(); raf = requestAnimationFrame(frame); }
      };
      document.addEventListener('visibilitychange', onVis);

      return () => {
        cancelAnimationFrame(raf);
        window.removeEventListener('scroll', onScroll);
        window.removeEventListener('resize', onResize);
        document.removeEventListener('visibilitychange', onVis);
        cv.remove();
      };
    }, []);

    return null;
  }

  window.HeroGlobe = HeroGlobe;
})();
