// OMNIX — Animaciones avanzadas para la sub-sección Arquitectura
// TypeStream · MagneticHover · LiveTicker · SpringNumber · GraphPulse

// ── useTicker ────────────────────────────────────────────────
// Emite un tick cada N ms. Útil para logs en vivo y streams.
const useTicker = (interval = 1000, active = true) => {
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    if (!active) return;
    const id = setInterval(() => setTick((t) => t + 1), interval);
    return () => clearInterval(id);
  }, [interval, active]);
  return tick;
};

// ── useTypeStream ────────────────────────────────────────────
// Efecto máquina de escribir para logs técnicos.
const useTypeStream = (lines, charDelay = 12, lineDelay = 300, active = true) => {
  const [visibleLines, setVisibleLines] = React.useState([]);
  React.useEffect(() => {
    if (!active) return;
    let cancelled = false;
    let out = [];
    const play = async () => {
      for (let li = 0; li < lines.length; li++) {
        if (cancelled) return;
        const line = lines[li];
        let acc = '';
        for (let ci = 0; ci < line.length; ci++) {
          if (cancelled) return;
          acc += line[ci];
          out = [...out.slice(0, li), acc];
          setVisibleLines([...out]);
          await new Promise((r) => setTimeout(r, charDelay));
        }
        await new Promise((r) => setTimeout(r, lineDelay));
      }
    };
    play();
    return () => { cancelled = true; };
  }, [lines.join('|'), charDelay, lineDelay, active]);
  return visibleLines;
};

// ── <MagneticHover> ──────────────────────────────────────────
// Card que se desplaza sutilmente hacia el cursor (max 8px).
const MagneticHover = ({ children, strength = 8, style = {}, ...rest }) => {
  const ref = React.useRef(null);
  const [t, setT] = React.useState({ x: 0, y: 0 });
  return (
    <div
      ref={ref}
      onMouseMove={(e) => {
        const r = ref.current.getBoundingClientRect();
        const cx = r.left + r.width / 2;
        const cy = r.top + r.height / 2;
        const dx = (e.clientX - cx) / (r.width / 2);
        const dy = (e.clientY - cy) / (r.height / 2);
        setT({ x: dx * strength, y: dy * strength });
      }}
      onMouseLeave={() => setT({ x: 0, y: 0 })}
      style={{
        transform: `translate(${t.x}px, ${t.y}px)`,
        transition: t.x === 0 && t.y === 0 ? 'transform 500ms cubic-bezier(0.2,0.7,0.2,1)' : 'transform 120ms cubic-bezier(0.2,0.7,0.2,1)',
        ...style,
      }}
      {...rest}
    >
      {children}
    </div>
  );
};

