/* ═══════════════════════════════════════════════════════════════════════════
   ESBART — Shared <Subnav> component (sub-navegació de pàgina)
   Rail lateral (desktop >1100px) + barra editorial sticky (pantalles petites).

   Props:
     items      — [{ id, label }] en ordre de pàgina (ids de seccions reals)
     active     — opcional: id actiu controlat externament (p. ex. acordió
                  d'Activitats). Si es passa, el scrollspy intern es desactiva.
     onNavigate — opcional: callback(id) abans de l'scroll (p. ex. obrir la
                  fila d'un acordió). L'scroll espera 120ms si existeix.
     label      — aria-label (default "Índex de seccions")

   Requereix shared/subnav.css. Exporta window.EsbartSubnav.
   ═══════════════════════════════════════════════════════════════════════════ */

function EsbartSubnav({ items, active, onNavigate, label = "Índex de seccions" }) {
  const first = items && items.length ? items[0].id : null;
  const [spy, setSpy] = React.useState(first);
  const controlled = active !== undefined && active !== null;
  const cur = controlled ? active : spy;
  const barRef = React.useRef(null);
  const innerRef = React.useRef(null);
  const progRef = React.useRef(null);

  /* Scrollspy determinista: l'activa és l'última secció el top de la qual ha
     creuat la línia de referència (38% del viewport); al final absolut de
     pàgina, sempre l'última. (Evita els salts de l'IntersectionObserver amb
     rootMargin dins d'iframes.) */
  React.useEffect(() => {
    if (controlled || !items || !items.length) return;
    let tick = false;
    const compute = () => {
      tick = false;
      const ref = window.scrollY + window.innerHeight * 0.38;
      let act = items[0].id;
      for (let i = 0; i < items.length; i++) {
        const el = document.getElementById(items[i].id);
        if (el && el.offsetTop <= ref) act = items[i].id;
      }
      if (window.scrollY > 0 &&
          window.scrollY + window.innerHeight >= document.documentElement.scrollHeight - 4) {
        act = items[items.length - 1].id;
      }
      setSpy(act);
    };
    const onScroll = () => { if (!tick) { tick = true; requestAnimationFrame(compute); } };
    window.addEventListener('scroll', onScroll, { passive: true });
    /* El layout inicial pot ser curt (imatges pendents): recalcula a 'load'
       i amb un parell de represes diferides per evitar un actiu inicial erròni. */
    window.addEventListener('load', compute);
    const t1 = setTimeout(compute, 600);
    const t2 = setTimeout(compute, 1800);
    compute();
    return () => {
      window.removeEventListener('scroll', onScroll);
      window.removeEventListener('load', compute);
      clearTimeout(t1); clearTimeout(t2);
    };
  }, [items, controlled]);

  /* Barra: progrés de lectura + fades de scroll lateral */
  React.useEffect(() => {
    const bar = barRef.current, inner = innerRef.current, prog = progRef.current;
    if (!bar || !inner) return;
    const updProgress = () => {
      const max = document.documentElement.scrollHeight - window.innerHeight;
      if (prog) prog.style.width = (max > 0 ? (window.scrollY / max) * 100 : 0) + '%';
    };
    const updFades = () => {
      bar.classList.toggle('can-l', inner.scrollLeft > 4);
      bar.classList.toggle('can-r', inner.scrollLeft + inner.clientWidth < inner.scrollWidth - 4);
    };
    const onResize = () => { updProgress(); updFades(); };
    window.addEventListener('scroll', updProgress, { passive: true });
    window.addEventListener('resize', onResize);
    inner.addEventListener('scroll', updFades, { passive: true });
    updProgress(); updFades();
    return () => {
      window.removeEventListener('scroll', updProgress);
      window.removeEventListener('resize', onResize);
      inner.removeEventListener('scroll', updFades);
    };
  }, []);

  /* Barra: autocentra l'enllaç actiu quan hi ha overflow */
  React.useEffect(() => {
    const inner = innerRef.current;
    if (!inner) return;
    const a = inner.querySelector('a.active');
    if (a && inner.scrollWidth > inner.clientWidth + 4) {
      inner.scrollTo({ left: a.offsetLeft - inner.clientWidth / 2 + a.offsetWidth / 2, behavior: 'smooth' });
    }
  }, [cur]);

  const go = (e, id) => {
    e.preventDefault();
    if (onNavigate) onNavigate(id);
    try { history.replaceState(null, '', '#' + id); } catch (err) {}
    setTimeout(() => {
      const el = document.getElementById(id);
      if (el) {
        const y = el.getBoundingClientRect().top + window.scrollY - 130;
        window.scrollTo({ top: y, behavior: 'smooth' });
      }
    }, onNavigate ? 120 : 0);
  };

  if (!items || !items.length) return null;

  return (
    <>
      <div className="esubnav-bar" ref={barRef}>
        <div className="wrap inner" ref={innerRef}>
          {items.map((it, i) => (
            <a key={it.id} href={'#' + it.id} className={cur === it.id ? 'active' : ''} onClick={(e) => go(e, it.id)}>
              <span className="n">{String(i + 1).padStart(2, '0')}</span>
              <span className="t">{it.label}</span>
            </a>
          ))}
        </div>
        <div className="fade l"></div>
        <div className="fade r"></div>
        <div className="more">›</div>
        <div className="progress" ref={progRef}></div>
      </div>
      <nav className="esubnav-rail" aria-label={label}>
        {items.map((it) => (
          <a key={it.id} href={'#' + it.id} className={cur === it.id ? 'active' : ''} onClick={(e) => go(e, it.id)}>
            <span className="lbl">{it.label}</span>
            <span className="node"></span>
          </a>
        ))}
      </nav>
    </>
  );
}

window.EsbartSubnav = EsbartSubnav;
