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; public class ConfigObservationRepository : MongoRepository, IConfigObservationRepository { private readonly ApiSettings _apiSettings; private readonly IMasterListServiceFactory _masterListServiceFactory; public ConfigObservationRepository(IOptions apiSettings, IMongoDatabase database, IMasterListServiceFactory masterListServiceFactory) : base(database) { _masterListServiceFactory = masterListServiceFactory; _apiSettings = apiSettings.Value; } public override string GetCollectionName() { return _apiSettings.ConfigObservations ?? "config_observations"; } public async Task FindById(ObjectId id) { var result = await Collection.FindAsync(Builders.Filter.Eq(x => x.Id, id)); return await result.FirstOrDefaultAsync(); } public async Task Update(ConfigObservation configObservation) { await UpdateOneAsync(configObservation.Id, configObservation); return configObservation; } public async Task Delete(ObjectId id) { return await DeleteAsync(id); } public async Task> FindAllIds() { var allCollection = await Collection.FindAsync(_ => true); return allCollection.ToList().Select(item => item.Id).ToList(); } public async Task> FindAll() { var result = await Collection.FindAsync(_ => true); return await result.ToListAsync(); } 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; } 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; } public async Task Count() { var filter = Builders.Filter.Empty; var result = await Collection.CountDocumentsAsync(filter); return result; } 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; } 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(); } 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(); } public async Task InsertOneAsyncAndReturn(ConfigObservation configObservationItem) { await Collection.InsertOneAsync(configObservationItem); return configObservationItem; } 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(); } 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(); } 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); } }