/* ============================================================================
 * Chrome.jsx — Estructura y utilidades reutilizables del sitio.
 * Contiene el "armazón" que envuelve al contenido: navegación, secciones,
 * portada, pie de página, y las utilidades de animación y layout.
 * El contenido (textos, enlaces) proviene de content.js -> window.BraphoContent.
 * Las secciones concretas viven en Sections.jsx.
 * ========================================================================== */

const { Button, NodeRule, SectionLabel } = window.BraphoDesignSystem_df0706 || {};
const C = window.BraphoContent;

/* --- Utilidades compartidas ------------------------------------------ */

// Altura de la cabecera fija; se descuenta al hacer scroll a una sección.
const HEADER_H = 76;

// Desplazamiento suave hacia una sección por su id ('top' = inicio).
// Una sola función usada por la cabecera, la portada y los botones internos.
function scrollToId(id) {
  if (id === 'top') { window.scrollTo({ top: 0, behavior: 'smooth' }); return; }
  const el = document.getElementById(id);
  if (el) window.scrollTo({ top: el.offsetTop - HEADER_H, behavior: 'smooth' });
}

// Traduce el acento de content.js ('primary'/'secondary') a variable CSS.
function accentVar(accent) {
  return accent === 'secondary' ? 'var(--node-secondary)' : 'var(--node-primary)';
}

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

/* --- Animación de aparición al hacer scroll -------------------------- */

// Devuelve [ref, visible]: `visible` pasa a true cuando el elemento entra en
// pantalla (o de inmediato si el usuario prefiere menos movimiento).
function useReveal(threshold = 0.18) {
  const ref = React.useRef(null);
  const [on, setOn] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    if (prefersReducedMotion()) { setOn(true); return; }
    const el = ref.current;
    let done = false;
    const fire = () => { if (!done) { done = true; setOn(true); } };
    const r = el.getBoundingClientRect();
    let raf = 0;
    if (r.top < window.innerHeight && r.bottom > 0) raf = requestAnimationFrame(() => requestAnimationFrame(fire));
    let io = null;
    if ('IntersectionObserver' in window) {
      io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { fire(); io.disconnect(); } }, { threshold, rootMargin: '0px 0px -8% 0px' });
      io.observe(el);
    }
    const check = () => { const b = el.getBoundingClientRect(); if (b.top < window.innerHeight * 0.92 && b.bottom > 0) fire(); };
    window.addEventListener('scroll', check, { passive: true });
    const t = setTimeout(() => { const b = el.getBoundingClientRect(); if (b.top < window.innerHeight) fire(); }, 800);
    return () => { if (io) io.disconnect(); cancelAnimationFrame(raf); clearTimeout(t); window.removeEventListener('scroll', check); };
  }, []);
  return [ref, on];
}

// Envoltura que aplica la animación de aparición a cualquier bloque.
function Reveal({ children, delay = 0, as = 'div', style }) {
  const [ref, on] = useReveal();
  const Tag = as;
  return (
    <Tag ref={ref} style={{ opacity: on ? 1 : 0, transform: on ? 'none' : 'translateY(18px)',
      transition: 'opacity var(--dur-reveal) var(--ease-out) ' + delay + 'ms, transform var(--dur-reveal) var(--ease-out) ' + delay + 'ms', ...style }}>{children}</Tag>
  );
}

// Número de columnas según el ancho de ventana. `ladder` es [[minAncho, cols], ...].
function useCols(ladder) {
  const pick = () => { const w = window.innerWidth; for (const [min, n] of ladder) if (w >= min) return n; return ladder[ladder.length - 1][1]; };
  const [n, setN] = React.useState(pick);
  React.useEffect(() => {
    const fn = () => setN(pick());
    window.addEventListener('resize', fn);
    return () => window.removeEventListener('resize', fn);
  }, []);
  return n;
}

// true cuando el ancho de la ventana es <= maxWidth (pantallas pequeñas / móvil).
function useIsNarrow(maxWidth = 640) {
  const query = '(max-width: ' + maxWidth + 'px)';
  const [narrow, setNarrow] = React.useState(() => window.matchMedia(query).matches);
  React.useEffect(() => {
    const m = window.matchMedia(query);
    const fn = () => setNarrow(m.matches);
    fn();
    m.addEventListener ? m.addEventListener('change', fn) : m.addListener(fn);
    return () => { m.removeEventListener ? m.removeEventListener('change', fn) : m.removeListener(fn); };
  }, []);
  return narrow;
}

