using adas_core.Application.Exceptions; using adas_core.Application.Services.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.MongoModels; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MongoDB.Bson; using Serilog; using Patient = adas_core.Domain.Models.MongoModels.Patient; namespace adas_core.Application.Services; public class AdminPanelService( IOptions apiSettings, IPatientService patientService, IConfigObservationService configObservationService, IMedicineService medicineService, IPointOfCareService pocService, IUnitService unitService, ILogger logger, IAdmissionService admissionService, IAuthService authService, IDischargeService dischargeService, IDisplayService displayService) : IAdminPanelService { private readonly List _defaultIdRecord = apiSettings.Value.DefaultIdRecord ?? []; #region Patient public async Task ArchivePatient(Patient patient) { try { await patientService.ArchivePatient(patient); logger.LogDebug("archived patientid {patientid} from ADMPanel", patient.Id); return true; } catch (Exception e) { Console.WriteLine(e); throw; } } public async Task CreatePatient(AdmPanelRequest admRequest) { var patient = new Patient { Id = ObjectId.GenerateNewId() }; await UpdateNewPatient(patient, admRequest); await patientService.Insert(patient); logger.LogDebug("Inserted {patientid} from ADMPanel", patient.Id); return patient; } private async Task UpdateNewPatient(Patient patient, AdmPanelRequest admRequest) { if (!string.IsNullOrEmpty(admRequest.PatientNumber)) patient.PatientNumber = admRequest.PatientNumber; if (admRequest.AdmTime.HasValue) patient.AdmTime = admRequest.AdmTime; if (admRequest.Patient != null && !admRequest.Patient.IsEmptyDontCheckIds()) patient.Person = admRequest.Patient; if (admRequest.Patient != null && (admRequest.Patient.Ids == null || admRequest.Patient.Ids.Count == 0)) { if (patient.Person is { Ids: null }) patient.Person.Ids = new Dictionary(); foreach (var item in _defaultIdRecord) patient.Person?.Ids?.Add(item, admRequest?.PatientNumber ?? "null"); } patient.Person?.SetIds(patient.Person?.Ids ?? new Dictionary()); if (admRequest is { UnitId: not null }) { var unit = await unitService.FindById(admRequest.UnitId); patient.UnitId = unit?.Id ?? admRequest.UnitId; patient.UnitString = unit?.Name; if (admRequest is { PointOfCareId: not null }) { //El paciente existe en la localizacion no te dejo insertarlo var patientInLocation = await patientService.FindByPointOfCareId(admRequest.PointOfCareId.Value); if (patientInLocation != null) { logger.LogError( "trying to insert patientid {patientid} in to location already in use. PointOfcareId: {poc}", patient.Id, patient.PointOfCareId); throw new Exception($"patient already in location: {patient.Location}"); } var poc = await pocService.FindById(admRequest.PointOfCareId.Value); if (poc == null) { logger.LogError( "trying to insert patientid {patientid} in to location not found. PointOfcareId: {poc}", patient.Id, admRequest.PointOfCareId); throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); } await pocService.SetPointOfCareStatus(poc.Id, StatusEnum.PointOfCare.InUse); patient.Location = new PatientLocation ( bed: poc.Bed, room: poc.Room, unitName: unit?.Name ); patient.PointOfCareId = poc.Id; } else { var pocUnknown = await pocService.FindByBedAndUnitId(VirtualPointOfCare.Unknown.ToString(), patient.UnitId); patient.PointOfCareId = pocUnknown?.Id; } patient.UpdateDate = DateTime.UtcNow; } } public async Task FindPatientById(ObjectId id) { return await patientService.FindById(id) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); } public async Task FindPatientByLocation(PatientLocation location) { return await patientService.FindByLocation(location); } public async Task FindPatientByPatientNumber(string patientNumber) { return await patientService.FindByPatientNumber(patientNumber); } public async Task UpdatePatientData(AdmPanelRequest request, Patient oldPatient) { //traer el paciente que se quiere actualizar con los valores que tenga en la base de datos a una variable //actualizar unicamente los campos que tengan que ver con los datos del paciente if (request.PatientNumber == null || request.Patient == null || request.Patient.IsEmptyDontCheckIds()) { logger.LogError("Patient Data not updated. Old Patient:{oldPatient}. Api Request {request}", oldPatient, request); throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); } var patientNumberChanged = oldPatient.PatientNumber != request.PatientNumber; await patientService.UpdatePatientData(oldPatient.Id, request.PatientNumber, request.Patient, patientNumberChanged); return true; } public async Task UpdatePatientLocation(AdmPanelRequest request) { var patient = await patientService.FindByLocation(request.OldLocation); var patientExistsInLocation = await patientService.FindByLocation(request.Location); //Si ya hay un paciente en esa localización if (patientExistsInLocation != null) //Si hay un paciente distinto en la nueva localización movemos al anterior if (patient != null && patientExistsInLocation.PatientNumber != patient.PatientNumber) await patientService.UpdateLocation(patientExistsInLocation.Id, new PatientLocation(VirtualPointOfCare.Pushed.ToString(), ObjectId.GenerateNewId().ToString())); if (patient != null) { if (request.Location?.Bed == null || string.IsNullOrEmpty(request.Location.Bed)) request.Location = new PatientLocation(VirtualPointOfCare.Pushed.ToString(), ObjectId.GenerateNewId().ToString()); //to solve problems when empty beds with not scapped "" request.Location.Bed = request.Location?.Bed?.Replace("\"", ""); await patientService.UpdateLocation(patient.Id, request.Location); patient = await patientService.FindById(patient.Id); if (patient != null) await patientService.Update(patient); } else { patient = new Patient { Id = ObjectId.GenerateNewId() }; await patientService.Insert(patient); } return true; } public async Task FindPatient(AdmPanelRequest request) { var findByLocation = !request.Location?.IsFullEmpty(); return await patientService.FindPatient(request.PatientId, request.PatientNumber, request.Location, findByLocation ?? false) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); } public async Task FindByLocation(PatientLocation location) { return await patientService.FindByLocation(location) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); } #endregion #region ConfigObservations public async Task CreateConfig(ConfigObservation configObservation) { _ = await configObservationService.CreateConfig(configObservation) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictCreationFailed); return true; } public async Task UpdateConfig(ConfigObservation configObservation) { _ = await configObservationService.UpdateConfig(configObservation) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); return true; } public async Task DeleteConfigObservationItem(ObjectId id) { _ = await configObservationService.RemoveConfigItem(id) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed); return true; } #endregion #region Unit public async Task InsertUnit(Unit unit) { //Insertamos la unidad y creamos los PoCs por defecto para esa unidad var result = await unitService.InsertOne(unit); if (result != null) { // Por cada valor del enum VirtualPointOfCare, creamos un PointOfCare asociado a la unidad foreach (var pocEnum in Enum.GetValues(typeof(VirtualPointOfCare)).Cast()) { var poc = new PointOfCare { UnitId = result.Id, Status = StatusEnum.PointOfCare.Available, Room = pocEnum.ToString(), Bed = pocEnum.ToString() }; var insertedPoc = await pocService.InsertPointOfCare(poc); if (insertedPoc != null) { result.PointOfCareIds ??= []; result.PointOfCareIds.Add(insertedPoc.Id); } } // Actualizamos la unidad con los nuevos PointOfCareIds await unitService.UpdateUnit(result); } return result; } public async Task GetUnitDependencyDto(Unit unit) { try { return new UnitInfoDto(unit) { Admissions = await admissionService.CountAdmissionsByUnitId(unit.Id), Discharges = await dischargeService.CountDischargesByUnitId(unit.Id), Displays = await displayService.CountDisplaysByUnitId(unit.Id), Patients = await patientService.CountPatientsByUnitId(unit.Id), PointOfCares = await pocService.CountPoCsByUnitId(unit.Id), VirtualPointOfCares = await pocService.CountVirtualPoCsByUnitId(unit.Id) }; } catch (Exception e) { logger.LogError(e.Message); return null; } } public async Task DeleteUnitById(ObjectId unitId) { try { var unit = await unitService.FindById(unitId); if (unit == null) throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); //No se puede borrar una unidad que est� en uso var patients = await patientService.CountPatientsByUnitId(unitId); if (patients > 0) //Si tiene pacientes no se permite borrado throw new ConflictException(HttpEnum.ErrorMessage.ConflictResourceInUse); //Borramos admisiones await admissionService.DeleteAdmissionsByUnitId(unitId); //discharges await dischargeService.DeleteDischargesByUnitId(unitId); //Borramos Authorizations await authService.DeleteByUnitId(unitId); //Displays await displayService.DeleteDisplaysByUnitId(unitId); //PointOfCares await pocService.DeletePoCsByUnitId(unitId); //Una vez borrados los recursos asociados a la unidad, borramos la unidad await unitService.DeleteUnitById(unit); return true; } catch (Exception e) { Log.Error(e.Message); return false; } } #endregion #region Medicine public async Task GetMedicineById(ObjectId medicineId) { return await medicineService.GetMedicineById(medicineId) ?? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing); } public async Task PostMedicine(Medicine medicine) { var newMedicine = await medicineService.PostMedicine(medicine) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictCreationFailed); return newMedicine; } public async Task UpdateMedicine(Medicine medicine) { var updatedMedicine = await medicineService.UpdateMedicine(medicine) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed); return updatedMedicine; } public async Task DeleteMedicineById(string medicineId) { if (!ObjectId.TryParse(medicineId, out var objectId)) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat); await medicineService.DeleteMedicineById(objectId); _ = await medicineService.GetMedicineById(ObjectId.Parse(medicineId)) ?? throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed); return true; } #endregion }