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;
}
}