/* --- Contenedor y sección genéricos ---------------------------------- */

function Container({ children, narrow, style }) {
  return <div style={{ width: '100%', maxWidth: narrow ? 'var(--container-narrow)' : 'var(--container)', margin: '0 auto', padding: '0 clamp(20px,5vw,48px)', ...style }}>{children}</div>;
}

// Sección con cabecera opcional (etiqueta + título + intro) y variantes de tono.
function Section({ id, label, node = 'primary', title, intro, children, tone = 'page', wide, introFull }) {
  const inverse = tone === 'ink';
  return (
    <section id={id} style={{
      padding: 'clamp(56px,7vw,96px) 0 clamp(80px,11vw,140px)',
      background: inverse ? 'var(--ink-800)' : tone === 'raised' ? 'var(--paper-200)' : 'transparent',
      backgroundImage: inverse ? 'var(--grid-paper-inverse)' : 'none',
      color: inverse ? 'var(--paper-100)' : 'var(--text-body)',
    }}>
      <Container>
        {(label || title) && (
          <Reveal style={{ marginBottom: children ? 'clamp(48px,6vw,80px)' : 0 }}>
            {label && <SectionLabel node={inverse ? 'inverse' : node} tone={inverse ? 'inverse' : 'muted'} style={{ marginBottom: 'var(--space-5)' }}>{label}</SectionLabel>}
            {title && <h2 style={{ fontSize: 'var(--size-h2)', fontWeight: 'var(--weight-medium)', maxWidth: wide ? '30ch' : '24ch', color: inverse ? 'var(--paper-100)' : 'var(--text-strong)', marginBottom: intro ? 'var(--space-5)' : 0 }}>{title}</h2>}
            {intro && <p style={{ maxWidth: introFull ? 'none' : '50ch', fontSize: 'var(--size-body-lg)', color: inverse ? 'var(--ink-300)' : 'var(--ink-600)' }}>{intro}</p>}
          </Reveal>
        )}
        {children}
      </Container>
    </section>
  );
}

/* --- Cabecera -------------------------------------------------------- */

// Ícono de menú (tres líneas) / cerrar (X) para la cabecera móvil.
function MenuIcon({ open }) {
  return (
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" aria-hidden="true">
      {open
        ? <><line x1="5" y1="5" x2="19" y2="19" /><line x1="19" y1="5" x2="5" y2="19" /></>
        : <><line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="18" x2="21" y2="18" /></>}
    </svg>
  );
}

function Header() {
  const [scrolled, setScrolled] = React.useState(false);
  const [open, setOpen] = React.useState(false);
  // En pantallas medias y grandes se muestra la navegación completa; en
  // pantallas pequeñas (<=640px) se colapsa en un menú desplegable.
  const narrow = useIsNarrow(640);
  React.useEffect(() => {
    const fn = () => setScrolled(window.scrollY > 8);
    fn(); window.addEventListener('scroll', fn, { passive: true });
    return () => window.removeEventListener('scroll', fn);
  }, []);
  // Al pasar a pantalla ancha, cierra el menú desplegable si quedó abierto.
  React.useEffect(() => { if (!narrow) setOpen(false); }, [narrow]);

  // Navega a una sección y cierra el menú móvil.
  const goto = (target) => { setOpen(false); scrollToId(target); };

  return (
    <header style={{ position: 'sticky', top: 0, zIndex: 20, background: 'var(--paper-100)', borderBottom: '1px solid ' + (scrolled || open ? 'var(--paper-300)' : 'transparent'), transition: 'border-color var(--dur-base) var(--ease-standard)' }}>
      <Container style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', height: HEADER_H, gap: 'var(--space-5)' }}>
        <a href="#top" onClick={(e) => { e.preventDefault(); goto('top'); }} style={{ border: 'none', display: 'flex', alignItems: 'center' }}>
          <img src={C.site.logo} alt={C.site.brand} style={{ height: 40, width: 'auto', display: 'block' }} />
        </a>

        {narrow ? (
          // --- Móvil: botón hamburguesa ---
          <button aria-label={open ? 'Cerrar menú' : 'Abrir menú'} aria-expanded={open} onClick={() => setOpen((v) => !v)}
            style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 44, height: 44, padding: 0, border: 'none', background: 'transparent', color: 'var(--ink-800)', cursor: 'pointer', marginRight: -8 }}>
            <MenuIcon open={open} />
          </button>
        ) : (
          // --- Medias/desktop: navegación completa (sin cambios) ---
          <nav style={{ display: 'flex', gap: 'var(--space-6)', alignItems: 'center' }}>
            {C.site.nav.map(({ label, target }) => (
              <a key={target} href={'#' + target} onClick={(e) => { e.preventDefault(); goto(target); }}
                style={{ fontSize: 'var(--size-small)', color: 'var(--ink-600)', border: 'none' }}>{label}</a>
            ))}
            <Button size="sm" variant="secondary" onClick={() => goto('contacto')}>Conversemos</Button>
          </nav>
        )}
      </Container>

      {/* Panel desplegable móvil: se despliega bajo la barra y no empuja el contenido. */}
      {narrow && open && (
        <div style={{ position: 'absolute', top: '100%', left: 0, right: 0, background: 'var(--paper-100)', borderBottom: '1px solid var(--paper-300)', boxShadow: '0 12px 24px rgba(18,23,29,.08)' }}>
          <Container style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-4)', padding: 'var(--space-5) clamp(20px,5vw,48px) var(--space-6)' }}>
            {C.site.nav.map(({ label, target }) => (
              <a key={target} href={'#' + target} onClick={(e) => { e.preventDefault(); goto(target); }}
                style={{ fontSize: 'var(--size-body-lg)', color: 'var(--ink-800)', border: 'none', padding: 'var(--space-2) 0' }}>{label}</a>
            ))}
            <Button size="md" variant="secondary" onClick={() => goto('contacto')} style={{ justifyContent: 'center', marginTop: 'var(--space-2)' }}>Conversemos</Button>
          </Container>
        </div>
      )}
    </header>
  );
}

