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; using adas_core.Domain.Models.Filter; using adas_core.Domain.Models.MongoModels; using adas_core.Domain.Models.Responses; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using MongoDB.Bson; using MongoDB.Driver; namespace adas_core.Application.Services; public class TreatmentService( ITreatmentRepository treatmentRepository, ITreatmentArchiveRepository treatmentArchiveRepository, IPatientService patientService, IConfigObservationService configObservationService, ILogger logger, IClientMessageService clientMessageService, ISubscribersService subscribersService, Lazy calculatedObservationsService, IUnitService unitService, IHttpContextAccessor httpContextAccessor, ILocalAuditService auditService) : ITreatmentService { public async Task> GetTreatmentsByPatientId(ObjectId id) { return await treatmentRepository.GetByPatientId(id); } public async Task Insert(PatientTreatment treatment) { logger.LogDebug("Insert {treatment}", treatment); var mappedTreatment = await MapTreatment(treatment); if (mappedTreatment != null) { await treatmentRepository.InsertOneAsync(mappedTreatment); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, mappedTreatment); _ = SendBroadcast(mappedTreatment, OperationType.Treatment); } } public async Task DeleteByPatientId(ObjectId id) { var treatmentToDelete = await FindByPatientId(id) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed); if (!treatmentToDelete.Any()) return true; logger.LogDebug("Delete Treatments by Patient Id {id}", id); var result = await treatmentRepository.DeleteByPatientId(id); if (!result) throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, treatmentToDelete, null); return result; } public async Task Archive(Patient patient) { await ArchiveByPatientId(patient.Id); } public async Task ArchiveByPatientId(ObjectId id) { logger.LogDebug("ArchiveB Treatments by Patient Id PatientId {id}", id); using (var cursor = await FindByPatientIdAsync(id)) { while (await cursor.MoveNextAsync()) foreach (var current in cursor.Current) await treatmentArchiveRepository.InsertOneAsync(current); } await DeleteByPatientId(id); } public async Task UpdateTreatment(PatientTreatment patientTreatment) { var oldTreatment = await treatmentRepository.GetById(patientTreatment.Id) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); logger.LogDebug("Updating Treatment {treatment}", patientTreatment.ToJson()); var result = await treatmentRepository.Update(patientTreatment); if (!result) throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldTreatment, patientTreatment); _ = SendBroadcast(patientTreatment, OperationType.UpdateTreatment); return result; } public async Task> FindByPatientIdAsync(ObjectId patientId) { return await treatmentRepository.FindByPatientIdAsync(patientId); } public async Task> FindByPatientId(ObjectId patientId) { return await treatmentRepository.FindByPatientId(patientId); } public async Task> GetBolusTreatments(ObjectId patientId) { return await treatmentRepository.FindBolusTreatments(patientId); } public async Task SaveRequestAsync(ApiRequest apiRequest) { await SaveRequest(apiRequest); } public async Task SaveRequest(ApiRequest apiRequest) { if (string.IsNullOrEmpty(apiRequest.PatientNumber)) { logger.LogDebug("Patient is null"); throw new ApiRequestException("Patient is null"); } logger.LogDebug("patientNumber: {apiRequestpatientNumber}", apiRequest.PatientNumber); var unitConfig = await unitService.FindByName(apiRequest.Location?.UnitName); if (unitConfig != null) { if (!unitConfig.Configuration.AutoAdt && !apiRequest.RequestFromPanel) { logger.LogWarning("Unit: {UnitName} with auto adt set to false can't manage auto ADT", apiRequest.Location?.UnitName); return; } } else { logger.LogWarning("Unit not found in Mapping list: {UnitName} can't manage auto ADT", apiRequest.Location?.UnitName); return; } try { switch (apiRequest.Type) { /* * OMP EVENT * OMP_O09 - Pharmacy/treatment order * ORM_O01 - Order message * RAS_O17 - Pharmacy/treatment administration */ case "OMP_O09": case "ORM_O01": case "RAS_O17": var patient = await patientService.FindByPatientNumber(apiRequest.PatientNumber); if (patient == null) { logger.LogDebug( "Ignore treatment: {apiRequest.treatments} for patient: {apiRequest.patientNumber}, patient not found", apiRequest.Treatment, apiRequest.PatientNumber); return; } apiRequest.Treatments ??= []; if (apiRequest.Treatment != null) apiRequest.Treatments.Add(apiRequest.Treatment); foreach (var treatment in apiRequest.Treatments) { treatment.PatientId = patient.Id; treatment.MessageTime = apiRequest.MessageTime; await Insert(treatment); } break; default: throw new ApiRequestException("ApiRequest type " + apiRequest.Type + " is not valid for Treatments"); } } catch (Exception ex) { logger.LogError("ERROR SAVING REQUEST: {exMessage} trace: {exStackTrace}", ex.Message, ex.StackTrace); throw; } } /* * Return active treatments of patient PatientType active = NW, canceled= DC */ public async Task> GetActiveTreatmentsByPatient(ObjectId id) { var treatments = await treatmentRepository.GetByPatientId(id); var activeTreatments = treatments .Where(IsValidTreatment) .GroupBy(t => t.PlacerOrder?.EntityIdentifier) .Select(GetMostRecentActiveTreatment) .Where(t => t != null) .AsEnumerable(); return activeTreatments; } public async Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId) { await treatmentRepository.UpdateManyObjectId(nameId, id, oldId); var treatments = await treatmentRepository.FindByPatientId(id); foreach (var treat in treatments) _ = SendBroadcast(treat, OperationType.UpdateTreatment); } public async Task> GetPaginatedTreatments(PaginationFilter filter) { var result = treatmentRepository.GetPaginatedTreatments(filter); var count = await result.CountDocumentsAsync(); var data = await result.Skip((filter.PageNumber - 1) * filter.PageSize) .Limit(filter.PageSize) .ToCursorAsync(); var dataList = await data.ToListAsync(); return new PaginationResponse(dataList, filter.PageNumber, filter.PageSize, count); } public async Task> GetActiveTreatmentsByPatientIdAndOrder(ObjectId patientId, string order) { return await treatmentRepository.GetActiveTreatmentsByPatientIdAndOrder(patientId, order); } public async Task DeleteById(ObjectId id) { var oldTreatment = await treatmentRepository.GetById(id) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldTreatment, null); await treatmentRepository.DeleteAsync(id); } private async Task MapTreatment(PatientTreatment treatment) { var treatment2 = await calculatedObservationsService.Value.Map(treatment); if (treatment2 == null) return null; var treatment3 = await configObservationService.Map(treatment2); if (treatment3 == null) logger.LogDebug("Mapping {treatment}: Ignored", treatment); return treatment; } private async Task SendBroadcast(PatientTreatment treatment, OperationType operationType) { var patient = await patientService.FindById(treatment.PatientId); if (patient?.PointOfCareId == null) return; var subscribers = subscribersService.GetSubscribers() .Where(s => s.LocationIds.Contains(patient.PointOfCareId.Value)).ToList(); foreach (var subscriber in subscribers) await clientMessageService.SendAsync(subscriber.Id, operationType, treatment); } private static bool IsValidTreatment(PatientTreatment treatment) { if (treatment.PlacerOrder == null) return false; var currentTime = DateTime.UtcNow; if (treatment.EndTime != null && currentTime.CompareTo(treatment.EndTime) > 0) return false; if (treatment.StartTime != null && currentTime.CompareTo(treatment.StartTime) < 0) return false; return treatment.OrderControl != OrderControlType.Dc; } private static PatientTreatment? GetMostRecentActiveTreatment(IGrouping group) { return group .Where(t => t.OrderControl is OrderControlType.Nw or OrderControlType.Xo) .OrderByDescending(t => t.OrderTime) .FirstOrDefault(); } }