/**
 * Saldo denormalizado de una cuenta por cobrar.
 *
 * `cuentas_cobrar.saldo_pendiente` es la suma de los saldos de sus cuotas. Cada
 * vez que algo mueve las cuotas —un cobro, una anulación, una nota de crédito,
 * una refinanciación— hay que recalcularlo: si no, la cuenta queda reclamando
 * una deuda que ya no existe, o perdonando una que sí.
 */

export interface CuotaDeCuenta {
  /** Saldo vigente de la cuota. Un 0 es un valor válido: la cuota está saldada. */
  saldo_pendiente?: unknown;
  /** Monto original, usado solo cuando la cuota todavía no tiene saldo cargado. */
  dmoncuota?: unknown;
  /** Estado de la cuota. Manda sobre la columna de saldo. */
  estado?: unknown;
}

/**
 * Estados cuya cuota ya no debe nada, sin importar qué diga su columna de saldo.
 *
 * Se comparan en minúsculas porque en la base conviven las dos grafías
 * ('pendiente' y 'Pendiente') y los dos géneros ('pagado'/'pagada').
 */
const ESTADOS_SIN_DEUDA = new Set(['pagado', 'pagada', 'anulado', 'anulada', 'refinanciada', 'refinanciado']);

const num = (v: unknown): number => {
  const n = Number(v);
  return Number.isFinite(n) ? n : 0;
};

/** Cuentas distintas a las que pertenecen estas cuotas, en orden de aparición. */
export function cuentasAfectadas(cuotas: Array<{ cuenta_id: string | null }>): string[] {
  const vistas = new Set<string>();
  for (const cuota of cuotas) {
    if (cuota.cuenta_id) vistas.add(cuota.cuenta_id);
  }
  return [...vistas];
}

/**
 * Saldo y estado que le corresponden a una cuenta según sus cuotas.
 *
 * Una cuota pagada, anulada o refinanciada aporta 0 aunque su `saldo_pendiente`
 * diga otra cosa: la anulación de factura marca el estado pero deja el saldo
 * viejo escrito, y creerle a esa columna resucita deuda muerta.
 *
 * El fallback al monto de la cuota solo aplica cuando no hay saldo cargado
 * (null/undefined). Un `saldo_pendiente` de 0 vale 0: escribirlo como
 * `saldo_pendiente || dmoncuota` haría que una cuota saldada aportara su monto
 * entero, porque 0 es falsy.
 */
export function saldoDeCuenta(cuotas: CuotaDeCuenta[]): { saldo: number; estado: 'pagado' | 'pendiente' } {
  let saldo = 0;
  for (const cuota of cuotas) {
    const estado = String(cuota.estado ?? '').toLowerCase();
    if (ESTADOS_SIN_DEUDA.has(estado)) continue;
    saldo += num(cuota.saldo_pendiente ?? cuota.dmoncuota);
  }
  const redondeado = Math.max(0, +saldo.toFixed(2));
  return { saldo: redondeado, estado: redondeado <= 0.009 ? 'pagado' : 'pendiente' };
}