/* --- Portada (Hero) -------------------------------------------------- */

/* Red viva: nodo central y tres nodos de distinto tamaño en órbitas oscilantes, siempre enlazados. */
function HeroLink() {
  const [ref, on] = useReveal(0.3);
  const ease = 'var(--ease-out)';
  const W = 400, H = 320, cx = 200, cy = 160;
  const sats = [
    { r: 9, orbit: 112, speed: 0.045, phase: 0.2, wob: 0.07, wobF: 0.7, color: 'var(--node-primary)' },
    { r: 7, orbit: 100, speed: -0.06, phase: 2.4, wob: 0.09, wobF: 0.5, color: 'var(--node-secondary)' },
    { r: 6, orbit: 130, speed: 0.035, phase: 4.3, wob: 0.06, wobF: 0.9, color: 'var(--node-primary)' },
  ];
  const [t, setT] = React.useState(0);
  React.useEffect(() => {
    if (!on || prefersReducedMotion()) return;
    let raf, last = performance.now();
    const tick = (now) => { const dt = Math.min(now - last, 50) / 1000; last = now; setT((v) => v + dt); raf = requestAnimationFrame(tick); };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [on]);
  const pos = sats.map((s) => {
    const a = s.phase + t * s.speed * Math.PI * 2;
    const wob = 1 + s.wob * Math.sin(t * s.wobF + s.phase);
    return { x: cx + Math.cos(a) * s.orbit * wob * 1.18, y: cy + Math.sin(a) * s.orbit * wob * 0.72 };
  });
  const pct = (v, total) => (v / total * 100) + '%';
  return (
    <div ref={ref} style={{ border: '1.5px solid var(--line-rule)', borderRadius: 'var(--radius-md)', background: 'var(--paper-200)', backgroundImage: 'var(--grid-paper)', aspectRatio: '5 / 4', position: 'relative', overflow: 'hidden' }}>
      <svg viewBox={'0 0 ' + W + ' ' + H} preserveAspectRatio="none" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }} aria-hidden="true">
        {pos.map((p, i) => (
          <line key={i} x1={cx} y1={cy} x2={p.x} y2={p.y} stroke="var(--ink-800)" strokeWidth="1.5" vectorEffect="non-scaling-stroke" pathLength="1" strokeDasharray="1" strokeDashoffset={on ? 0 : 1} style={{ transition: 'stroke-dashoffset 800ms ' + ease + ' ' + (700 + i * 180) + 'ms' }} />
        ))}
      </svg>
      {sats.map((s, i) => (
        <span key={i} style={{ position: 'absolute', left: pct(pos[i].x, W), top: pct(pos[i].y, H), width: s.r * 2, height: s.r * 2, borderRadius: '50%', background: s.color, border: '1.5px solid var(--ink-800)', transform: on ? 'translate(-50%,-50%) scale(1)' : 'translate(-50%,-50%) scale(0)', transition: 'transform 480ms ' + ease + ' ' + (400 + i * 180) + 'ms' }} />
      ))}
      <span style={{ position: 'absolute', zIndex: 2, left: pct(cx, W), top: pct(cy, H), width: 26, height: 26, borderRadius: '50%', background: 'var(--ink-800)', boxShadow: '0 0 0 5px var(--paper-200), 0 0 0 6.5px var(--ink-800)', transform: on ? 'translate(-50%,-50%) scale(1)' : 'translate(-50%,-50%) scale(0)', transition: 'transform 520ms ' + ease + ' 200ms' }} />
    </div>
  );
}

