/* Tuo v3 — Animation Primitives: Counter, Typewriter, SectionTitle, CardTitle, Reveal */

const _FM = window.Motion || window.FramerMotion || {};
const { motion: fm, useInView, useMotionValue, useTransform, animate: fmAnimate, useReducedMotion, useScroll, AnimatePresence } = _FM;

// ── Animated Counter ──
// All Counters with `synced=true` start together when the FIRST synced one in any
// group enters view, and use the SAME duration so they end together.
function Counter({ value, suffix = '', prefix = '', duration = 2.4, decimals = 0, startFrom, delay = 0, synced = false, format }) {
  const ref = React.useRef(null);
  const inView = fm ? useInView(ref, { once: true, margin: '-100px' }) : true;
  const reduce = fm ? useReducedMotion() : false;
  const initial = startFrom !== undefined ? startFrom : 0;
  const mv = fm ? useMotionValue(initial) : null;

  // Default formatter: thousands separator + decimals
  const fmt = format || ((latest) => {
    const n = Number(latest);
    const abs = Math.abs(n);
    const fixed = abs.toFixed(decimals);
    const [intPart, decPart] = fixed.split('.');
    const withCommas = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    const sign = n < 0 ? '-' : '';
    const numStr = decPart ? `${withCommas}.${decPart}` : withCommas;
    return `${sign}${prefix}${numStr}${suffix}`;
  });

  const display = fm ? useTransform(mv, fmt) : null;

  React.useEffect(() => {
    if (!fm || reduce) return;
    if (inView) {
      // Hard synchronization: all synced counters in the same generation
      // wait for the master "go" signal so they truly start together.
      const start = () => fmAnimate(mv, value, { duration, ease: [0.16, 1, 0.3, 1], delay });
      if (synced) {
        if (window.__tuoCounterSyncDispatched) {
          start();
        } else {
          const handler = () => start();
          window.addEventListener('tuo-counter-go', handler, { once: true });
          // Schedule one global "go" after a beat so all visible counters subscribe first
          if (!window.__tuoCounterSyncScheduled) {
            window.__tuoCounterSyncScheduled = true;
            requestAnimationFrame(() => requestAnimationFrame(() => {
              window.__tuoCounterSyncDispatched = true;
              window.dispatchEvent(new Event('tuo-counter-go'));
            }));
          }
        }
      } else {
        start();
      }
    }
  }, [inView, value, duration, reduce, delay, synced]);

  if (!fm || reduce) return React.createElement('span', { ref }, fmt(value));
  return React.createElement(fm.span, { ref, style: { fontVariantNumeric: 'tabular-nums' } }, display);
}

// ── Typewriter ──
function Typewriter({ lines, delay = 0, speed = 35 }) {
  const [displayed, setDisplayed] = React.useState('');
  const [done, setDone] = React.useState(false);
  const reduce = fm ? useReducedMotion() : true;
  const fullText = lines.join('\n');

  React.useEffect(() => {
    if (reduce) { setDisplayed(fullText); setDone(true); return; }
    let i = 0;
    const start = setTimeout(() => {
      const interval = setInterval(() => {
        i++;
        setDisplayed(fullText.slice(0, i));
        if (i >= fullText.length) { clearInterval(interval); setDone(true); }
      }, speed);
      return () => clearInterval(interval);
    }, delay * 1000);
    return () => clearTimeout(start);
  }, [fullText, delay, speed, reduce]);

  const parts = displayed.split('\n');
  return React.createElement(React.Fragment, null,
    parts.map((line, i) => React.createElement(React.Fragment, { key: i }, line, i < parts.length - 1 && React.createElement('br'))),
    !done && fm && React.createElement(fm.span, {
      animate: { opacity: [1, 0, 1] }, transition: { duration: 0.8, repeat: Infinity },
      style: { display: 'inline-block', marginLeft: 2, color: '#3ecf8e' }
    }, '|')
  );
}

