import { test } from "node:test";
import assert from "node:assert/strict";
import { curvaABC, dividirCusto, progressoDoMes } from "./equilibrio.ts";

/* ------------------------------------------------------------------ */
/* progressoDoMes                                                     */
/* ------------------------------------------------------------------ */

test("meio do mês, no ritmo: os números do termômetro fecham entre si", () => {
  const p = progressoDoMes({
    fixoMensal: 10000, cmAcumulada: 6000, receitaMes: 15000, diaAtual: 15, diasNoMes: 30,
  });
  assert.equal(p.progressoPct, 60);
  assert.equal(p.lucroAtual, -4000);
  assert.equal(p.bateu, false);
  assert.equal(p.diasRestantes, 15);
  assert.equal(p.cmNecessariaAteHoje, 5000);
  assert.equal(p.emRitmo, true);
  assert.equal(p.mcPctDoMes, 40);
  assert.equal(p.faturamentoParaEquilibrio, 25000);
  assert.equal(p.metaVendaAteHoje, 12500);
  /* Ritmo dobra o realizado do meio do mês. */
  assert.equal(p.previsaoCm, 12000);
  assert.equal(p.previsaoLucro, 2000);
  assert.equal(p.previsaoVenda, 30000);
});

test("primeiro dia sem venda: devendo o fixo inteiro, sem previsão inventada", () => {
  const p = progressoDoMes({
    fixoMensal: 9469.57, cmAcumulada: 0, receitaMes: 0, diaAtual: 1, diasNoMes: 31,
  });
  assert.equal(p.progressoPct, 0);
  assert.equal(p.lucroAtual, -9469.57);
  assert.equal(p.faturamentoParaEquilibrio, null);
  assert.equal(p.metaVendaAteHoje, null);
  assert.equal(p.previsaoCm, 0);
  assert.equal(p.previsaoLucro, -9469.57);
  /* A cota do primeiro dia já existe — e zero acumulado fica atrás dela. */
  assert.equal(p.cmNecessariaAteHoje, 305.47);
  assert.equal(p.emRitmo, false);
});

test("último dia do mês: previsão é o realizado, resta zero dia", () => {
  const p = progressoDoMes({
    fixoMensal: 10000, cmAcumulada: 11000, receitaMes: 30000, diaAtual: 31, diasNoMes: 31,
  });
  assert.equal(p.diasRestantes, 0);
  assert.equal(p.previsaoCm, 11000);
  assert.equal(p.previsaoVenda, 30000);
  assert.equal(p.bateu, true);
  assert.equal(p.progressoPct, 110);
  assert.equal(p.lucroAtual, 1000);
  assert.equal(p.cmNecessariaAteHoje, 10000);
});

test("sem custo fixo cadastrado: nada de dividir por zero", () => {
  const p = progressoDoMes({
    fixoMensal: 0, cmAcumulada: 5000, receitaMes: 10000, diaAtual: 10, diasNoMes: 30,
  });
  assert.equal(p.progressoPct, 0);
  assert.equal(p.bateu, false);
  assert.equal(p.faturamentoParaEquilibrio, null);
  assert.equal(p.lucroAtual, 5000);
});

test("contribuição negativa: o termômetro conta a verdade, não zera", () => {
  /* Vendeu abaixo da matéria-prima: o mês está PIOR do que sem vender. */
  const p = progressoDoMes({
    fixoMensal: 10000, cmAcumulada: -500, receitaMes: 2000, diaAtual: 10, diasNoMes: 30,
  });
  assert.equal(p.progressoPct, -5);
  assert.equal(p.lucroAtual, -10500);
  assert.equal(p.faturamentoParaEquilibrio, null);
  assert.equal(p.emRitmo, false);
});

test("meta do comercial: prorata diária e ritmo pela RECEITA, não pela contribuição", () => {
  const p = progressoDoMes({
    fixoMensal: 10000, cmAcumulada: 6000, receitaMes: 15000, diaAtual: 15, diasNoMes: 30,
    metaDeVendas: 40000,
  });
  assert.equal(p.metaDoComercial, 40000);
  assert.equal(p.metaDoComercialAteHoje, 20000);
  /* Vendeu 15.000 com cota de 20.000: atrás da meta da gestão, mesmo que o
     equilíbrio esteja no ritmo. As duas réguas convivem. */
  assert.equal(p.metaDoComercialEmRitmo, false);
  assert.equal(p.emRitmo, true);
});