function Hero() {
  const h = C.hero;
  return (
    <section id="top" style={{ padding: 'clamp(32px,5vw,72px) 0 clamp(72px,9vw,120px)' }}>
      <Container>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(min(100%,340px),1fr))', gap: 'clamp(40px,6vw,96px)', alignItems: 'center' }}>
          <div>
            <Reveal><SectionLabel style={{ marginBottom: 'var(--space-6)' }}>{h.label}</SectionLabel></Reveal>
            <Reveal delay={80}>
              <h1 style={{ fontSize: 'var(--size-display)', fontWeight: 'var(--weight-medium)', lineHeight: 'var(--leading-tight)', maxWidth: '14ch', marginBottom: 'var(--space-6)' }}>
                {h.title}
              </h1>
            </Reveal>
            <Reveal delay={160}>
              <p style={{ fontSize: 'var(--size-body-lg)', color: 'var(--ink-600)', maxWidth: '40ch', marginBottom: 'var(--space-8)' }}>
                {h.text}
              </p>
            </Reveal>
            <Reveal delay={240} style={{ display: 'flex', gap: 'var(--space-5)', flexWrap: 'wrap', alignItems: 'center' }}>
              <Button size="lg" onClick={() => scrollToId(h.primaryCta.target)}>{h.primaryCta.label}</Button>
              <Button variant="ghost" onClick={() => scrollToId(h.secondaryCta.target)}>{h.secondaryCta.label}</Button>
            </Reveal>
          </div>
          <HeroLink />
        </div>
      </Container>
    </section>
  );
}

/* --- Pie de página --------------------------------------------------- */

function Footer() {
  const { site, footer } = C;
  return (
    <footer style={{ background: 'var(--ink-800)', color: 'var(--paper-100)', padding: 'clamp(56px,7vw,88px) 0 var(--space-6)' }}>
      <Container>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(min(100%,220px),1fr))', gap: 'var(--space-7)', alignItems: 'start' }}>
          <div>
            <img src={site.logoCream} alt={site.brand} style={{ height: 26, display: 'block', marginBottom: 'var(--space-4)' }} />
            <p style={{ margin: 0, fontSize: 'var(--size-small)', color: 'var(--ink-300)', maxWidth: '30ch' }}>{footer.tagline}</p>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-2)', fontSize: 'var(--size-small)' }}>
            <span style={{ color: 'var(--ink-300)' }}>{footer.locationLabel}</span>
            <span>{site.location}</span>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-2)', fontSize: 'var(--size-small)' }}>
            <span style={{ color: 'var(--ink-300)' }}>{footer.contactLabel}</span>
            {site.social.map(({ label, href, icon }) => (
              <a key={label} href={href} style={{ color: 'var(--paper-100)', display: 'inline-flex', alignItems: 'center', gap: 8, border: 'none', width: 'fit-content' }}>
                <i data-lucide={icon} style={{ width: 14, height: 14 }}></i>{label}
              </a>
            ))}
          </div>
        </div>
        <div style={{ marginTop: 'clamp(48px,6vw,80px)', paddingTop: 'var(--space-4)', borderTop: '1px solid var(--ink-600)', display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap', gap: 'var(--space-3)', fontSize: 'var(--size-label)', color: 'var(--ink-300)' }}>
          <span>{footer.copyright}</span>
          <span>{footer.credits}</span>
        </div>
      </Container>
    </footer>
  );
}

Object.assign(window, { scrollToId, accentVar, useReveal, useCols, Reveal, Container, Header, Section, Hero, Footer });
