using adas_core.Application.Repositories.Interfaces; using adas_core.Domain.Enums; using adas_core.Domain.Models; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.DTO; using adas_core.Domain.Models.Masters; using adas_core.Domain.Models.MongoModels; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; using Serilog; using MongoUtils = adas_core.Infrastructure.Utils.MongoUtils; namespace adas_core.Infrastructure.Repositories; public class AdmissionRepository : MongoRepository, IAdmissionRepository { private readonly ApiSettings _apiSettings; public AdmissionRepository(IOptions apiSettings, IMongoDatabase database) : base(database) { if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings)); _apiSettings = apiSettings.Value; } public override string GetCollectionName() { return _apiSettings.Admissions; } public override async Task InsertOneAsync(Admission admission) { try { admission.AdmissionDate = DateTime.UtcNow; await base.InsertOneAsync(admission); } catch (Exception e) { Log.Warning("Exception trying to insert admission: {admission}. Exception {e}", admission, e); } } public async Task Delete(ObjectId id) { try { var filter = Builders.Filter.Eq(x => x.Id, id); await Collection.DeleteOneAsync(filter, null); } catch (Exception e) { Log.Error("Exception trying to delete admission: {id}. Exception {e}", id, e); throw; } } public async Task Update(Admission admission) { try { await UpdateOneAsync(admission.Id, admission); } catch (Exception e) { Log.Error("Exception trying to update admission: {admission}. Exception {e}", admission, e); throw; } } public async Task UpdateLocation(ObjectId id, ObjectId newLocation) { var filterBuilder = Builders.Filter; var filter = filterBuilder.Eq(p => p.Id, id); var update = Builders.Update .Set(p => p.PointOfCareId, newLocation); await Collection.UpdateOneAsync(filter, update); } public async Task UpdatePatient(ObjectId id, Person patient) { var filterBuilder = Builders.Filter; var filter = filterBuilder.Eq(p => p.Id, id); var update = Builders.Update .Set(p => p.Person, patient); await Collection.UpdateOneAsync(filter, update); } public async Task> FindAll() { try { var result = await Collection.FindAsync(_ => true); return await result.ToListAsync(); } catch (Exception ex) { Log.Error("Error getting all admissions. Exception: {ex}", ex); return []; } } public async Task SearchByPatientNumberAndDistinctUnit(string patientNumber, ObjectId unitId) { if (string.IsNullOrWhiteSpace(patientNumber)) return null; // Paciente ubicado en un PoC pero en diferente unidad var patient = await Collection.Find(Builders.Filter.And( Builders.Filter.Eq(p => p.Nhc, patientNumber), Builders.Filter.Ne(p => p.UnitId, unitId) )).ToListAsync(); // Si hay mas de una coincidencia devolvemos null por que puede no estar completo el patientNumber if (patient.Count > 1) return null; return patient.FirstOrDefault(); } public async Task FindById(ObjectId id) { try { var filter = Builders.Filter.Eq(p => p.Id, id); var result = await Collection.FindAsync(filter); return await result.FirstOrDefaultAsync(); } catch (Exception ex) { Log.Error("Error searching admission by id: {id}. Exception: {ex}", id, ex); return null; } } public async Task FindByNhc(string nhc) { try { var filter = Builders.Filter.Eq(p => p.Nhc, nhc); var result = await Collection.FindAsync(filter); return await result.FirstOrDefaultAsync(); } catch (Exception ex) { Log.Error("Error searching admission by NHC: {nhc}. Exception: {ex}", nhc, ex); return null; } } public async Task> FindByLocation(PatientLocation location) { try { var filter = Builders.Filter.Where(p => p.PatientLocation != null && location.UnitName == p.PatientLocation.UnitName && location.Bed == p.PatientLocation.Bed && location.Room == p.PatientLocation.Room); return await Collection.Find(filter).ToListAsync(); } catch (Exception ex) { Log.Error("Error searching admission by location: {location}. Exception: {ex}", location, ex); return []; } } public async Task?> FindByOrigin(string origin) { try { var filter = string.IsNullOrEmpty(origin) ? Builders.Filter.Empty : Builders.Filter.Where(p => p.Origin != null && origin.Equals(p.Origin.Name)); var result = await Collection.FindAsync(filter); return result.ToEnumerable(); } catch (Exception ex) { Log.Error("Error searching admissions by origin: {origin}. Exception: {ex}", origin, ex); return null; } } public async Task InsertOneAsyncAndReturn(Admission origin) { try { await Collection.InsertOneAsync(origin); return origin; } catch (Exception ex) { Log.Error(ex.Message); return null; } } public async Task> GetAdmissionByUnitIdWithOutPoC(ObjectId unitId) { try { var filter = Builders.Filter.Where(p => p.UnitId == unitId && p.PointOfCareId == null); var result = await Collection.FindAsync(filter); return result.ToList(); } catch (Exception ex) { Log.Error(ex.Message); return []; } } public async Task CountByUnitId(ObjectId unitId) { try { var filter = Builders.Filter.Where(p => p.UnitId == unitId); var result = await Collection.CountDocumentsAsync(filter); return result; } catch (Exception ex) { Log.Error(ex.Message); return 0; } } public async Task> FindByPointOfCareId(ObjectId pocId) { try { var filter = Builders.Filter.Where(p => p.PointOfCareId == pocId); var result = await Collection.FindAsync(filter); return result.ToList(); } catch (Exception ex) { Log.Error(ex.Message); return []; } } public async Task> FindByUnitIds(List unitIds) { var filterUnit = Builders.Filter.In("unitId", unitIds); return await Collection.Find(filterUnit).ToListAsync(); } public async Task> UpdateMasterListOption(List unitIds, UpdateOptionMasterListDto opt, string typeName) { var isParsed = Enum.TryParse(typeName, out var parsedTypeName); if (isParsed) { var filterUnit = Builders.Filter.In("unitId", unitIds); switch (parsedTypeName) { case MasterListType.OriginList: var originFilter = Builders.Filter.Eq( "origin.name", opt.OldOption?.Name ); var filterUpdateorigin = Builders.Filter.And(filterUnit, originFilter); var updateorigin = Builders.Update .Set("origin.name", opt.UpdatedOption?.Name); await Collection.UpdateManyAsync(filterUpdateorigin, updateorigin); await Collection.UpdateManyAsync(Builders.Filter.And(filterUnit, Builders.Filter.Eq( "originAux", opt.OldOption?.Name )), Builders.Update .Set("originAux", opt.UpdatedOption?.Name)); // Filtro para devolver los documentos actualizados (OR entre diagnosis.name y diagnosisAux) var originFilterToReturn = Builders.Filter.Eq("origin.name", opt.UpdatedOption?.Name); var originAuxFilterToReturn = Builders.Filter.Eq("originAux", opt.UpdatedOption?.Name); var filterToReturnorigin = Builders.Filter.And( filterUnit, Builders.Filter.Or(originFilterToReturn, originAuxFilterToReturn) ); // Devolver los documentos actualizados var updatedDocumentsorigin = await Collection.Find(filterToReturnorigin).ToListAsync(); return updatedDocumentsorigin; case MasterListType.DiagnosisList: var diagnosisFilter = Builders.Filter.Eq( "diagnosis.name", opt.OldOption?.Name ); var filterUpdateDiagnosis = Builders.Filter.And(filterUnit, diagnosisFilter); var updateDiagnosis = Builders.Update .Set("diagnosis.name", opt.UpdatedOption?.Name) .Set("diagnosis.description", opt.UpdatedOption?.Description); await Collection.UpdateManyAsync(filterUpdateDiagnosis, updateDiagnosis); await Collection.UpdateManyAsync(Builders.Filter.And(filterUnit, Builders.Filter.Eq( "diagnosisAux", opt.OldOption?.Name )), Builders.Update .Set("diagnosisAux", opt.UpdatedOption?.Name)); // Filtro para devolver los documentos actualizados (OR entre diagnosis.name y diagnosisAux) var diagnosisFilterToReturn = Builders.Filter.Eq("diagnosis.name", opt.UpdatedOption?.Name); var diagnosisAuxFilterToReturn = Builders.Filter.Eq("diagnosisAux", opt.UpdatedOption?.Name); var filterToReturn = Builders.Filter.And( filterUnit, Builders.Filter.Or(diagnosisFilterToReturn, diagnosisAuxFilterToReturn) ); // Devolver los documentos actualizados var updatedDocuments = await Collection.Find(filterToReturn).ToListAsync(); return updatedDocuments; case MasterListType.AllergyList: // allergies [] break; case MasterListType.InsulationList: // insulation break; case MasterListType.LanguageBarrierList: // languageBarrier break; case MasterListType.PassiveSittingList: // passiveSitting break; } } return new List(); } public async Task> DeleteMasterListOption(List unitIds, OptionList opt, string typeName) { var isParsed = Enum.TryParse(typeName, out var parsedTypeName); if (isParsed) { var filterUnit = Builders.Filter.In("unitId", unitIds); switch (parsedTypeName) { case MasterListType.OriginList: // origin // originAux // Filtro para devolver los documentos actualizados (OR entre diagnosis.name y diagnosisAux) var originFilterToReturn = Builders.Filter.Eq("origin.name", opt.Name); var originAuxFilterToReturn = Builders.Filter.Eq("originAux", opt.Name); var filterToReturnOrigin = Builders.Filter.And( filterUnit, Builders.Filter.Or(originFilterToReturn, originAuxFilterToReturn) ); // Devolver los documentos actualizados var updatedDocumentOrigin = await Collection.Find(filterToReturnOrigin).ToListAsync(); var originFilter = Builders.Filter.Eq( "origin.name", opt.Name ); var filterUpdateOrigin = Builders.Filter.And(filterUnit, originFilter); var updateorigin = Builders.Update .Set(x => x.Origin, null); await Collection.UpdateManyAsync(filterUpdateOrigin, updateorigin); await Collection.UpdateManyAsync(Builders.Filter.And(filterUnit, Builders.Filter.Eq( "originAux", opt.Name )), Builders.Update .Set(x => x.OriginAux, "")); return updatedDocumentOrigin; case MasterListType.DiagnosisList: // Filtro para devolver los documentos actualizados (OR entre diagnosis.name y diagnosisAux) var diagnosisFilterToReturn = Builders.Filter.Eq("diagnosis.name", opt.Name); var diagnosisAuxFilterToReturn = Builders.Filter.Eq("diagnosisAux", opt.Name); var filterToReturn = Builders.Filter.And( filterUnit, Builders.Filter.Or(diagnosisFilterToReturn, diagnosisAuxFilterToReturn) ); // Devolver los documentos actualizados var updatedDocuments = await Collection.Find(filterToReturn).ToListAsync(); var diagnosisFilter = Builders.Filter.Eq( "diagnosis.name", opt.Name ); var filterUpdateDiagnosis = Builders.Filter.And(filterUnit, diagnosisFilter); var updateDiagnosis = Builders.Update .Set(x => x.Diagnosis, null); await Collection.UpdateManyAsync(filterUpdateDiagnosis, updateDiagnosis); await Collection.UpdateManyAsync(Builders.Filter.And(filterUnit, Builders.Filter.Eq( "diagnosisAux", opt.Name )), Builders.Update .Set(x => x.DiagnosisAux, null)); return updatedDocuments; case MasterListType.AllergyList: // allergies [] break; case MasterListType.InsulationList: // insulation break; case MasterListType.LanguageBarrierList: // languageBarrier break; case MasterListType.PassiveSittingList: // passiveSitting break; } } return new List(); } public async Task DeleteAdmissionsByUnitId(ObjectId unitId) { try { var filter = Builders.Filter.Eq(p => p.UnitId, unitId); await Collection.DeleteManyAsync(filter); return true; } catch (Exception e) { Log.Logger.Error(e.Message); return false; } } public override async Task CreateIndexes() { var optionsUq = new CreateIndexOptions { Background = true, Unique = true, PartialFilterExpression = Builders.Filter.Exists(p => p.Nhc) }; var indexes = new List> { new("{ nhc: 1 }", optionsUq) }; await MongoUtils.EnsureIndexes(Collection, indexes); } public async Task?> FindByDiagnosis(string diagnosis) { try { var filter = Builders.Filter.Where(p => p.Diagnosis != null && diagnosis.Equals(p.Diagnosis.Name)); var result = await Collection.FindAsync(filter); return result.ToEnumerable(); } catch (Exception ex) { Log.Error("Error searching admissions by diagnosis: {origin}. Exception: {ex}", diagnosis, ex); return null; } } }