/**
 * Conta de dinheiro em centavos inteiros.
 *
 * Nota fiscal não perdoa um centavo: a SEFAZ confere que a soma dos itens,
 * descontos e frete fecha com o total (rejeições 610, 629 e companhia). Somar
 * reais em ponto flutuante dá 0,30000000000000004; somar centavos inteiros dá
 * 30. Tudo que entra na nota passa por aqui.
 */

export function centavos(valor: number | string | null | undefined): number {
  const n = typeof valor === "string" ? Number(valor.replace(",", ".")) : Number(valor);
  if (!Number.isFinite(n)) return 0;
  return Math.round(n * 100);
}

export function reais(emCentavos: number): number {
  return Math.round(emCentavos) / 100;
}

/**
 * Divide `total` (centavos) em partes proporcionais aos `pesos`, sem sobrar nem
 * faltar centavo: o resto vai para quem teve a maior fração perdida no
 * arredondamento (maior resto). Pesos todos zero dividem por igual.
 */
export function ratear(total: number, pesos: number[]): number[] {
  const n = pesos.length;
  if (n === 0) return [];
  const totalInteiro = Math.round(total);
  if (totalInteiro === 0) return pesos.map(() => 0);

  const positivos = pesos.map((p) => (Number.isFinite(p) && p > 0 ? p : 0));
  const soma = positivos.reduce((acc, p) => acc + p, 0);
  const base = soma > 0 ? positivos : pesos.map(() => 1);
  const somaBase = soma > 0 ? soma : n;

  const sinal = totalInteiro < 0 ? -1 : 1;
  const absoluto = Math.abs(totalInteiro);
  const brutos = base.map((p) => (absoluto * p) / somaBase);
  const partes = brutos.map((b) => Math.floor(b));
  let restante = absoluto - partes.reduce((acc, p) => acc + p, 0);

  const ordem = brutos
    .map((b, i) => ({ i, fracao: b - Math.floor(b), peso: base[i] }))
    .sort((a, b) => b.fracao - a.fracao || b.peso - a.peso || a.i - b.i);
  for (let k = 0; restante > 0 && k < ordem.length; k += 1, restante -= 1) {
    partes[ordem[k].i] += 1;
  }
  return partes.map((p) => p * sinal);
}

/** Arredonda para `casas` decimais sem o erro clássico do 1.005. */
export function arredondar(valor: number, casas: number): number {
  if (!Number.isFinite(valor)) return 0;
  const fator = 10 ** casas;
  return Math.round((valor + Number.EPSILON) * fator) / fator;
}

export function formatarReais(valor: number): string {
  return new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(valor || 0);
}
