import { test } from "node:test";
import assert from "node:assert/strict";
import {
  capacidadeDaFila,
  compararPrevistoComReal,
  diasUteisNoMes,
  ratearPeloPrevisto,
  somarDiasUteis,
  type LinhaDeTempo,
} from "./tempo-de-producao.ts";

const SEG_A_SEX = [1, 2, 3, 4, 5];

function linha(parte: Partial<LinhaDeTempo> & Pick<LinhaDeTempo, "productId" | "orderId" | "previstoMin" | "realMin">): LinhaDeTempo {
  return { nome: parte.productId, itemId: `${parte.orderId}-i`, fonte: "item", ...parte };
}

test("previsto × real: banner subestimado, caneca certa, chaveiro com poucos dados", () => {
  const r = compararPrevistoComReal([
    linha({ productId: "banner", orderId: "p1", previstoMin: 60, realMin: 110 }),
    linha({ productId: "banner", orderId: "p2", previstoMin: 30, realMin: 60 }),
    linha({ productId: "banner", orderId: "p3", previstoMin: 90, realMin: 150, fonte: "cronometro", aproximado: true }),
    linha({ productId: "caneca", orderId: "p4", previstoMin: 40, realMin: 42 }),
    linha({ productId: "caneca", orderId: "p5", previstoMin: 40, realMin: 38 }),
    linha({ productId: "caneca", orderId: "p6", previstoMin: 40, realMin: 45 }),
    linha({ productId: "chaveiro", orderId: "p7", previstoMin: 10, realMin: 30 }),
  ]);

  const [banner, caneca, chaveiro] = r;
  assert.equal(banner.productId, "banner");
  assert.equal(banner.pedidos, 3);
  assert.equal(banner.previstoMin, 180);
  assert.equal(banner.realMin, 320);
  assert.equal(banner.razao, 1.78);
  assert.equal(banner.situacao, "subestimado");
  assert.equal(banner.sugestaoFator, 1.8);
  assert.equal(banner.fonte, "misto");
  assert.equal(banner.aproximados, 1);

  assert.equal(caneca.situacao, "ok");
  assert.equal(caneca.sugestaoFator, null);
  assert.equal(caneca.razao, 1.04);

  /* Um pedido só, mesmo com 3× de diferença, não muda ficha de ninguém. */
  assert.equal(chaveiro.situacao, "poucos_dados");
  assert.equal(chaveiro.sugestaoFator, null);
});

test("previsto × real: superestimado sugere fator abaixo de 1", () => {
  const r = compararPrevistoComReal([
    linha({ productId: "flyer", orderId: "a", previstoMin: 100, realMin: 40 }),
    linha({ productId: "flyer", orderId: "b", previstoMin: 100, realMin: 45 }),
    linha({ productId: "flyer", orderId: "c", previstoMin: 100, realMin: 35 }),
  ]);
  assert.equal(r[0].situacao, "superestimado");
  assert.equal(r[0].sugestaoFator, 0.4);
});

test("previsto × real: linha sem previsto ou sem real não entra", () => {
  const r = compararPrevistoComReal([
    linha({ productId: "x", orderId: "a", previstoMin: 0, realMin: 40 }),
    linha({ productId: "x", orderId: "b", previstoMin: 30, realMin: 0 }),
  ]);
  assert.deepEqual(r, []);
});

test("rateio pelo previsto, e igual quando ninguém tem previsto", () => {
  assert.deepEqual(ratearPeloPrevisto(120, [{ id: "a", previsto: 30 }, { id: "b", previsto: 90 }]), { a: 30, b: 90 });
  assert.deepEqual(ratearPeloPrevisto(90, [{ id: "a", previsto: 0 }, { id: "b", previsto: 0 }, { id: "c", previsto: 0 }]), { a: 30, b: 30, c: 30 });
  assert.deepEqual(ratearPeloPrevisto(90, []), {});
});

test("dias úteis de setembro de 2026, seg a sex, são 22", () => {
  assert.equal(diasUteisNoMes(2026, 9, SEG_A_SEX), 22);
  assert.equal(diasUteisNoMes(2026, 9, [1, 2, 3, 4, 5, 6]), 26);
  assert.equal(diasUteisNoMes(2026, 9, []), 0);
});

test("somar dias úteis pula fim de semana; zero devolve o próximo útil", () => {
  /* Quarta 2/9 + 6 úteis: qui 3, sex 4, seg 7, ter 8, qua 9, qui 10. */
  assert.deepEqual(somarDiasUteis({ ano: 2026, mes: 9, dia: 2 }, 6, SEG_A_SEX), { ano: 2026, mes: 9, dia: 10 });
  /* Sábado 5/9 + 0 úteis = segunda 7/9. */
  assert.deepEqual(somarDiasUteis({ ano: 2026, mes: 9, dia: 5 }, 0, SEG_A_SEX), { ano: 2026, mes: 9, dia: 7 });
  /* Vira o mês. */
  assert.deepEqual(somarDiasUteis({ ano: 2026, mes: 9, dia: 29 }, 3, SEG_A_SEX), { ano: 2026, mes: 10, dia: 2 });
});

test("capacidade: 38 h de fila em 160 h/mês ocupam 6 dias úteis e o prazo cai em 10/09", () => {
  const c = capacidadeDaFila({
    minutosFila: 38 * 60,
    pedidos: 12,
    horasProdutivasMes: 160,
    diasDeExpediente: SEG_A_SEX,
    hoje: { ano: 2026, mes: 9, dia: 2 },
  });
  assert.equal(c.horasFila, 38);
  assert.equal(c.diasUteisNoMes, 22);
  assert.equal(c.horasPorDiaUtil, 7.27);
  assert.equal(c.diasUteisNecessarios, 6);
  assert.equal(c.prazoSugerido, "2026-09-10");
  assert.equal(c.ocupacaoDoMesPct, 23.75);
});

test("capacidade sem horas produtivas: só a fila, sem prazo", () => {
  const c = capacidadeDaFila({
    minutosFila: 600,
    pedidos: 3,
    horasProdutivasMes: null,
    diasDeExpediente: SEG_A_SEX,
    hoje: { ano: 2026, mes: 9, dia: 2 },
  });
  assert.equal(c.horasFila, 10);
  assert.equal(c.horasMes, null);
  assert.equal(c.prazoSugerido, null);
  assert.equal(c.ocupacaoDoMesPct, null);
});

test("capacidade: fila vazia entrega no próximo dia útil e ocupa 0%", () => {
  const c = capacidadeDaFila({
    minutosFila: 0,
    pedidos: 0,
    horasProdutivasMes: 100,
    diasDeExpediente: SEG_A_SEX,
    hoje: { ano: 2026, mes: 9, dia: 5 },
  });
  assert.equal(c.diasUteisNecessarios, 0);
  assert.equal(c.prazoSugerido, "2026-09-07");
  assert.equal(c.ocupacaoDoMesPct, 0);
});
