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.DTO; using adas_core.Domain.Models.Filter; using adas_core.Domain.Models.Masters; 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; using Serilog; namespace adas_core.Application.Services; public class UnitService( IUnitRepository unitRepository, Lazy patientService, ILogger logger, IMasterListServiceFactory masterListServiceFactory, ISubscribersService subscribersService, Lazy clientMessageService, IPointOfCareService pointOfCareService, IHttpContextAccessor httpContextAccessor, ILocalAuditService auditService) : IUnitService { public async Task> GetAll(bool withPoCs = false) { var units = await unitRepository.GetAll(); if (withPoCs) foreach (var unit in units) { var pocList = await pointOfCareService.FindAllByUnitId(unit.Id); unit.PointOfCares = pocList?.ToList(); } return units; } public async Task> GetAllCompact() { var units = await unitRepository.GetAll(); var result = new List(); foreach (var unit in units) result.Add(new UnitInfoDto { Id = unit.Id, Name = unit.Name ?? string.Empty, Title = unit.Title ?? string.Empty }); return result; } public async Task GetOneCompact(ObjectId id) { var unit = await unitRepository.FindById(id); var result = new UnitInfoDto { Id = unit?.Id, Name = unit?.Name ?? string.Empty, Title = unit?.Title ?? string.Empty }; return result; } public async Task> GetPaginatedUnits(PaginationFilter filter, bool withPoCs = false) { var result = unitRepository.GetPaginatedUnits(filter); var count = await result.CountDocumentsAsync(); var data = await result.Skip((filter.PageNumber - 1) * filter.PageSize) .Limit(filter.PageSize) .ToListAsync(); if (withPoCs && data.Any()) { var unitIds = data.Select(u => u.Id).ToList(); var allPocsForUnits = await pointOfCareService.FindAllByUnitIds(unitIds); foreach (var unit in data) unit.PointOfCares = allPocsForUnits.Where(poc => poc.UnitId == unit.Id).ToList(); } return new PaginationResponse(data, filter.PageNumber, filter.PageSize, count); } // public Task GetByPointOfCare(PointOfCare pointOfCare) // { // return _unitRepository.FindByPointOfCare(pointOfCare); // } public async Task GetInfo(ObjectId id, LocaleEnum? dataLocale, bool fillLists = true, bool withPoCs = false) { var unit = await Get(id.ToString()) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); //if (unit == null )// || unit.PointOfCares == null tiene sentido? //{ // _logger.LogError("Section not found: {id}", id); // return null; //} if (fillLists) { if (unit.AltableOptionListId.HasValue) unit.AltableOptionList = await masterListServiceFactory.GetMasterListById(MasterListType.AltableOptionList, unit.AltableOptionListId.Value, dataLocale) as AltableOptionList; if (unit.AllergyListId.HasValue) unit.AllergyList = await masterListServiceFactory.GetMasterListById(MasterListType.AllergyList, unit.AllergyListId.Value, dataLocale) as AllergyList; if (unit.DestinationListId.HasValue) unit.DestinationList = await masterListServiceFactory.GetMasterListById(MasterListType.DestinationList, unit.DestinationListId.Value, dataLocale) as DestinationList; if (unit.InternalDestinationListId.HasValue) unit.InternalDestinationList = await masterListServiceFactory.GetMasterListById(MasterListType.InternalDestinationList, unit.InternalDestinationListId.Value, dataLocale) as InternalDestinationList; if (unit.DiagnosisListId.HasValue) unit.DiagnosisList = await masterListServiceFactory.GetMasterListById(MasterListType.DiagnosisList, unit.DiagnosisListId.Value, dataLocale) as DiagnosisList; if (unit.DischargeStatusListId.HasValue) unit.DischargeStatusList = await masterListServiceFactory.GetMasterListById(MasterListType.DischargeStatusList, unit.DischargeStatusListId.Value, dataLocale) as DischargeStatusList; if (unit.DoctorListId.HasValue) unit.DoctorList = await masterListServiceFactory.GetMasterListById(MasterListType.DoctorList, unit.DoctorListId.Value, dataLocale) as DoctorList; if (unit.DoctorTypeListId.HasValue) unit.DoctorTypeList = await masterListServiceFactory.GetMasterListById(MasterListType.DoctorTypeList, unit.DoctorTypeListId.Value, dataLocale) as DoctorTypeList; if (unit.InsulationListId.HasValue) unit.InsulationList = await masterListServiceFactory.GetMasterListById(MasterListType.InsulationList, unit.InsulationListId.Value, dataLocale) as InsulationList; if (unit.MobilityOptionListId.HasValue) unit.MobilityOptionList = await masterListServiceFactory.GetMasterListById(MasterListType.MobilityOptionList, unit.MobilityOptionListId.Value, dataLocale) as MobilityOptionList; if (unit.OriginListId.HasValue) unit.OriginList = await masterListServiceFactory.GetMasterListById(MasterListType.OriginList, unit.OriginListId.Value, dataLocale) as OriginList; if (unit.PatientStatusListId.HasValue) unit.PatientStatusList = await masterListServiceFactory.GetMasterListById(MasterListType.PatientStatusList, unit.PatientStatusListId.Value, dataLocale) as PatientStatusList; if (unit.ProcedureListId.HasValue) unit.ProcedureList = await masterListServiceFactory.GetMasterListById(MasterListType.ProcedureList, unit.ProcedureListId.Value, dataLocale) as ProcedureList; if (unit.TestListId.HasValue) unit.TestList = await masterListServiceFactory.GetMasterListById(MasterListType.TestList, unit.TestListId.Value, dataLocale) as TestList; if (unit.ServiceListId.HasValue) unit.ServiceList = await masterListServiceFactory.GetMasterListById(MasterListType.ServiceList, unit.ServiceListId.Value, dataLocale) as ServiceList; if (unit.TherapeuticCeilingListId.HasValue) unit.TherapeuticCeilingList = await masterListServiceFactory.GetMasterListById(MasterListType.TherapeuticCeilingList, unit.TherapeuticCeilingListId.Value, dataLocale) as TherapeuticCeilingList; if (unit.TreatmentListId.HasValue) unit.TreatmentList = await masterListServiceFactory.GetMasterListById(MasterListType.TreatmentList, unit.TreatmentListId.Value, dataLocale) as TreatmentList; if (unit.VisitOptionListId.HasValue) unit.VisitOptionList = await masterListServiceFactory.GetMasterListById(MasterListType.VisitOptionList, unit.VisitOptionListId.Value, dataLocale) as VisitOptionList; if (unit.AccessControlListId.HasValue) unit.AccessControlList = await masterListServiceFactory.GetMasterListById(MasterListType.AccessControlList, unit.AccessControlListId.Value, dataLocale) as AccessControlList; if (unit.LanguageBarrierListId.HasValue) unit.LanguageBarrierList = await masterListServiceFactory.GetMasterListById(MasterListType.LanguageBarrierList, unit.LanguageBarrierListId.Value, dataLocale) as LanguageBarrierList; if (unit.PassiveSittingListId.HasValue) unit.PassiveSittingList = await masterListServiceFactory.GetMasterListById(MasterListType.PassiveSittingList, unit.PassiveSittingListId.Value, dataLocale) as PassiveSittingList; if (unit.GenericListId.HasValue) unit.GenericList = await masterListServiceFactory.GetMasterListById(MasterListType.GenericList, unit.GenericListId.Value, dataLocale) as GenericList; } if (withPoCs) { var pocList = await pointOfCareService.FindAllByUnitId(unit.Id); unit.PointOfCares = pocList?.ToList(); } return unit; } public async Task GetInfo(ObjectId id, bool withPoCs = true, bool withDevices = true) { var unit = await Get(id.ToString()) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); if (withPoCs) { var pocList = await pointOfCareService.FindAllByUnitIdWithDevices(unit.Id); unit.PointOfCares = pocList?.ToList(); } return unit; } public async Task GetByName(string itemUnitName) { return await unitRepository.FindByName(itemUnitName) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); } public async Task FindByPatientId(ObjectId patientId) { //var sections = await GetAll(); var patient = await patientService.Value.FindById(patientId); // if (patient != null && !string.IsNullOrEmpty(patient.Bed) && patient.IsInActivePoC()) // { // // Deberia ser una lista? revisar como gestionar varias unidades con eel mismo pointOfCare // return sections.FirstOrDefault(s => s.PointOfCares.Any(c=>c.Bed==patient.Bed && c.UnitName == patient.UnitString)); // } if (patient is { UnitId: not null }) return await FindById(patient.UnitId); throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); } public async Task?> FindUnitsByMasterListId(ObjectId masterListId, MasterListType masterListType) { try { var result = await unitRepository.FindByMasterListId(masterListId, masterListType); return result; } catch (Exception ex) { Log.Error("Exception finding by MasterId{id} section exception:{e} ", masterListId, ex.Message); return null; } } public async Task CountUnitsByMasterListId(ObjectId masterListId, MasterListType masterListType) { return await unitRepository.CountUnitsByMasterListId(masterListId, masterListType); } public async Task> FindUnitsByMasterListId(ObjectId masterListId) { try { var result = await unitRepository.FindByMasterListId(masterListId); return result; } catch (Exception ex) { Log.Error("Exception finding by MasterId{id} section exception:{e} ", masterListId, ex.Message); return new List(); } } public async Task UpdateUnitMasterList(UpdateUnitIdListDto updateUnitListDto) { var unit = await FindById(updateUnitListDto.UnitId) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); var updatedUnit = await unitRepository.UpdateUnitMasterList(updateUnitListDto) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, unit, updatedUnit); return updatedUnit; } public async Task UpdateConfiguration(ObjectId unitIdParsed, UnitConfiguration unitConfiguration) { var oldConfig = await FindById(unitIdParsed) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); var result = await unitRepository.UpdateConfiguration(unitIdParsed, unitConfiguration); var newConfig = await FindById(unitIdParsed) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); if (!result) throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldConfig, newConfig); return result; } public async Task FindById(ObjectId? id) { if (id == null) return null; return await unitRepository.FindById(id); } public async Task FindByName(string? name) { if (string.IsNullOrEmpty(name)) return null; return await unitRepository.FindByName(name); } public async Task FindByUnitNameOrPocName(string? name, string? pocName) { if (!string.IsNullOrEmpty(name)) return await unitRepository.FindByName(name); if (!string.IsNullOrEmpty(pocName)) { var poc = await pointOfCareService.FindByBed(pocName); if (poc != null) return await FindById(poc.FirstOrDefault()?.UnitId); } return null; } // public async Task FindByPointOfCare(PointOfCare pointOfCare) // { // return await _unitRepository.FindByPointOfCare(pointOfCare); // } public async Task InsertOne(Unit unit) { var newUnit = await unitRepository.InsertOneUnit(unit) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictCreationFailed); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, newUnit); return newUnit; } public async Task UpdateUnit(Unit unit) { var oldUnit = await FindById(unit.Id) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); var newUnit = await unitRepository.UpdateUnit(unit); if (newUnit == null) return null; await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldUnit, newUnit); SendUnitBroadcast(newUnit, OperationType.UpdateUnit); return newUnit; } public async Task UpdateUnitInfo(ObjectId unitId, string name, string title, string? configObsId = null) { var oldUnit = await FindById(unitId) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); var newUnit = await unitRepository.UpdateUnitInfo(unitId, name, title) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldUnit, newUnit); if (newUnit != null) SendUnitBroadcast(newUnit, OperationType.UpdateUnit); return newUnit; } public async Task DeleteUnitById(Unit unit) { //if (unit is not { Status: null }) throw new ConflictException(ErrorMessage.Conflict_ResourceInUse); _ = await unitRepository.DeleteAsync(unit.Id) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, unit, null); return true; } public async Task Get(string id) { Unit? section = null; if (ObjectId.TryParse(id, out var oid)) section = await FindById(oid); var sections = await GetAll(); section ??= sections.FirstOrDefault(s => s.Title == id); section ??= sections.FirstOrDefault(s => s.Name == id); return section; } public async Task?> FindByLocation(PatientLocation location) { try { var sections = await GetAll(); // Cambiar por comparacion con Location? return sections.Where(section => section.PointOfCares != null && section.PointOfCares.Any(c => c.Bed == location.Bed && c.UnitName == location.UnitName)).ToList(); } catch (Exception e) { Log.Error("Exception finding by location section exception:{e} location: {location} ", e.Message, location); return null; } } private async void SendUnitBroadcast(Unit unit, OperationType operation) { try { var locations = new List(); var pocs = await pointOfCareService.FindAllByUnitId(unit.Id); if (pocs == null) return; locations.AddRange(pocs.Select(c => c.Id)); var subscribers = subscribersService.GetSubscribers() .Where(s => s.LocationIds.Any(id => locations.Contains(id))) .ToList(); foreach (var subscriber in subscribers) _ = clientMessageService.Value.SendAsync(subscriber.Id, operation, unit); } catch (Exception e) { logger.LogError( "Error sending Unit Broadcast {unit} with operation type {operationToString()} message: {eMessage}", unit, operation.ToString(), e.Message); } } }