/**
 * Cuánto queda por saldar de una rendición de viáticos.
 *
 * `rendicion_viatico.saldo` es la diferencia entre lo adelantado y lo rendido
 * (positiva: el empleado debe devolver; negativa: la empresa le debe). Es un
 * dato fijo: el cierre lo usa para decidir si hay devolución o reintegro.
 *
 * Lo que la persona necesita ver es otra cosa: si esa diferencia ya se saldó.
 * Una devolución o reintegro inmediato la salda al cierre; uno diferido la deja
 * pendiente en una cuenta a pagar al empleado hasta que se paga. Antes la
 * pantalla mostraba la diferencia como "saldo" aun con la devolución hecha, y
 * parecía que el empleado seguía debiendo.
 */

export interface MovimientoCierre {
  tipo: string; // DEVOLUCION | REINTEGRO
  monto: unknown;
  diferido: boolean;
  anulado?: boolean;
  fecha?: Date | string | null;
  cxp_empleado?: { monto_original: unknown; saldo_pendiente: unknown } | null;
}

export interface SaldoRendicion {
  /** Adelantado − rendido. Positivo: debe devolver el empleado; negativo: debe la empresa. */
  diferencia: number;
  /** Lo que ya se devolvió o reintegró efectivamente. */
  saldado: number;
  /** Lo que falta saldar, con el mismo signo que la diferencia. 0 si ya está saldado. */
  pendiente: number;
  /** Parte de lo pendiente que está en una cuenta a pagar al empleado (reintegro diferido). */
  pendiente_en_cxp: number;
}

const r2 = (n: number) => Math.round(n * 100) / 100;

export function calcularSaldoRendicion(saldo: unknown, movimientos: MovimientoCierre[] = []): SaldoRendicion {
  const diferencia = r2(Number(saldo ?? 0));
  let saldado = 0;
  let enCxp = 0;
  for (const m of movimientos) {
    if (m.anulado) continue;
    const monto = Number(m.monto ?? 0);
    if (m.diferido) {
      // Diferido: cuenta lo que ya se pagó de la cuenta a pagar; el resto sigue pendiente.
      const original = Number(m.cxp_empleado?.monto_original ?? monto);
      const pendienteCxp = Number(m.cxp_empleado?.saldo_pendiente ?? monto);
      saldado += Math.max(0, original - pendienteCxp);
      enCxp += Math.max(0, pendienteCxp);
    } else {
      saldado += monto;
    }
  }
  saldado = r2(Math.min(saldado, Math.abs(diferencia)));
  const restante = r2(Math.max(0, Math.abs(diferencia) - saldado));
  return {
    diferencia,
    saldado,
    pendiente: diferencia < 0 && restante > 0 ? -restante : restante,
    pendiente_en_cxp: r2(Math.min(enCxp, restante)),
  };
}