// ── SectionTitle — typewriter at 28ms + underline ──
function SectionTitle({ children }) {
  const ref = React.useRef(null);
  const inView = fm ? useInView(ref, { once: true, margin: '-80px' }) : true;
  const reduce = fm ? useReducedMotion() : true;
  const [typingDone, setTypingDone] = React.useState(false);
  const text = typeof children === 'string' ? children : '';

  React.useEffect(() => {
    if (!fm || reduce || !inView || !text) { setTypingDone(true); return; }
  }, [inView, reduce, text]);

  if (!fm || reduce || !text) return React.createElement('h2', { ref, className: 'section-title' },
    React.createElement('span', { className: 'section-title-text' }, children),
    React.createElement('div', { className: 'section-title-underline', style: { transform: 'scaleX(1)' } }));

  return React.createElement('h2', { ref, className: 'section-title' },
    React.createElement('span', { className: 'section-title-text' },
      inView ? React.createElement(SectionTypewriter, { text, speed: 28, onComplete: () => setTypingDone(true) }) : ''
    ),
    React.createElement(fm.div, {
      className: 'section-title-underline',
      initial: { scaleX: 0 },
      animate: typingDone ? { scaleX: 1 } : {},
      transition: { duration: 0.7, ease: [0.16, 1, 0.3, 1] }
    })
  );
}

// Internal typewriter for section titles
function SectionTypewriter({ text, speed = 28, onComplete }) {
  const [displayed, setDisplayed] = React.useState('');
  const [done, setDone] = React.useState(false);
  React.useEffect(() => {
    let i = 0;
    const interval = setInterval(() => {
      i++;
      setDisplayed(text.slice(0, i));
      if (i >= text.length) { clearInterval(interval); setDone(true); if (onComplete) onComplete(); }
    }, speed);
    return () => clearInterval(interval);
  }, [text, speed]);
  return React.createElement(React.Fragment, null,
    displayed,
    !done && fm && React.createElement(fm.span, {
      animate: { opacity: [1, 0, 1] }, transition: { duration: 0.8, repeat: Infinity },
      style: { display: 'inline-block', marginLeft: 2, color: '#3ecf8e' }
    }, '|')
  );
}

// ── CardTitle — letter stagger ──
function CardTitle({ children }) {
  const ref = React.useRef(null);
  const inView = fm ? useInView(ref, { once: true }) : true;
  const reduce = fm ? useReducedMotion() : true;
  if (!fm || reduce || typeof children !== 'string') return React.createElement('h3', { ref }, children);
  const letters = children.split('');
  return React.createElement('h3', { ref },
    letters.map((letter, i) => React.createElement(fm.span, {
      key: i,
      initial: { opacity: 0, y: 8 },
      animate: inView ? { opacity: 1, y: 0 } : {},
      transition: { duration: 0.4, delay: i * 0.02, ease: 'easeOut' },
      style: { display: 'inline-block', whiteSpace: letter === ' ' ? 'pre' : 'normal' }
    }, letter))
  );
}

// ── Reveal (scroll-triggered fade) ──
function Reveal({ children, delay = 0 }) {
  if (!fm) return React.createElement('div', null, children);
  const ref = React.useRef(null);
  const inView = useInView(ref, { once: true, margin: '-60px' });
  return React.createElement(fm.div, {
    ref,
    initial: { opacity: 0, y: 24 },
    animate: inView ? { opacity: 1, y: 0 } : {},
    transition: { duration: 0.7, delay, ease: [0.16, 1, 0.3, 1] }
  }, children);
}

// ── Orchestrated entrance wrapper ──
function Entrance({ children, delay = 0, y = 12 }) {
  if (!fm) return React.createElement('div', null, children);
  return React.createElement(fm.div, {
    initial: { opacity: 0, y },
    animate: { opacity: 1, y: 0 },
    transition: { duration: 0.6, delay, ease: [0.16, 1, 0.3, 1] }
  }, children);
}

Object.assign(window, { Counter, Typewriter, SectionTitle, CardTitle, Reveal, Entrance, _FM, fm, useInView, useMotionValue, useTransform, fmAnimate, useReducedMotion, useScroll, AnimatePresence });
