/**
 * Qué se puede hacer con el costo de una orden según su momento. Es la misma regla que aplica el servidor
 * (`CostoOrdenServicio`), escrita acá una sola vez y sin dependencias para poder probarla: la pantalla sólo la
 * consulta, no la reinventa en cada botón (#24981, P15).
 *
 * Los cinco momentos:
 *  - BORRADOR   todavía se edita: el servidor no estima ni acepta bases hasta planificarla.
 *  - ANTES      planificada: se estima y se captura la base estimada.
 *  - EJECUCION  materia prima despachada o en ejecución: además se captura la base REAL (P10).
 *  - LEGADO     producida sin cerrar con costo congelado (órdenes de antes de P10b): sólo ahí se estima tarde,
 *               se completa una base pendiente y se aplica el costo real a mano.
 *  - CERRADA    el costo quedó congelado: un dato tardío es un AJUSTE, no se reescribe.
 *  - ANULADA    el servidor rechaza todo; la tarjeta sólo muestra.
 */
export type FaseCosto = "BORRADOR" | "ANTES" | "EJECUCION" | "LEGADO" | "CERRADA" | "ANULADA";

export function faseDeCosto(estado: string, cerradoEn: string | null): FaseCosto {
  if ("ANULADA" === estado) return "ANULADA";
  if (null !== cerradoEn) return "CERRADA";
  if ("PRODUCIDA" === estado || "TERMINADA" === estado) return "LEGADO";
  if ("MP_DESPACHADA" === estado || "EN_EJECUCION" === estado) return "EJECUCION";
  if ("PLANIFICADA" === estado) return "ANTES";

  return "BORRADOR";
}

export type RenglonParaReglas = {
  base: string;
  basePendiente: boolean;
  baseReal: number | null;
};

/** Estimar o re-estimar: antes de producir, salvo que ya haya un real (re-estimar lo borraría); tarde, sólo una orden que nunca se estimó. */
export function puedeEstimar(fase: FaseCosto, renglones: RenglonParaReglas[], yaEstimada: boolean): boolean {
  if ("LEGADO" === fase) return !yaEstimada && 0 === renglones.length;
  if ("ANTES" !== fase && "EJECUCION" !== fase) return false;

  return renglones.every((r) => null === r.baseReal);
}

/** La base ESTIMADA: antes de producir; después, sólo la que quedó pendiente de una estimación tardía. */
export function puedeBaseEstimada(fase: FaseCosto, r: RenglonParaReglas): boolean {
  if ("MANUAL" !== r.base) return false;
  if ("ANTES" === fase || "EJECUCION" === fase) return true;

  return "LEGADO" === fase && r.basePendiente;
}

/** La base REAL: con la materia prima despachada (antes de cerrar) o, en una orden heredada, ya producida. */
export function puedeBaseReal(fase: FaseCosto, r: RenglonParaReglas): boolean {
  return "MANUAL" === r.base && ("EJECUCION" === fase || "LEGADO" === fase);
}

/** «Aplicar costo real» a mano sólo existe para órdenes heredadas que todavía no lo tienen. */
export function puedeAplicarReal(fase: FaseCosto, totalReal: number | null): boolean {
  return "LEGADO" === fase && null === totalReal;
}

/**
 * El botón Guardar de la base de un componente. Basta UNA de las dos bases que se están pidiendo: el servidor acepta
 * la real sin la estimada (y al revés), así que exigir la estimada cuando sólo se tiene la real dejaba la captura sin salida.
 */
export function guardarBaseDeshabilitado(pideEstimada: boolean, pideReal: boolean, estimada: string, real: string): boolean {
  const hayEstimada = pideEstimada && "" !== estimada.trim();
  const hayReal = pideReal && "" !== real.trim();

  return !hayEstimada && !hayReal;
}

/** Con la materia prima despachada y en ejecución el servidor admite capturar y pedir/despachar/anular adicionales (`admiteCaptura`). */
export function admiteCaptura(estado: string): boolean {
  return "MP_DESPACHADA" === estado || "EN_EJECUCION" === estado;
}

/** La tarjeta de ejecución se ve desde el despacho en adelante, ANULADA incluida (de sólo lectura): anular no borra lo capturado. */
export function muestraEjecucion(estado: string): boolean {
  return admiteCaptura(estado) || "PRODUCIDA" === estado || "TERMINADA" === estado || "ANULADA" === estado;
}

/** Los ajustes existen desde el cierre; una orden cerrada que luego se anula los conserva, así que se siguen mostrando. */
export function muestraAjustes(estado: string, cerradoEn: string | null): boolean {
  return null !== cerradoEn && ("PRODUCIDA" === estado || "TERMINADA" === estado || "ANULADA" === estado);
}

/** Registrar ajustes nuevos: sólo con la orden viva (producida o terminada), no anulada. */
export function admiteAjustesNuevos(estado: string): boolean {
  return "PRODUCIDA" === estado || "TERMINADA" === estado;
}

/** Los productos a los que se les puede cargar un ajuste: los que produjeron algo (sin unidades no hay a quién cargarle el costo). */
export function productosAjustables<T extends { cantidadProducida: number }>(detalles: T[]): T[] {
  return detalles.filter((d) => d.cantidadProducida > 0);
}

/**
 * La regla de una línea de consumo se manda SÓLO si cambió: el servidor rechaza `FIJO_LOTE` como valor entrante, así que
 * reenviar la actual de una línea de lote fijo impediría guardar su real.
 */
export function reglaAEnviar(actual: string, elegida: string | undefined): string | undefined {
  return undefined === elegida || elegida === actual ? undefined : elegida;
}

/**
 * ¿Falta la base real de este componente para poder cerrar? No si su producto ya quedó en cero unidades capturadas con la
 * orden en ejecución: el cierre fuerza esa base a cero porque no hay unidades a las que costear, y pedirla es pedir un dato
 * que se descarta. (Con la materia prima recién despachada el cero todavía es «no capturado», así que sí se pide.)
 */
export function faltaBaseReal(fase: FaseCosto, estado: string, r: RenglonParaReglas, unidadesProducidas: number): boolean {
  if (!puedeBaseReal(fase, r) || null !== r.baseReal) return false;

  return !("EN_EJECUCION" === estado && unidadesProducidas <= 0);
}
