using adas_core.Application.Exceptions;
using adas_core.Application.Repositories.Interfaces;
using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.MongoModels;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
using System.Text.RegularExpressions;
namespace adas_core.Infrastructure.Repositories;
///
/// Repositorio para manejar las operaciones CRUD de ConfigObservation en MongoDB.
///
public class ConfigObservationRepository : MongoRepository, IConfigObservationRepository
{
private readonly ApiSettings _apiSettings;
private readonly IMasterListServiceFactory _masterListServiceFactory;
///
/// Constructor para ConfigObservationRepository, inyecta las dependencias necesarias.
///
/// Configuración de la API.
/// Instancia de la base de datos MongoDB.
/// Fábrica de servicios de lista maestra.
public ConfigObservationRepository(IOptions apiSettings, IMongoDatabase database,
IMasterListServiceFactory masterListServiceFactory) : base(database)
{
_masterListServiceFactory = masterListServiceFactory;
_apiSettings = apiSettings.Value;
}
///
/// Obtiene el nombre de la colección de MongoDB para ConfigObservation, utilizando la configuración proporcionada o un valor predeterminado.
///
/// El nombre de la colección de MongoDB para ConfigObservation.
public override string GetCollectionName()
{
return _apiSettings.ConfigObservations ?? "config_observations";
}
///
/// Busca un ConfigObservation por su ID en la base de datos MongoDB.
///
/// El ID del ConfigObservation a buscar.
/// El ConfigObservation encontrado, o null si no se encuentra.
public async Task FindById(ObjectId id)
{
var result = await Collection.FindAsync(Builders.Filter.Eq(x => x.Id, id));
return await result.FirstOrDefaultAsync();
}
///
/// Actualiza un ConfigObservation existente en la base de datos MongoDB.
///
/// El ConfigObservation con los datos actualizados.
/// El ConfigObservation actualizado, o null si no se encuentra.
public async Task Update(ConfigObservation configObservation)
{
await UpdateOneAsync(configObservation.Id, configObservation);
return configObservation;
}
///
/// Elimina un ConfigObservation por su ID en la base de datos MongoDB.
///
///
///
public async Task Delete(ObjectId id)
{
return await DeleteAsync(id);
}
///
/// Busca todos los IDs de ConfigObservation en la base de datos MongoDB.
///
/// Una lista de todos los IDs de ConfigObservation.
public async Task> FindAllIds()
{
var allCollection = await Collection.FindAsync(_ => true);
return allCollection.ToList().Select(item => item.Id).ToList();
}
///
/// Busca todos los ConfigObservation en la base de datos MongoDB.
///
/// Una colección de todos los ConfigObservation.
public async Task> FindAll()
{
var result = await Collection.FindAsync(_ => true);
return await result.ToListAsync();
}
///
/// Busca todos los nombres de ConfigObservation en la base de datos MongoDB, eliminando duplicados y espacios en blanco.
///
/// El ID del ConfigObservation para filtrar los nombres (opcional).
/// Una lista de nombres de ConfigObservation.
public async Task> GetConfigNames(string id)
{
var allConfigs = await Collection.Find(_ => true).ToListAsync();
var distinctNames = allConfigs
.Where(item => !string.IsNullOrWhiteSpace(item.Name))
.Select(item => item.Name!.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
return distinctNames;
}
///
/// Busca todos los nombres de ConfigObservation en la base de datos MongoDB, eliminando duplicados y espacios en blanco.
///
///
public async Task> GetConfigNames()
{
var allConfigs = await Collection.Find(_ => true).ToListAsync();
var distinctNames = allConfigs
.Where(item => !string.IsNullOrWhiteSpace(item.Name))
.Select(item => item.Name!.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
return distinctNames;
}
///
/// Cuenta el número total de ConfigObservation en la base de datos MongoDB.
///
/// El número total de ConfigObservation.
public async Task Count()
{
var filter = Builders.Filter.Empty;
var result = await Collection.CountDocumentsAsync(filter);
return result;
}
///
/// Busca ConfigObservation en la base de datos MongoDB utilizando paginación y un filtro de texto opcional que busca en varios campos.
///
/// El filtro de paginación y búsqueda.
/// Una colección de ConfigObservation que cumple con los criterios de búsqueda y paginación.
/// Se lanza cuando el texto de búsqueda es demasiado largo.
public async Task> GetPaginatedItems(PaginationFilter filter)
{
var builder = Builders.Filter;
var filterDefinition = builder.Empty;
if (!string.IsNullOrWhiteSpace(filter.FilteredRequest?.Text))
{
var searchText = filter.FilteredRequest.Text;
if (searchText.Length > 100)
throw new BadRequestException("Search text too long");
var searchTextEscaped = Regex.Escape(searchText);
var regex = new BsonRegularExpression(searchTextEscaped, "i");
var searchFilters = new List>
{
builder.Regex(x => x.Name, regex),
builder.Regex(x => x.CodingSystem, regex),
builder.Regex(x => x.OriginalName, regex),
builder.Regex(x => x.Code, regex),
builder.Regex("uiConfiguration.screenLabel", regex)
};
filterDefinition = builder.Or(searchFilters);
}
var sortDefinition = Builders.Sort.Ascending(x => x.Name);
var skip = Math.Max(0, (filter.PageNumber - 1) * filter.PageSize);
var limit = Math.Min(filter.PageSize, 100); // límite defensivo
var items = await Collection
.Find(filterDefinition)
.Sort(sortDefinition)
.Skip(skip)
.Limit(limit)
.ToListAsync();
return items;
}
///
/// Busca un ConfigObservation por su nombre en la base de datos MongoDB, utilizando una búsqueda insensible a mayúsculas y minúsculas.
///
/// El nombre del ConfigObservation a buscar.
/// El ConfigObservation que coincide con el nombre proporcionado, o null si no se encuentra.
/// Se lanza cuando el nombre es nulo, vacío o demasiado largo.
public async Task FindByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
if (name.Length > 100)
throw new BadRequestException("Name too long");
var safeName = Regex.Escape(name);
var filter = Builders.Filter.Regex(
x => x.Name,
new BsonRegularExpression($"^{safeName}$", "i")
);
return await Collection
.Find(filter)
.FirstOrDefaultAsync();
}
///
/// Busca un ConfigObservation por su sistema de codificación y código en la base de datos MongoDB, utilizando una búsqueda insensible a mayúsculas y minúsculas.
///
/// El sistema de codificación del ConfigObservation a buscar.
/// El código del ConfigObservation a buscar.
/// El ConfigObservation que coincide con el sistema de codificación y código proporcionados, o null si no se encuentra.
public async Task GetByCodeSysAndCode(string? codingSystem, string? code)
{
var builder = Builders.Filter;
var filter = builder.Empty;
if (!string.IsNullOrEmpty(codingSystem) && !string.IsNullOrEmpty(code))
{
filter &= builder.Eq(x => x.CodingSystem, codingSystem);
filter &= builder.Eq(x => x.Code, code);
}
if (filter == builder.Empty) return null;
var result = await Collection.FindAsync(filter);
return await result.FirstOrDefaultAsync();
}
///
/// Inserta un nuevo ConfigObservation en la base de datos MongoDB y devuelve el objeto insertado, incluyendo su ID generado.
///
/// El ConfigObservation a insertar en la base de datos.
/// El ConfigObservation insertado, incluyendo su ID generado.
public async Task InsertOneAsyncAndReturn(ConfigObservation configObservationItem)
{
await Collection.InsertOneAsync(configObservationItem);
return configObservationItem;
}
///
/// Busca todos los ConfigObservation que coinciden con un nombre específico en la base de datos MongoDB, utilizando una búsqueda insensible a mayúsculas y minúsculas.
///
/// El nombre del ConfigObservation a buscar.
/// Una lista de ConfigObservation que coinciden con el nombre proporcionado.
public async Task> FindAllByName(string name)
{
var builder = Builders.Filter;
var filter = builder.Empty;
if (!string.IsNullOrEmpty(name)) filter &= builder.Eq(x => x.Name, name);
if (filter == builder.Empty) return [];
var result = await Collection.FindAsync(filter);
return await result.ToListAsync();
}
///
/// Busca un ConfigObservation que coincida con los parámetros proporcionados (código, sistema de codificación, nombre u nombre original) en la base de datos MongoDB, utilizando una búsqueda insensible a mayúsculas y minúsculas.
///
/// El código del ConfigObservation a buscar.
/// El sistema de codificación del ConfigObservation a buscar.
/// El nombre del ConfigObservation a buscar.
/// El nombre original del ConfigObservation a buscar.
/// El ConfigObservation que coincide con los parámetros proporcionados, o null si no se encuentra.
public async Task GetSingleConfigObservationItem(string? code, string? codingSystem,
string? name, string? originalName)
{
var builder = Builders.Filter;
var filterDefinition = builder.Empty;
if (!string.IsNullOrEmpty(codingSystem)) filterDefinition &= builder.Eq(x => x.CodingSystem, codingSystem);
if (!string.IsNullOrEmpty(code)) filterDefinition &= builder.Eq(x => x.Code, code);
if (!string.IsNullOrEmpty(name)) filterDefinition &= builder.Eq(x => x.Name, name);
if (!string.IsNullOrEmpty(originalName)) filterDefinition &= builder.Eq(x => x.OriginalName, originalName);
return await Collection
.Find(filterDefinition)
.FirstOrDefaultAsync();
}
///
/// Inserta una carga inicial de ConfigObservation en la base de datos MongoDB utilizando una lista maestra de observaciones de enfermería.
/// Si ya existen ConfigObservation en la base de datos, solo se insertan aquellos que faltan en comparación con la lista maestra.
///
///
public sealed override async Task InsertInitialLoad()
{
var stringNurseObs = _masterListServiceFactory.StringNurseObs();
var isInitialized = await FindAll();
if (isInitialized.Count > 0)
{
var existingNames = isInitialized
.Where(c => c.Name != null) // Filtrar nulls para evitar errores de referencia
.Select(c => c.Name!) // Seleccionar solo los nombres (usamos '!' si confías en el filtro anterior)
.ToList();
var missingItems = stringNurseObs
.Where(x => !existingNames.Contains(x))
.ToList();
foreach (var item in missingItems)
await InsertOneAsync(new ConfigObservation
{
Name = item, Code = "NURSE-ADAS", CodingSystem = "ADAS",
InsertMode = ObservationEnum.InsertMode.Manual
});
return;
}
var masterListObsConfig = stringNurseObs.Select(c => new ConfigObservation
{
Name = c, Code = "NURSE-ADAS", CodingSystem = "ADAS", InsertMode = ObservationEnum.InsertMode.Manual
})
.ToList();
foreach (var item in masterListObsConfig) await InsertOneAsync(item);
}
}