using adas_core.Application.Exceptions; using adas_core.Application.Repositories.Interfaces; using adas_core.Application.Services.Interfaces; using adas_core.Application.Subscriptions; using adas_core.Domain.Enums; using adas_core.Domain.Models.DTO.Display; using adas_core.Domain.Models.Filter; using adas_core.Domain.Models.GroupedObservations; using adas_core.Domain.Models.MongoModels; using adas_core.Domain.Models.Responses; using adas_core.Domain.Utils; using Microsoft.AspNetCore.Http; using MongoDB.Bson; using MongoDB.Driver; using Newtonsoft.Json; using Serilog; using DisplayConfig = adas_core.Domain.Models.MongoModels.DisplayConfig; namespace adas_core.Application.Services; public class DisplayConfigService( IDisplayConfigRepository displayConfigRepository, Lazy displayService, ISubscribersService subscribersService, IClientMessageService clientMessageService, IHttpContextAccessor httpContextAccessor, ILocalAuditService auditService, IMasterListServiceFactory masterListServiceFactory, IDisplayCardConfigRepository displayCardConfigRepository, IDisplayDetailConfigRepository displayDetailConfigRepository, IDisplayChartConfigRepository displayChartRepository) : IDisplayConfigService { public async Task> GetAll() { var result = await displayConfigRepository.GetAll(); var resultToReturn = new List(); foreach (var config in result) { var c = await AddDisplaySectionMinimal(config); if (c != null) resultToReturn.Add(c); } return resultToReturn; } public async Task> GetAllCompactPaginated(PaginationFilter filter) { var result = displayConfigRepository.GetAllPaginated(filter); var count = await result.CountDocumentsAsync(); var resultToReturn = new List(); var data = await result.Skip((filter.PageNumber - 1) * filter.PageSize) .Limit(filter.PageSize) .ToCursorAsync(); var dataList = await data.ToListAsync(); foreach (var config in dataList) { var isInUse = await displayService.Value.IsDisplayConfigInUse(config.Id); resultToReturn.Add(new DisplayConfigMinimalResponse(config, isInUse)); } return new PaginationResponse(resultToReturn, filter.PageNumber, filter.PageSize, count); } public async Task> GetByType(DisplayConfigEnums.DisplayType type) { var result = await displayConfigRepository.GetByType(type); var resultToReturn = new List(); foreach (var config in result) { var c = await AddDisplaySectionMinimal(config); if (c != null) resultToReturn.Add(c); } return resultToReturn; } public async Task GetById(ObjectId id) { return await AddDisplaySectionMinimal(await displayConfigRepository.GetById(id)) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); } public async Task GetById(ObjectId? configId, ObjectId unitId, DisplayConfigEnums.DisplayType displayType) { if (configId.HasValue) { DisplayConfig? currentConfig; DisplayConfig? defaultConfig; try { currentConfig = await GetById(configId.Value); } catch (NotFoundException) { currentConfig = null; } try { defaultConfig = await GetDefaultByUnitIdAndType(unitId, displayType); } catch (NotFoundException) { defaultConfig = null; } if (defaultConfig != null && currentConfig != null) return currentConfig.MergeConfig(defaultConfig); return defaultConfig ?? currentConfig; } return await GetDefaultByUnitIdAndType(unitId, displayType); } public async Task InsertOne(DisplayConfig config) { await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, config); return await displayConfigRepository.InsertOneAsyncAndReturn(config); } public async Task InsertOneMinimal(CreateDisplayConfigDto config) { DisplayConfig newDisplayConfig; if (config.Type == DisplayConfigEnums.DisplayType.DisplayNurse) newDisplayConfig = new DisplayNurse { Hospital = config.Hospital, Type = config.Type }; else newDisplayConfig = new DisplayConfig { Hospital = config.Hospital, Type = config.Type }; newDisplayConfig.Id = ObjectId.GenerateNewId(); var result = await displayConfigRepository.InsertOneAsyncAndReturn(newDisplayConfig); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, newDisplayConfig); return result; } public async Task InsertOneTest() { var d = new DisplayNurse { Type = DisplayConfigEnums.DisplayType.DisplayNurse }; await displayConfigRepository.InsertOneAsyncAndReturn(d); var e = new SmartDisplay { Type = DisplayConfigEnums.DisplayType.SmartDisplay }; await displayConfigRepository.InsertOneAsyncAndReturn(e); return d; } public async Task UpdateConfig(ObjectId displayConfigId, object newDisplayConfig) { var baseType = JsonConvert.DeserializeObject(newDisplayConfig.ToString()!); // var cardConfigUpdate = await UpdateDisplayCardConfig(displayConfigId, baseType); var oldDisplayConfig = await displayConfigRepository.GetById(displayConfigId); switch (baseType!.Type) { case DisplayConfigEnums.DisplayType.SmartDisplay: var smartConfigToReturn = await displayConfigRepository.UpdateSmartDisplay(displayConfigId, JsonConvert.DeserializeObject(newDisplayConfig.ToString()!)); if (smartConfigToReturn != null) { // smartConfigToReturn.CardConfig = cardConfigUpdate; SendSmartDisplayConfigBroadcast(displayConfigId, smartConfigToReturn, oldDisplayConfig as SmartDisplay); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldDisplayConfig, newDisplayConfig); return smartConfigToReturn; } break; case DisplayConfigEnums.DisplayType.DisplayNurse: var obsNurseList = masterListServiceFactory.StringNurseObs(); var displayConfigUpdate = JsonConvert.DeserializeObject(newDisplayConfig.ToString()!); var nurseConfigToReturn = await displayConfigRepository.UpdateDisplayNurse(displayConfigId, displayConfigUpdate, obsNurseList); if (nurseConfigToReturn != null) { // nurseConfigToReturn.CardConfig = cardConfigUpdate; SendDisplayConfigBroadcast(displayConfigId, OperationType.UpdateDisplayConfig, nurseConfigToReturn); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldDisplayConfig, nurseConfigToReturn); return nurseConfigToReturn; } break; default: throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundNoMatches); } throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); } public Task UpdateFieldList(ObjectId objectIdConfigDisplay, List fields) { return displayConfigRepository.UpdateFieldList(objectIdConfigDisplay, fields); } public async Task UpdateConfigColor(ObjectId objectIdConfigDisplay, ColorConfig colorConfig) { var oldDisplayConfig = await displayConfigRepository.GetById(objectIdConfigDisplay) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); if (oldDisplayConfig.ColorConfig == null) { oldDisplayConfig.ColorConfig = new ColorConfig(); await displayConfigRepository.UpdateOneAsync(objectIdConfigDisplay, oldDisplayConfig); } var result = await displayConfigRepository.UpdateConfigColor(objectIdConfigDisplay, colorConfig); var newDisplayConfig = await displayConfigRepository.GetById(objectIdConfigDisplay) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldDisplayConfig, newDisplayConfig); return result; } public async Task UpdateHeaderConfig(ObjectId objectIdConfigDisplay, HeaderConfig headerConfig) { var oldDisplayConfig = await displayConfigRepository.GetById(objectIdConfigDisplay) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); var result = await displayConfigRepository.UpdateHeaderConfig(objectIdConfigDisplay, headerConfig); var newDisplayConfig = await displayConfigRepository.GetById(objectIdConfigDisplay) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldDisplayConfig, newDisplayConfig); return result; } public async Task UpdateSetHomeBanner(ObjectId objectIdConfigDisplay, List bannerItems) { var oldDisplayConfig = await displayConfigRepository.GetById(objectIdConfigDisplay) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); var result = await displayConfigRepository.UpdateSetHomeBanner(objectIdConfigDisplay, bannerItems); var newDisplayConfig = await displayConfigRepository.GetById(objectIdConfigDisplay) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldDisplayConfig, newDisplayConfig); return result; } public async Task UpdateBaseConfig(DisplayConfig baseConfig) { var oldDisplayConfig = await displayConfigRepository.GetById(baseConfig.Id) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); var result = await displayConfigRepository.UpdateBaseConfig(baseConfig.Id, baseConfig); var newDisplayConfig = await displayConfigRepository.GetById(baseConfig.Id) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldDisplayConfig, newDisplayConfig); return result; } public async Task UpdateDisplayConfigHospitalName(ObjectId objectIdConfigDisplay, string name) { var oldDisplayConfig = await displayConfigRepository.GetById(objectIdConfigDisplay) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); var result = await displayConfigRepository.UpdateDisplayConfigHospitalName(objectIdConfigDisplay, name); var newDisplayConfig = await displayConfigRepository.GetById(objectIdConfigDisplay) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldDisplayConfig, newDisplayConfig); return result; } public async Task DeleteDisplayConfig(ObjectId objectIdConfigDisplay) { var displays = await displayService.Value.GetByConfigId(objectIdConfigDisplay); if (displays.Count > 0) { var type = displays.First().Type; var defaultConfig = await GetDefaultConfig(type) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed); foreach (var display in displays) _ = await displayService.Value.UpdateConfigId(display, defaultConfig.Id) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed); } var result = await displayConfigRepository.DeleteDisplayConfig(objectIdConfigDisplay); if (result != null) { await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, result, null); return true; } return false; } public async Task> GetDisplayConfigLocations(ObjectId objectIdConfigDisplay) { return await displayService.Value.GetDisplayConfigLocations(objectIdConfigDisplay); } public async Task> GetAllCompact() { return await displayConfigRepository.GetAllCompact(); } public async Task InsertOneWithTemplate(string objectId, DisplayConfigEnums.DisplayType configType, string? configHospital) { if (ObjectId.TryParse(objectId, out var objectIdConfigDisplay)) { var template = await GetById(objectIdConfigDisplay); switch (configType) { case DisplayConfigEnums.DisplayType.StandarDisplay: if (template is StandarDisplay standardTemplate) { var standarConfigg = new StandarDisplay { Hospital = configHospital, Type = DisplayConfigEnums.DisplayType.StandarDisplay }; standarConfigg.MergeConfig(standardTemplate); await InsertOne(standarConfigg); return standarConfigg; } break; case DisplayConfigEnums.DisplayType.DisplayNurse: if (template is DisplayNurse nurseTemplate) { var nurseConfig = new DisplayNurse { Hospital = configHospital, Type = DisplayConfigEnums.DisplayType.DisplayNurse }; nurseConfig.MergeConfig(nurseTemplate); await InsertOne(nurseConfig); return nurseConfig; } break; case DisplayConfigEnums.DisplayType.SmartDisplay: if (template is SmartDisplay smartTemplate) { var smartConfig = new SmartDisplay { Hospital = configHospital, Type = DisplayConfigEnums.DisplayType.DisplayNurse }; smartConfig.MergeConfig(smartTemplate); await InsertOne(smartConfig); return smartConfig; } break; default: return null; } } return null; } public async Task UpdateCardConfig(CardConfig baseConfig) { var result = await displayCardConfigRepository.UpdateOne(baseConfig); if (result.Changes > 0) { var displayConfigs = await displayConfigRepository.GetAllByCardConfigIdAndRotating(baseConfig.Id); foreach (var displayConfig in displayConfigs) { await displayConfigRepository.UpdateDisplayNurse(displayConfig, new DisplayNurseDto() { CardConfig = result.Data }, masterListServiceFactory.StringNurseObs()); } var displays = await displayConfigRepository.GetAllByCardConfigId(baseConfig.Id); foreach (var display in displays) SendDisplayConfigBroadcast(display, OperationType.UpdateCardDisplayConfig, result.Data); return true; } return false; } public async Task UpdateDetailConfig(CardDetailsConfig baseConfig) { var result = await displayDetailConfigRepository.UpdateOne(baseConfig); var displays = await displayConfigRepository.GetAllByCardDetailConfigId(baseConfig.Id); foreach (var display in displays) SendDisplayConfigBroadcast(display, OperationType.UpdateDetailDisplayConfig, result.Data); if (result.Changes > 0) return true; return false; } public async Task UpdateChartConfig(ChartConfig baseConfig) { var result = await displayChartRepository.UpdateOne(baseConfig); if (result.Changes > 0) return true; return false; } public async Task DeleteChartConfig(ObjectId objectIdConfigDisplay) { var res = await displayChartRepository.DeleteOne(objectIdConfigDisplay); if (res != null) { await UpdateDeletedChartConfig(objectIdConfigDisplay); return true; } return false; } public async Task GetChartConfig(ObjectId objectIdConfigChart) { return await displayChartRepository.GetById(objectIdConfigChart); } public async Task InsertCardDetailConfig(CreateDisplayConfigCardDto updateDisplayConfigNameDto) { if (updateDisplayConfigNameDto.DetailConfig == null) return null; var result = await displayDetailConfigRepository.InsertOneAsyncAndReturn(updateDisplayConfigNameDto.DetailConfig); if (updateDisplayConfigNameDto.DisplayConfigId != null && result != null) { var res = await UpdateDetailConfigId(updateDisplayConfigNameDto.DisplayConfigId, result.Id); if (res) SendDisplayConfigBroadcast(updateDisplayConfigNameDto.DisplayConfigId.Value, OperationType.UpdateDetailDisplayConfig, result); } return result; } public async Task InsertChartConfig(CreateDisplayConfigCardDto updateDisplayConfigNameDto) { if (updateDisplayConfigNameDto.ChartConfig == null) return null; var result = await displayChartRepository.InsertOneAsyncAndReturn(updateDisplayConfigNameDto.ChartConfig); if (updateDisplayConfigNameDto.DisplayConfigId != null && result != null) { var res = await AddChartId(updateDisplayConfigNameDto.DisplayConfigId, result.Id); if (res) SendDisplayConfigBroadcast(updateDisplayConfigNameDto.DisplayConfigId.Value, OperationType.UpdateChartConfig, result); } return result; } public async Task InsertCardConfig(CreateDisplayConfigCardDto updateDisplayConfigNameDto) { if(updateDisplayConfigNameDto.CardConfig == null) return null; var result = await displayCardConfigRepository.InsertOneAsyncAndReturn(updateDisplayConfigNameDto.CardConfig); if (updateDisplayConfigNameDto.DisplayConfigId != null && result != null) { var res = await UpdateCardConfigId(updateDisplayConfigNameDto.DisplayConfigId, result.Id); if (res) SendDisplayConfigBroadcast(updateDisplayConfigNameDto.DisplayConfigId.Value, OperationType.UpdateDetailDisplayConfig, result); } return result; } public async Task> GetCardConfigAll() { return await displayCardConfigRepository.GetAll(); } public async Task GetCardConfigById(ObjectId id) { return await displayCardConfigRepository.GetById(id); } public async Task GetDefaultConfig(DisplayConfigEnums.DisplayType type) { return await displayConfigRepository.GetDefault(type); } private async Task GetDefaultByUnitIdAndType(ObjectId unitId, DisplayConfigEnums.DisplayType displayType) { return await displayConfigRepository.GetDefaultByUnitIdAndType(unitId, displayType); //?? throw new NotFoundException(ErrorMessage.NotFound_ResourceMissing); } private async Task AddDisplaySectionMinimal(DisplayConfig? displayConfig) { if (displayConfig == null) return null; var displayConfigAux = displayConfigRepository.GetById(displayConfig.Id) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); if (displayConfig.Type == DisplayConfigEnums.DisplayType.SmartDisplay && !displayConfig.DisplaySectionIdList.IsNullOrEmpty()) { foreach (var displayId in displayConfig.DisplaySectionIdList) { var d = await displayService.Value.GetById(displayId); if (d != null) { var minimalDisplay = new MinimalDisplaySection { Id = displayId, Name = d.Name }; displayConfig.DisplaySectionList.Add(minimalDisplay); } } await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, displayConfigAux, displayConfig); } return displayConfig; } private async Task UpdateDeletedChartConfig(ObjectId deletedId) { await displayConfigRepository.UpdateDeletedChartConfig(deletedId); } private async Task AddChartId(ObjectId? displayConfigId, ObjectId resultId) { var result = await displayConfigRepository.AddChartId(displayConfigId, resultId); return result; } private async Task UpdateCardConfigId(ObjectId? displayConfigId, ObjectId? resultId) { var result = await displayConfigRepository.UpdateCardConfigId(displayConfigId, resultId); return result; } private async Task UpdateDetailConfigId(ObjectId? displayConfigId, ObjectId? resultId) { var result = await displayConfigRepository.UpdateDetailConfigId(displayConfigId, resultId); return result; } private async void SendDisplayConfigBroadcast(ObjectId displayConfigId, OperationType operationType, object? newDisplayConfig) { try { var listDisplayId = await displayService.Value.GetByConfigId(displayConfigId); var listDisplayIdList = listDisplayId.Select(c => c.Id).ToList(); var subscribers = subscribersService.GetSubscribers().Where(s => s.DisplayId != null && listDisplayIdList.Contains((ObjectId)s.DisplayId)).ToList(); foreach (var sub in subscribers) _ = clientMessageService.SendAsync(sub.Id, operationType, newDisplayConfig); } catch (Exception e) { Log.Error("Error sending update for DisplayNurse config: {message}", e.Message); //throw new ConflictException(ErrorMessage.Conflict_UpdateFailed, e); } } private async void SendSmartDisplayConfigBroadcast(ObjectId displayConfigId, SmartDisplay? newDisplayConfig, SmartDisplay? oldDisplayConfig) { try { var listDisplayId = await displayService.Value.GetByConfigId(displayConfigId); var listDisplayIdList = listDisplayId.Select(c => c.Id).ToList(); var subscribers = subscribersService.GetSubscribers().Where(s => s.DisplayId != null && listDisplayIdList.Contains((ObjectId)s.DisplayId)).ToList(); if (newDisplayConfig != null && oldDisplayConfig != null) SendSmartDisplayConfigUpdate(subscribers, oldDisplayConfig, newDisplayConfig); else Log.Error("Error sending update for SmartDisplay config config is null"); } catch (Exception e) { Log.Error("Error sending update for SmartDisplay config: {message}", e.Message); //throw new ConflictException(ErrorMessage.Conflict_UpdateFailed, e); } finally { // Enviar un mensaje a todos los clientes para que actualicen la configuraci�n del display var displayConfig = await displayConfigRepository.GetById(displayConfigId); if (displayConfig != null) _ = clientMessageService.SendToAllAsync(OperationType.UpdateDisplayConfig, displayConfig); } } private void SendSmartDisplayConfigUpdate(List subscribers, SmartDisplay? oldDisplayDisplayConfig, SmartDisplay? newDisplayDisplayConfig) { // Obtener las propiedades que han cambiado var differentProperties = oldDisplayDisplayConfig?.GetDifferentProperties(newDisplayDisplayConfig); // Enviar un mensaje a los clientes por cada propiedad que haya cambiado if (differentProperties != null) foreach (var property in differentProperties) foreach (var sub in subscribers) _ = clientMessageService.SendAsync(sub.Id, OperationType.UpdateDisplayConfig, newDisplayDisplayConfig?.GetType().GetProperty(property)?.GetValue(newDisplayDisplayConfig)); } }