"use client";

import { useEffect, useRef, useState } from "react";

/**
 * Anima um numero ate o novo valor.
 *
 * Trocar de golpe parece erro de renderizacao; a subida mostra que entrou
 * movimento. Desliga para quem pediu menos animacao no sistema.
 *
 * Mora em lib porque a vitrine de lojas e a landing usam o mesmo contador.
 */
export function useNumeroAnimado(alvo: number, duracao = 900) {
  const [exibido, setExibido] = useState(alvo);
  const [reduzir, setReduzir] = useState(false);
  const quadroRef = useRef<number | null>(null);
  const deRef = useRef(alvo);

  /* Preferencia do sistema e um sinal externo: acompanha por listener em vez
     de ler uma vez, para quem muda a opcao com a pagina aberta. */
  useEffect(() => {
    const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
    const aplicar = () => setReduzir(mq.matches);
    aplicar();
    mq.addEventListener("change", aplicar);
    return () => mq.removeEventListener("change", aplicar);
  }, []);

  useEffect(() => {
    if (reduzir) {
      deRef.current = alvo;
      return;
    }

    const de = deRef.current;
    if (de === alvo) return;

    const inicio = performance.now();
    const passo = (agora: number) => {
      const t = Math.min(1, (agora - inicio) / duracao);
      const suave = 1 - Math.pow(1 - t, 3);
      setExibido(de + (alvo - de) * suave);
      if (t < 1) {
        quadroRef.current = requestAnimationFrame(passo);
      } else {
        deRef.current = alvo;
      }
    };
    quadroRef.current = requestAnimationFrame(passo);

    return () => {
      if (quadroRef.current) cancelAnimationFrame(quadroRef.current);
      deRef.current = alvo;
    };
  }, [alvo, duracao, reduzir]);

  /* Com menos animacao o valor sai direto do alvo, sem passar por estado. */
  return reduzir ? alvo : exibido;
}
