/**
 * Cuánto se descuenta de una cuenta de tesorería al pagar un documento (gasto,
 * orden de pago) que puede estar en otra moneda.
 *
 * El saldo de `tes_cuentas` y el `monto` de `tes_movimientos` están siempre en la
 * moneda de la cuenta. Antes se descontaba el total del documento tal cual: un
 * gasto de USD 100 pagado desde una cuenta en guaraníes le restaba Gs. 100.
 *
 * Reglas (ver docs/plan-gastos-multimoneda.md):
 *   - misma moneda → el total, sin convertir;
 *   - documento en moneda extranjera desde una cuenta en guaraníes → total × cotización
 *     (el banco hizo la conversión; el asiento usa la misma cotización, así que cuadra);
 *   - cualquier otra combinación (guaraníes desde una cuenta en USD, USD desde EUR) → no se permite.
 */

export const MONEDA_LOCAL = 'PYG';

export type PagoEnCuenta =
  | { ok: true; monto: number; tipoCambio: number | null; convertido: boolean }
  | { ok: false; mensaje: string };

export const normalizarMoneda = (codigo?: string | null): string =>
  String(codigo || MONEDA_LOCAL).toUpperCase().trim() || MONEDA_LOCAL;

/** Una cotización usable para pasar una moneda extranjera a guaraníes. */
export const cotizacionValida = (cotizacion: unknown): boolean => {
  const n = Number(cotizacion);
  return Number.isFinite(n) && n > 0 && n !== 1;
};

const redondear = (valor: number, decimales: number) => {
  const f = 10 ** decimales;
  return Math.round((valor + Number.EPSILON) * f) / f;
};

export function montoEnMonedaDeCuenta(params: {
  total: number;
  monedaDocumento?: string | null;
  cotizacion?: number | null;
  monedaCuenta?: string | null;
  nombreCuenta?: string | null;
}): PagoEnCuenta {
  const doc = normalizarMoneda(params.monedaDocumento);
  const cuenta = normalizarMoneda(params.monedaCuenta);
  const total = Number(params.total) || 0;
  const nombre = params.nombreCuenta ? `"${params.nombreCuenta}"` : 'elegida';

  if (doc === cuenta) {
    return {
      ok: true,
      monto: redondear(total, 2),
      tipoCambio: doc === MONEDA_LOCAL ? null : cotizacionValida(params.cotizacion) ? Number(params.cotizacion) : null,
      convertido: false,
    };
  }

  if (cuenta === MONEDA_LOCAL) {
    if (!cotizacionValida(params.cotizacion)) {
      return {
        ok: false,
        mensaje: `Falta la cotización del ${doc} para descontar el pago de la cuenta ${nombre}, que está en guaraníes.`,
      };
    }
    const tc = Number(params.cotizacion);
    return { ok: true, monto: redondear(total * tc, 0), tipoCambio: tc, convertido: true };
  }

  if (doc === MONEDA_LOCAL) {
    return {
      ok: false,
      mensaje: `El pago está en guaraníes y la cuenta ${nombre} está en ${cuenta}. Elegí una cuenta en guaraníes.`,
    };
  }

  return {
    ok: false,
    mensaje: `El pago está en ${doc} y la cuenta ${nombre} está en ${cuenta}. Elegí una cuenta en ${doc} o en guaraníes.`,
  };
}
