import { test } from "node:test";
import assert from "node:assert/strict";
import {
  admiteAjustesNuevos,
  admiteCaptura,
  faltaBaseReal,
  productosAjustables,
  reglaAEnviar,
  muestraAjustes,
  muestraEjecucion,
  faseDeCosto,
  guardarBaseDeshabilitado,
  puedeAplicarReal,
  puedeBaseEstimada,
  puedeBaseReal,
  puedeEstimar,
} from "./costos-reglas.ts";

const manual = { base: "MANUAL", basePendiente: false, baseReal: null };

test("una orden anulada es de sólo lectura, tenga o no documento de producción", () => {
  const fase = faseDeCosto("ANULADA", null);
  assert.equal(fase, "ANULADA");
  assert.equal(puedeEstimar(fase, [], false), false);
  assert.equal(puedeBaseEstimada(fase, manual), false);
  assert.equal(puedeBaseReal(fase, manual), false);
  assert.equal(puedeAplicarReal(fase, null), false);
});

test("un borrador no estima ni captura bases: el servidor lo rechaza hasta planificar (hallazgo de Codex en #17)", () => {
  const fase = faseDeCosto("BORRADOR", null);
  assert.equal(fase, "BORRADOR");
  assert.equal(puedeEstimar(fase, [], false), false);
  assert.equal(puedeBaseEstimada(fase, manual), false);
  assert.equal(puedeBaseReal(fase, manual), false);
  assert.equal(faseDeCosto("PLANIFICADA", null), "ANTES");
});

test("una orden cerrada con costo congelado no admite nada, aunque esté PRODUCIDA o TERMINADA", () => {
  for (const estado of ["PRODUCIDA", "TERMINADA"]) {
    const fase = faseDeCosto(estado, "2026-10-18 10:00:00");
    assert.equal(fase, "CERRADA");
    assert.equal(puedeEstimar(fase, [], false), false);
    assert.equal(puedeBaseReal(fase, manual), false);
    assert.equal(puedeAplicarReal(fase, null), false);
  }
});

test("la base real se captura durante la ejecución, no sólo después de producir", () => {
  assert.equal(puedeBaseReal(faseDeCosto("EN_EJECUCION", null), manual), true);
  assert.equal(puedeBaseReal(faseDeCosto("MP_DESPACHADA", null), manual), true);
  assert.equal(puedeBaseReal(faseDeCosto("PLANIFICADA", null), manual), false);
  assert.equal(puedeBaseReal(faseDeCosto("EN_EJECUCION", null), { ...manual, base: "UNIDAD_PRODUCIDA" }), false);
});

test("una orden heredada producida sin cerrar todavía admite la base real", () => {
  assert.equal(puedeBaseReal(faseDeCosto("PRODUCIDA", null), manual), true);
});

test("una orden heredada producida sin estimar puede estimar tarde; con renglones ya no", () => {
  const fase = faseDeCosto("PRODUCIDA", null);
  assert.equal(fase, "LEGADO");
  assert.equal(puedeEstimar(fase, [], false), true);
  assert.equal(puedeEstimar(fase, [manual], false), false);
  // Ya estimada sin que ninguna tarifa aplicara: no hay renglones, pero el servidor rechaza otra estimación tardía.
  assert.equal(puedeEstimar(fase, [], true), false);
});

test("en una orden heredada sólo se completa la base estimada que quedó pendiente", () => {
  const fase = faseDeCosto("TERMINADA", null);
  assert.equal(puedeBaseEstimada(fase, { ...manual, basePendiente: true }), true);
  assert.equal(puedeBaseEstimada(fase, manual), false);
});

test("re-estimar con un real ya capturado se oculta: el servidor lo rechaza", () => {
  const fase = faseDeCosto("EN_EJECUCION", null);
  assert.equal(puedeEstimar(fase, [manual], false), true);
  assert.equal(puedeEstimar(fase, [{ ...manual, baseReal: 12 }], false), false);
});

test("«aplicar costo real» sólo para heredadas sin real", () => {
  assert.equal(puedeAplicarReal("LEGADO", null), true);
  assert.equal(puedeAplicarReal("LEGADO", 10), false);
  assert.equal(puedeAplicarReal("EJECUCION", null), false);
});

test("Guardar base: alcanza con la real aunque la estimada esté vacía (hallazgo de Codex en #7)", () => {
  assert.equal(guardarBaseDeshabilitado(true, true, "", "59629.5"), false);
  assert.equal(guardarBaseDeshabilitado(true, true, "100", ""), false);
  assert.equal(guardarBaseDeshabilitado(true, true, "", ""), true);
  assert.equal(guardarBaseDeshabilitado(true, true, "  ", "  "), true);
  assert.equal(guardarBaseDeshabilitado(true, false, "", "99"), true);
  assert.equal(guardarBaseDeshabilitado(false, true, "99", ""), true);
});

test("la captura y los adicionales siguen abiertos en EN_EJECUCION (hallazgo de Codex en #17)", () => {
  assert.equal(admiteCaptura("MP_DESPACHADA"), true);
  assert.equal(admiteCaptura("EN_EJECUCION"), true);
  assert.equal(admiteCaptura("PRODUCIDA"), false);
  assert.equal(admiteCaptura("PLANIFICADA"), false);
});

test("una orden anulada conserva visibles su ejecución y sus ajustes, sin permitir nuevos", () => {
  assert.equal(muestraEjecucion("ANULADA"), true);
  assert.equal(muestraEjecucion("PLANIFICADA"), false);
  assert.equal(muestraAjustes("ANULADA", "2026-10-18 10:00:00"), true);
  assert.equal(muestraAjustes("ANULADA", null), false);
  assert.equal(muestraAjustes("PRODUCIDA", null), false);
  assert.equal(admiteAjustesNuevos("ANULADA"), false);
  assert.equal(admiteAjustesNuevos("TERMINADA"), true);
});

test("ajustes: sólo los productos que produjeron algo (hallazgo de Codex en #17)", () => {
  const detalles = [{ plu: "A", cantidadProducida: 0 }, { plu: "B", cantidadProducida: 5 }];
  assert.deepEqual(productosAjustables(detalles).map((d) => d.plu), ["B"]);
  assert.deepEqual(productosAjustables([{ plu: "A", cantidadProducida: 0 }]), []);
});

test("la regla sólo se manda si cambió: FIJO_LOTE intacto no se reenvía", () => {
  assert.equal(reglaAEnviar("FIJO_LOTE", "FIJO_LOTE"), undefined);
  assert.equal(reglaAEnviar("PROPORCIONAL", "CAPTURADO"), "CAPTURADO");
  assert.equal(reglaAEnviar("PROPORCIONAL", undefined), undefined);
});

test("no se pide la base real de un producto que quedó en cero con la orden en ejecución", () => {
  const f = faseDeCosto("EN_EJECUCION", null);
  assert.equal(faltaBaseReal(f, "EN_EJECUCION", manual, 0), false);
  assert.equal(faltaBaseReal(f, "EN_EJECUCION", manual, 10), true);
  assert.equal(faltaBaseReal(faseDeCosto("MP_DESPACHADA", null), "MP_DESPACHADA", manual, 0), true);
  assert.equal(faltaBaseReal(f, "EN_EJECUCION", { ...manual, baseReal: 3 }, 10), false);
});