// ── <SpringNumber> ───────────────────────────────────────────
// Como CountUp pero se actualiza cuando la prop `to` cambia (para valores live).
const SpringNumber = ({ to, prefix = '', suffix = '', decimals = 0, duration = 700, style = {} }) => {
  const [value, setValue] = React.useState(to);
  const prevRef = React.useRef(to);
  React.useEffect(() => {
    const from = prevRef.current;
    prevRef.current = to;
    if (from === to) return;
    const start = performance.now();
    let raf;
    const tick = (now) => {
      const t = Math.min(1, (now - start) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      setValue(from + (to - from) * eased);
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [to, duration]);
  const fmt = value.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
  return <span style={{ fontVariantNumeric: 'tabular-nums', ...style }}>{prefix}{fmt}{suffix}</span>;
};

// ── <SegmentedTabs> ──────────────────────────────────────────
// Tabs animados horizontales con "pill" que se desliza.
const SegmentedTabs = ({ tabs, active, onChange, style = {} }) => {
  const refs = React.useRef([]);
  const [pill, setPill] = React.useState({ x: 0, w: 0 });
  React.useEffect(() => {
    const el = refs.current[active];
    if (el) {
      const r = el.getBoundingClientRect();
      const pr = el.parentElement.getBoundingClientRect();
      setPill({ x: r.left - pr.left, w: r.width });
    }
  }, [active, tabs.length]);
  return (
    <div style={{
      display: 'inline-flex', gap: 0, position: 'relative', padding: 4,
      background: '#F2F5F9', border: '1px solid #E4EBF3', borderRadius: 2, ...style,
    }}>
      <div style={{
        position: 'absolute', top: 4, bottom: 4,
        left: pill.x, width: pill.w, background: '#000',
        transition: 'left 380ms cubic-bezier(0.5,1.6,0.4,1), width 380ms cubic-bezier(0.5,1.6,0.4,1)',
        zIndex: 0,
      }}/>
      {tabs.map((t, i) => (
        <button
          key={t.k || i}
          ref={(el) => (refs.current[i] = el)}
          onClick={() => onChange(i)}
          style={{
            position: 'relative', zIndex: 1,
            padding: '10px 20px', border: 'none', background: 'transparent',
            fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.18em',
            textTransform: 'uppercase', cursor: 'pointer',
            color: active === i ? '#FFF' : '#52557A',
            transition: 'color 220ms',
            whiteSpace: 'nowrap',
          }}>
          {t.l || t}
        </button>
      ))}
    </div>
  );
};

// ── <FlowPath> ───────────────────────────────────────────────
// Path SVG con partícula que fluye — variante con más control que el original.
const FlowPath = ({ d, stroke = '#F4024C', strokeWidth = 1, particleColor, particleSize = 3, duration = 3, dashed = true, pulseWidth = false }) => {
  const uid = React.useId ? React.useId() : `fp-${Math.random().toString(36).slice(2)}`;
  return (
    <>
      <path id={uid} d={d} fill="none" stroke={stroke} strokeWidth={strokeWidth} strokeDasharray={dashed ? '4 6' : '0'} className={dashed ? 'omnix-flow-dash' : ''}/>
      {particleColor && (
        <circle r={particleSize} fill={particleColor}>
          <animateMotion dur={`${duration}s`} repeatCount="indefinite" rotate="auto">
            <mpath href={`#${uid}`}/>
          </animateMotion>
          {pulseWidth && <animate attributeName="r" values={`${particleSize};${particleSize*1.6};${particleSize}`} dur="1.2s" repeatCount="indefinite"/>}
        </circle>
      )}
    </>
  );
};

// ── <RadialProgress> ─────────────────────────────────────────
// Anillo de progreso animado con label central.
const RadialProgress = ({ value, max = 100, size = 100, stroke = 4, color = '#F4024C', label, sublabel }) => {
  const { ref, visible } = useReveal({ threshold: 0.3 });
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const pct = Math.min(1, value / max);
  const offset = visible ? c * (1 - pct) : c;
  return (
    <div ref={ref} style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="#E4EBF3" strokeWidth={stroke}/>
        <circle
          cx={size/2} cy={size/2} r={r} fill="none"
          stroke={color} strokeWidth={stroke} strokeLinecap="butt"
          strokeDasharray={c} strokeDashoffset={offset}
          style={{ transition: 'stroke-dashoffset 1200ms cubic-bezier(0.2,0.7,0.2,1)' }}
        />
      </svg>
      <div style={{
        position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center', gap: 2,
      }}>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: size/4, letterSpacing: '-0.02em', color: '#000', fontVariantNumeric: 'tabular-nums' }}>
          <CountUp to={value} suffix={max === 100 ? '%' : ''}/>
        </div>
        {sublabel && <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '0.14em', color: '#96A3B5', textTransform: 'uppercase' }}>{sublabel}</div>}
      </div>
    </div>
  );
};

// ── <SlideIn> ─────────────────────────────────────────────
// Como Reveal pero con dirección configurable (left/right/up/down).
const SlideIn = ({ children, direction = 'up', delay = 0, distance = 32, duration = 620, style = {}, ...rest }) => {
  const { ref, visible } = useReveal();
  const transforms = {
    up:    `translateY(${distance}px)`,
    down:  `translateY(-${distance}px)`,
    left:  `translateX(${distance}px)`,
    right: `translateX(-${distance}px)`,
  };
  return (
    <div ref={ref} style={{
      opacity: visible ? 1 : 0,
      transform: visible ? 'translate(0,0)' : transforms[direction],
      transition: `opacity ${duration}ms cubic-bezier(0.2,0.7,0.2,1) ${delay}ms, transform ${duration}ms cubic-bezier(0.2,0.7,0.2,1) ${delay}ms`,
      willChange: 'opacity, transform',
      ...style,
    }} {...rest}>{children}</div>
  );
};

// Inject extra keyframes
if (typeof document !== 'undefined' && !document.getElementById('omnix-adv-anim-keyframes')) {
  const s = document.createElement('style');
  s.id = 'omnix-adv-anim-keyframes';
  s.textContent = `
    @keyframes omnix-pulse-ring { 0% { transform: scale(0.95); opacity: 0.6; } 70% { transform: scale(1.6); opacity: 0; } 100% { transform: scale(1.6); opacity: 0; } }
    @keyframes omnix-flicker { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
    @keyframes omnix-orbit { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
    .omnix-pulse-ring::before {
      content: ''; position: absolute; inset: 0;
      border: 1.5px solid currentColor; border-radius: inherit;
      animation: omnix-pulse-ring 2s cubic-bezier(0.2,0.7,0.2,1) infinite;
      pointer-events: none;
    }
    .omnix-flicker { animation: omnix-flicker 1.6s ease-in-out infinite; }
    .omnix-caret::after { content: '▊'; margin-left: 2px; animation: omnix-flicker 0.9s steps(2) infinite; color: #F4024C; }
  `;
  document.head.appendChild(s);
}

Object.assign(window, {
  useTicker, useTypeStream,
  MagneticHover, SpringNumber, SegmentedTabs, FlowPath, RadialProgress, SlideIn,
});