test("sem meta definida, os campos da gestão ficam nulos — vale só o equilíbrio", () => {
  const p = progressoDoMes({
    fixoMensal: 10000, cmAcumulada: 6000, receitaMes: 15000, diaAtual: 15, diasNoMes: 30,
  });
  assert.equal(p.metaDoComercial, null);
  assert.equal(p.metaDoComercialAteHoje, null);
  assert.equal(p.metaDoComercialEmRitmo, null);
});

test("dia fora da régua é acomodado sem explodir", () => {
  const p = progressoDoMes({
    fixoMensal: 100, cmAcumulada: 50, receitaMes: 100, diaAtual: 99, diasNoMes: 30,
  });
  assert.equal(p.diasRestantes, 0);
  assert.equal(p.cmNecessariaAteHoje, 100);
});

/* ------------------------------------------------------------------ */
/* curvaABC                                                           */
/* ------------------------------------------------------------------ */

test("curva ABC: quem cruza a régua dos 80% ainda fecha o bloco A", () => {
  const r = curvaABC([
    { nome: "b", receita: 100, cm: 30 },
    { nome: "a", receita: 100, cm: 60 },
    { nome: "c", receita: 100, cm: 8 },
    { nome: "d", receita: 100, cm: 2 },
  ]);
  assert.deepEqual(r.map((i) => [i.nome, i.classe]), [
    ["a", "A"], /* 60% acumulado, começa em 0 */
    ["b", "A"], /* começa em 60 < 80: cruza a régua e fecha o bloco */
    ["c", "B"], /* começa em 90 < 95 */
    ["d", "C"], /* começa em 98 */
  ]);
  assert.equal(r[0].participacaoPct, 60);
});

test("curva ABC: contribuição zero ou negativa é C — mora de favor", () => {
  const r = curvaABC([
    { nome: "bom", receita: 10, cm: 100 },
    { nome: "zerado", receita: 10, cm: 0 },
    { nome: "prejuizo", receita: 10, cm: -40 },
  ]);
  assert.deepEqual(r.map((i) => [i.nome, i.classe]), [
    ["bom", "A"], ["zerado", "C"], ["prejuizo", "C"],
  ]);
});

test("curva ABC sem contribuição positiva nenhuma: todo mundo C", () => {
  const r = curvaABC([
    { nome: "x", receita: 10, cm: 0 },
    { nome: "y", receita: 10, cm: -5 },
  ]);
  assert.ok(r.every((i) => i.classe === "C"));
});

/* ------------------------------------------------------------------ */
/* dividirCusto                                                       */
/* ------------------------------------------------------------------ */

test("divide o custo congelado na proporção da ficha, fechando no total", () => {
  /* Caneca: ficha com 10,43 de materiais e 1,38 de processos. */
  const d = dividirCusto(11.81, 10.43, 1.38);
  assert.equal(Math.round((d.materiais + d.processos) * 100) / 100, 11.81);
  assert.equal(d.materiais, 10.43);
  assert.equal(d.processos, 1.38);
});

test("custo congelado diferente da ficha atual: a proporção vale, não o valor", () => {
  /* Congelou 20 quando a ficha atual soma 10+10: metade é matéria-prima. */
  const d = dividirCusto(20, 10, 10);
  assert.equal(d.materiais, 10);
  assert.equal(d.processos, 10);
});

test("sem ficha, tudo é matéria-prima — o lado conservador", () => {
  const d = dividirCusto(50, 0, 0);
  assert.equal(d.materiais, 50);
  assert.equal(d.processos, 0);
});

test("ficha só de processos: o custo inteiro é recuperação de fixo", () => {
  const d = dividirCusto(30, 0, 12);
  assert.equal(d.materiais, 0);
  assert.equal(d.processos, 30);
});

test("custo zero não inventa divisão", () => {
  const d = dividirCusto(0, 10, 10);
  assert.deepEqual(d, { materiais: 0, processos: 0 });
});
