/**
 * Medios de pago que no mueven fondos en el momento.
 *
 * "Pago por anticipo" (código SIFEN 11) cancela un gasto contra un anticipo que ya se
 * entregó antes (DOBA: la transferencia al despachante). La plata salió del banco con
 * ese anticipo; si el gasto la sacara de nuevo, el banco quedaría descontado dos veces.
 *
 * Además cada empresa puede marcar otro medio como que no mueve dinero
 * (`empresa_medio_pago.no_mueve_caja`). DOBA usa "Otro" para facturas que no se pagan
 * desde el banco y van contra Otros acreedores (oct-2026).
 *
 * Con estos medios el gasto no genera egreso en tesorería y su asiento acredita la
 * cuenta "Al pagar" del medio (en DOBA, Anticipos de despacho u Otros acreedores),
 * nunca un banco o caja.
 */
export const CODIGOS_MEDIO_SIN_CAJA = new Set([11]);

export const esMedioSinCaja = (medio?: { codigo?: number | null } | null, noMueveCajaEnEmpresa = false): boolean =>
  noMueveCajaEnEmpresa || (medio?.codigo != null && CODIGOS_MEDIO_SIN_CAJA.has(Number(medio.codigo)));

type DbMedios = {
  medio_pago: { findUnique: (args: any) => Promise<{ codigo: number | null } | null> };
  empresa_medio_pago: {
    findFirst: (args: any) => Promise<{ no_mueve_caja: boolean } | null>;
    findMany: (args: any) => Promise<Array<{ medio_pago_id: string }>>;
  };
};

/**
 * ¿Este medio no mueve dinero en esta empresa? (por su código o por la configuración de la empresa).
 * Si el medio ya está cargado (con su código), se pasa en `medio` y no se vuelve a buscar.
 */
export async function medioNoMueveCaja(
  db: DbMedios,
  empresaId: string,
  medioPagoId?: string | null,
  medio?: { codigo?: number | null } | null,
): Promise<boolean> {
  if (!medioPagoId) return false;
  const [delMedio, config] = await Promise.all([
    medio ?? db.medio_pago.findUnique({ where: { id: medioPagoId }, select: { codigo: true } }),
    db.empresa_medio_pago.findFirst({
      where: { empresa_id: empresaId, medio_pago_id: medioPagoId },
      select: { no_mueve_caja: true },
    }),
  ]);
  return esMedioSinCaja(delMedio, Boolean(config?.no_mueve_caja));
}

/** Ids de los medios que la empresa marcó como que no mueven dinero (para listados). */
export async function mediosSinCajaDeEmpresa(db: DbMedios, empresaId: string): Promise<Set<string>> {
  const filas = await db.empresa_medio_pago.findMany({
    where: { empresa_id: empresaId, no_mueve_caja: true },
    select: { medio_pago_id: true },
  });
  return new Set(filas.map((f) => f.medio_pago_id));
}
