/**
 * Saldo disponible de una NC para aplicar desde recibos (`rec_saldo_disponible`).
 * NULL significa "nunca se tocó": vale el total de la NC. Se descuenta y se
 * repone en los dos modos: una NC ESTRICTO aplicada en un recibo también se
 * consume, si no se la podía volver a elegir en el siguiente cobro de la misma
 * factura.
 */

interface TxSaldoNc {
  nota_credito_cab: {
    findUnique(args: unknown): Promise<{ id: string; rec_saldo_disponible: unknown } | null>;
    update(args: unknown): Promise<unknown>;
  };
  nota_credito_subtotal: {
    aggregate(args: unknown): Promise<{ _sum: { dtotgralope: unknown } }>;
  };
}

async function totalNc(tx: TxSaldoNc, notaCreditoId: string): Promise<number> {
  const agg = await tx.nota_credito_subtotal.aggregate({
    where: { nota_credito_cab_id: notaCreditoId },
    _sum: { dtotgralope: true },
  });
  return Number(agg._sum.dtotgralope) || 0;
}

async function saldoActual(tx: TxSaldoNc, notaCreditoId: string): Promise<{ saldo: number; total: number }> {
  const nc = await tx.nota_credito_cab.findUnique({
    where: { id: notaCreditoId },
    select: { id: true, rec_saldo_disponible: true },
  });
  const total = await totalNc(tx, notaCreditoId);
  const disponible = nc?.rec_saldo_disponible == null ? total : Number(nc.rec_saldo_disponible);
  return { saldo: disponible, total };
}

function redondear(v: number): number {
  return Math.round(v * 100) / 100;
}

/** Descuenta lo aplicado en un recibo. Devuelve el nuevo saldo. */
export async function consumirSaldoNc(tx: TxSaldoNc, notaCreditoId: string, monto: number): Promise<number> {
  const { saldo } = await saldoActual(tx, notaCreditoId);
  const nuevo = Math.max(0, redondear(saldo - monto));
  await tx.nota_credito_cab.update({ where: { id: notaCreditoId }, data: { rec_saldo_disponible: nuevo } });
  return nuevo;
}

/** Repone lo aplicado al anular el recibo, sin pasar el total de la NC. */
export async function reponerSaldoNc(tx: TxSaldoNc, notaCreditoId: string, monto: number): Promise<number> {
  const { saldo, total } = await saldoActual(tx, notaCreditoId);
  const nuevo = Math.min(total, redondear(saldo + monto));
  await tx.nota_credito_cab.update({ where: { id: notaCreditoId }, data: { rec_saldo_disponible: nuevo } });
  return nuevo;
}
