// Animation utilities
const { useEffect: useAnimEffect, useRef: useAnimRef, useState: useAnimState } = React;

// Reveal: fade up on scroll into view
function Reveal({ children, delay = 0, className = '', as: As = 'div', threshold = 0.18, once = true, style = {} }){
  const ref = useAnimRef(null);
  const [shown, setShown] = useAnimState(false);
  useAnimEffect(() => {
    const el = ref.current; if(!el) return;
    const obs = new IntersectionObserver(([e]) => {
      if(e.isIntersecting){ setShown(true); if(once) obs.disconnect(); }
      else if(!once) setShown(false);
    }, { threshold });
    obs.observe(el);
    return () => obs.disconnect();
  }, []);
  const dCls = delay ? ` d${Math.min(4, Math.max(1, Math.round(delay)))}` : '';
  return (
    <As ref={ref} className={`reveal${dCls} ${shown?'in':''} ${className}`} style={style}>
      {children}
    </As>
  );
}

// SplitText: char-by-char rise
function SplitText({ text, className = '', tag: Tag = 'h1', delay = 0, threshold = 0.2 }){
  const ref = useAnimRef(null);
  const [shown, setShown] = useAnimState(false);
  useAnimEffect(() => {
    const el = ref.current; if(!el) return;
    const obs = new IntersectionObserver(([e]) => {
      if(e.isIntersecting){ setShown(true); obs.disconnect(); }
    }, { threshold });
    obs.observe(el);
    return () => obs.disconnect();
  }, []);

  // Split by characters, preserving newlines as <br/>
  const lines = String(text).split('\n');

  return (
    <Tag ref={ref} className={`split ${shown?'in':''} ${className}`}>
      {lines.map((line, li) => (
        <React.Fragment key={li}>
          <span className="split-word">
            {[...line].map((ch, ci) => {
              const totalIndex = li*1000 + ci;
              return (
                <span key={ci} className="split-char" style={{
                  transitionDelay: `${delay + totalIndex * 28}ms`
                }}>{ch === ' ' ? '\u00A0' : ch}</span>
              );
            })}
          </span>
          {li < lines.length - 1 && <br/>}
        </React.Fragment>
      ))}
    </Tag>
  );
}

// HoverFigure: zoom + caption
function HoverFigure({ src, alt, caption, no, aspect = '4/5', style = {} }){
  return (
    <figure className="figure" style={{ aspectRatio: aspect, margin:0, ...style }}>
      <img src={src} alt={alt || caption} loading="lazy" />
      {(caption || no) && (
        <figcaption className="caption">
          {caption && <span>{caption}</span>}
          {no && <span className="no">{no}</span>}
        </figcaption>
      )}
    </figure>
  );
}

// HeroSlideshow: crossfading figure (reuses .figure frame)
function HeroSlideshow({ images, aspect = '4/5', interval = 5000, style = {} }){
  const [i, setI] = useAnimState(0);
  useAnimEffect(() => {
    if(images.length <= 1) return;
    const t = setInterval(() => setI(p => (p+1) % images.length), interval);
    return () => clearInterval(t);
  }, [images.length, interval]);
  const cur = images[i] || {};
  return (
    <figure className="figure slideshow" style={{ aspectRatio: aspect, margin:0, ...style }}>
      {images.map((im, n) => (
        <img key={n} src={im.src} alt={im.caption || ''}
             loading={n === 0 ? 'eager' : 'lazy'}
             className={n === i ? 'active' : ''} />
      ))}
      {(cur.caption || cur.no) && (
        <figcaption className="caption">
          {cur.caption && <span>{cur.caption}</span>}
          {cur.no && <span className="no">{cur.no}</span>}
        </figcaption>
      )}
    </figure>
  );
}

// EditorialBand: marquee/ticker
function EditorialBand({ items }){
  const all = [...items, ...items, ...items];
  return (
    <div className="editorial-band">
      <div className="editorial-band-track">
        {all.map((m, i) => (
          <span key={i}>{m} <span className="star">✻</span></span>
        ))}
      </div>
    </div>
  );
}

// Parallax wrapper — translateY based on scroll
function Parallax({ children, speed = 0.2, className = '', style = {} }){
  const ref = useAnimRef(null);
  useAnimEffect(() => {
    const el = ref.current; if(!el) return;
    let ticking = false;
    const onScroll = () => {
      if(ticking) return;
      ticking = true;
      requestAnimationFrame(() => {
        const r = el.getBoundingClientRect();
        const cy = window.innerHeight / 2;
        const offset = (r.top + r.height/2 - cy) * speed;
        el.style.transform = `translate3d(0, ${-offset}px, 0)`;
        ticking = false;
      });
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, [speed]);
  return <div ref={ref} className={className} style={style}>{children}</div>;
}

Object.assign(window, { Reveal, SplitText, HoverFigure, HeroSlideshow, EditorialBand, Parallax });
