// Tempo — animations primitives

function useCountUp(target, { duration = 900, decimals = 0, ease = (t) => 1 - Math.pow(1 - t, 3) } = {}) {
  const [v, setV] = React.useState(0);
  const ref = React.useRef({ start: 0, from: 0 });
  React.useEffect(() => {
    ref.current = { start: performance.now(), from: v };
    let raf;
    const tick = (now) => {
      const t = Math.min(1, (now - ref.current.start) / duration);
      const e = ease(t);
      setV(ref.current.from + (target - ref.current.from) * e);
      if (t < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [target]);
  if (decimals === 0) return Math.round(v);
  return parseFloat(v.toFixed(decimals));
}

function AnimatedMoney({ value, size = 28, weight = 600, color = 'inherit', sign = true }) {
  const v = useCountUp(value, { duration: 1000 });
  const formatted = Math.abs(v).toLocaleString('fr-FR');
  const prefix = sign ? (v < 0 ? '−$' : (v > 0 ? '+$' : '$')) : '$';
  return (
    <span className="num" style={{ fontSize: size, fontWeight: weight, color, letterSpacing: '-.018em', lineHeight: 1.05 }}>
      {prefix}{formatted}
    </span>
  );
}

function AnimatedNumber({ value, decimals = 0, suffix = '', size = 28, weight = 600, color = 'inherit' }) {
  const v = useCountUp(value, { duration: 1000, decimals });
  const display = decimals === 0 ? v : v.toFixed(decimals).replace('.', ',');
  return (
    <span className="num" style={{ fontSize: size, fontWeight: weight, color, letterSpacing: '-.018em', lineHeight: 1.05 }}>
      {display}{suffix}
    </span>
  );
}

function useLiveTime() {
  const [t, setT] = React.useState(() => new Date());
  React.useEffect(() => {
    const id = setInterval(() => setT(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  return t;
}

Object.assign(window, { useCountUp, AnimatedMoney, AnimatedNumber, useLiveTime });
