using adas_core.Application.Services.Interfaces; using adas_core.Domain.Models; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.Pumps; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MongoDB.Bson; namespace adas_core.Application.Services; /// /// Implements the contract, providing a service for working with calculated observations. /// /// public class CalculatedObservationsService : ICalculatedObservationsService { private static ICalculatedObservations? _service; private readonly ILogger? _logger; /// /// Initializes a new instance of the , resolving the internal implementation from the configured customization or falling back to . /// /// The providing the customization name used to locate the calculation implementation type. /// The supplied to the resolved customization type's constructor. /// The used to log warnings when the customization cannot be resolved. /// public CalculatedObservationsService( IOptions apiSettings, IServiceProvider serviceProvider, ILogger logger) { _logger = logger; var customize = apiSettings.Value.Customize; if (customize == null) { _logger.LogWarning("Not customization specified"); _service = new DefaultCalculatedObservations(); return; } var calculatedObservations = "adas_core.Application.Customizations." + customize + ".CalculatedObservations"; if (string.IsNullOrEmpty(customize)) { _service = new DefaultCalculatedObservations(); } else { var type = Type.GetType(calculatedObservations); if (type == null) { _logger.LogWarning( $"Type {calculatedObservations} not found for specification. Using DefaultCalculatedObservations"); _service = new DefaultCalculatedObservations(); return; } var ctor = Type.GetType(calculatedObservations)?.GetConstructor([typeof(IServiceProvider)]); if (ctor == null) { _logger.LogWarning( $"Constructor not found for type {calculatedObservations} accepts one parameter with type IServiceProvider. Using DefaultCalculatedObservations"); _service = new DefaultCalculatedObservations(); return; } _service = (ICalculatedObservations)ctor.Invoke([serviceProvider]); } } /// /// Maps a by delegating to the configured mapping service. /// If no service is available, the original observation is returned unchanged; if the service produces no mapping, a debug message is logged and null is returned. /// /// The patient observation to map. /// When true, restricts the mapping to lookups by name only. /// The mapped , or null when the service yields no result; the input is returned unchanged when no mapping service is configured. /// public virtual async Task Map(PatientObservation obs, bool onlyByName = false) { if (_service == null) return obs; var result = await _service.Map(obs, onlyByName); if (result == null) _logger?.LogDebug("Mapping calculated via service {serviceFullName}. {obs} Ignored", _service.GetType().FullName, obs); return result; } /// /// Maps a using the configured mapping service. Falls back to returning the original alarm unchanged when no service is available, and logs a debug entry when the service produces a null result (i.e., the alarm is ignored). /// /// The patient observation alarm to be mapped. /// When true, restricts the mapping to a name-based lookup only. /// The mapped , or null if the service mapped it to null, or the original when no service is configured. /// public virtual async Task Map(PatientObservationAlarm obs, bool onlyByName = false) { if (_service == null) return obs; var result = await _service.Map(obs, onlyByName); if (result == null) _logger?.LogDebug("Mapping calculated via service {serviceFullName}. {obs} Ignored", _service.GetType().FullName, obs); return result; } /// /// Maps the supplied by delegating to the configured mapping service. /// Returns when the underlying service has not been initialized. /// /// The pump observation to be mapped. /// A task that yields the mapped , or if no mapping service is available. /// public virtual async Task Map(PumpObservation obs) { if (_service == null) return null; var result = await _service.Map(obs); return result; } /// /// Maps a using the configured mapping service. Falls back to returning the original alert when no service is configured, and logs a debug entry when the service produces no mapping. /// /// The instance to be mapped. /// The mapped , the original if no service is available, or null if the service returned no result. /// public async Task Map(PatientRecordingAlert obs) { if (_service == null) return obs; var result = await _service.Map(obs); if (result == null) _logger?.LogDebug("Mapping calculated via service {serviceFullName}. {obs} Ignored", _service.GetType().FullName, obs); return result; } /// /// Asynchronously maps a using the underlying service. If the service is unavailable (null), the original treatment is returned unchanged as a fallback. /// /// The patient treatment instance to be mapped or transformed. /// A task that represents the asynchronous mapping operation, containing the mapped or null if the service returns no result. /// public async Task Map(PatientTreatment treatment) { if (_service == null) return treatment; var result = await _service.Map(treatment); return result; } /// /// Maps a by delegating to the configured mapping service. If no service is available, the original is returned as a fallback. /// /// The patient diagnosis to be mapped. /// A task that yields the mapped , or null if the underlying service returns no result. /// public virtual async Task Map(PatientDiagnosis diagnosis) { if (_service == null) return diagnosis; var result = await _service.Map(diagnosis); return result; } /// /// Asynchronously calculates medicine observations for a patient based on their active medicines. /// Delegates the calculation to the underlying service if it has been initialized; otherwise, the call is silently skipped. /// /// The list of medicines currently active for the patient. /// The unique identifier of the patient whose medicine observations are being calculated. /// public virtual async Task CalculateMedicineObservation(List activeMedicines, ObjectId patientId) { if (_service != null) await _service.CalculateMedicineObservation(activeMedicines, patientId); } /// /// Asynchronously calculates the active bolus dosage of opiates for the specified patient by delegating to the underlying service. /// If the service dependency is not initialized, the call is skipped silently as a no-op fallback. /// /// The unique identifier of the patient for whom the active bolus opiates calculation is performed. /// public async Task CalculateBolusOpiates(ObjectId patientId) { if (_service != null) await _service.CalculateActiveBolus(patientId); } /// /// Retrieves the active treatments associated with the specified patient. /// If the underlying service is not available, returns an empty list as a fallback instead of throwing. /// /// The unique identifier of the patient whose active treatments should be retrieved. /// A task that yields the collection of active entries for the patient, or an empty list when the service is unavailable. /// public virtual async Task> GetActiveTreatmentsByPatient(ObjectId id) { if (_service != null) return await _service.GetActiveTreatmentsByPatient(id); return new List(); } /// /// Maps a list of patient observations by delegating to the configured service's pre-mapping logic when available; otherwise, returns an empty list. /// /// The list of patient observations to be mapped. /// A task containing the mapped list of patient observations, or an empty list if no service is configured. /// public virtual async Task> MapList(List listToInsert) { if (_service != null) return await _service.PreMapList(listToInsert); return []; } /// /// Maps a source alarm onto the given patient observation by delegating to the configured service when available; if no service is configured, returns the original observation unchanged. /// /// The patient observation onto which the source alarm will be mapped. /// The source alarm to be applied to the observation. /// The produced by the service mapping, or the original when no service is configured. /// public virtual async Task MapSourceAlarm(PatientObservation observation, PatientObservationAlarm observationAlarm) { if (_service != null) return await _service.MapSourceAlarm(observation, observationAlarm); return observation; } }