// Animation primitives for Roberto Grécia site — institutional, refined
// Uses IntersectionObserver + CSS transitions. No external libraries.

const { useEffect, useRef, useState } = React;

/**
 * useReveal — adds `data-revealed="true"` to an element when it enters viewport.
 * Pair with CSS that transitions from a hidden state to a revealed state.
 */
function useReveal(options = {}) {
  const ref = useRef(null);
  const { threshold = 0.15, rootMargin = '0px 0px -60px 0px', once = true } = options;

  useEffect(() => {
    const el = ref.current;
    if (!el) return;

    // Respect reduced motion
    if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      el.setAttribute('data-revealed', 'true');
      return;
    }

    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            el.setAttribute('data-revealed', 'true');
            if (once) io.unobserve(el);
          } else if (!once) {
            el.setAttribute('data-revealed', 'false');
          }
        });
      },
      { threshold, rootMargin }
    );

    io.observe(el);
    return () => io.disconnect();
  }, []);

  return ref;
}

/**
 * Reveal — wrapper component that animates its children in.
 * Variants: 'up' (default), 'down', 'left', 'right', 'fade', 'scale'.
 * `delay` in ms.
 */
function Reveal({ children, as = 'div', variant = 'up', delay = 0, className = '', style = {}, ...rest }) {
  const ref = useReveal();
  const Tag = as;
  return (
    <Tag
      ref={ref}
      className={`rg-reveal rg-reveal--${variant} ${className}`}
      style={{ ...style, transitionDelay: `${delay}ms` }}
      {...rest}
    >
      {children}
    </Tag>
  );
}

/**
 * RevealWords — splits a string of text into words and reveals them in sequence.
 * Preserves spaces. Use for headlines.
 */
function RevealWords({ text, delay = 0, stagger = 55, className = '', style = {}, wordStyle = {} }) {
  const ref = useRef(null);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;

    if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      el.setAttribute('data-revealed', 'true');
      return;
    }

    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            el.setAttribute('data-revealed', 'true');
            io.unobserve(el);
          }
        });
      },
      { threshold: 0.2, rootMargin: '0px 0px -40px 0px' }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);

  // Accept either string or array of segments (to preserve inline style like italic color)
  const segments = Array.isArray(text) ? text : [{ text }];

  let wordIdx = 0;
  const out = [];
  segments.forEach((seg, segIdx) => {
    const words = seg.text.split(/(\s+)/);
    words.forEach((w, i) => {
      if (/^\s+$/.test(w)) {
        out.push(<span key={`s-${segIdx}-${i}`}>{w}</span>);
      } else if (w.length) {
        const d = delay + wordIdx * stagger;
        out.push(
          <span key={`w-${segIdx}-${i}`}
                className="rg-word"
                style={{ ...(seg.style || {}), transitionDelay: `${d}ms` }}>
            {w}
          </span>
        );
        wordIdx++;
      }
    });
    // optional separator between segments (like <br/>)
    if (seg.after === 'br') out.push(<br key={`br-${segIdx}`} />);
  });

  return (
    <span ref={ref} className={`rg-reveal-words ${className}`} style={style}>
      {out}
    </span>
  );
}

/**
 * DrawRule — horizontal rule that draws itself left-to-right on reveal.
 */
function DrawRule({ color = 'currentColor', width = '60px', height = 2, delay = 0, style = {} }) {
  const ref = useReveal();
  return (
    <div
      ref={ref}
      className="rg-draw-rule"
      style={{
        width,
        height,
        background: color,
        transitionDelay: `${delay}ms`,
        ...style,
      }}
    />
  );
}

/**
 * CountUp — animates a number from 0 to target once it enters viewport.
 */
function CountUp({ to, suffix = '', prefix = '', duration = 1400, className = '', style = {} }) {
  const ref = useRef(null);
  const [val, setVal] = useState(0);
  const started = useRef(false);

  useEffect(() => {
    const el = ref.current;
    if (!el) return;

    const run = () => {
      const start = performance.now();
      const step = (now) => {
        const t = Math.min(1, (now - start) / duration);
        const eased = 1 - Math.pow(1 - t, 3); // easeOutCubic
        setVal(Math.round(eased * to));
        if (t < 1) requestAnimationFrame(step);
      };
      requestAnimationFrame(step);
    };

    if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      setVal(to);
      return;
    }

    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting && !started.current) {
          started.current = true;
          run();
          io.unobserve(el);
        }
      });
    }, { threshold: 0.4 });
    io.observe(el);
    return () => io.disconnect();
  }, [to, duration]);

  return <span ref={ref} className={className} style={style}>{prefix}{val}{suffix}</span>;
}

/**
 * MeanderPattern — subtle SVG greek-key background. Very low opacity.
 * Meant to sit behind hero content as a watermark.
 */
function MeanderPattern({ color = '#B8892B', opacity = 0.06, style = {} }) {
  // Simple greek-key motif that tiles horizontally
  const pattern = (
    <svg width="0" height="0" style={{ position: 'absolute' }} aria-hidden="true">
      <defs>
        <pattern id="rg-meander" x="0" y="0" width="80" height="40" patternUnits="userSpaceOnUse">
          <path d="M0,30 L20,30 L20,10 L60,10 L60,30 L40,30 L40,20 L50,20"
                fill="none" stroke={color} strokeWidth="1.5" />
        </pattern>
      </defs>
    </svg>
  );
  return (
    <>
      {pattern}
      <div className="rg-meander-bg"
           style={{
             position: 'absolute', inset: 0,
             backgroundImage: `url("data:image/svg+xml;utf8,${encodeURIComponent(
               `<svg xmlns='http://www.w3.org/2000/svg' width='80' height='40'>
                  <path d='M0 30 L20 30 L20 10 L60 10 L60 30 L40 30 L40 20 L50 20' fill='none' stroke='${color}' stroke-width='1.2'/>
                </svg>`
             )}")`,
             backgroundRepeat: 'repeat',
             opacity,
             pointerEvents: 'none',
             ...style,
           }} />
    </>
  );
}

// Expose globals so other babel scripts can use them
Object.assign(window, { useReveal, Reveal, RevealWords, DrawRule, CountUp, MeanderPattern });
