using System.Collections;
using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.GroupedObservations;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Utils;
namespace adas_core.Application.Services;
///
/// Provides a demo implementation of that coordinates observation handling using for configuration and a of for deferred alarm access.
///
///
/// The service is constructed with an for observation configuration and a lazily-initialized so that alarm functionality is created only on first use.
///
///
public class ObservationDemoService(
IConfigObservationService configObservationService,
Lazy alarmService)
: IObservationDemoService
{
///
/// Generates a list of patient observation alarms based on the provided alarm fields, randomly skipping fields and skipping those with no matching configuration.
///
/// The patient to associate with the generated alarms.
/// The list of fields used to look up alarm configurations and produce alarms.
/// A task that represents the asynchronous operation, containing the list of mapped instances that were successfully resolved.
public async Task> GenerateAlarmByField(Patient patient, List dataAlarmfields)
{
var listToReturn = new List();
foreach (var field in dataAlarmfields)
{
var sendingRandom = new Random();
if (sendingRandom.Next(0, 2) == 0 || string.IsNullOrEmpty(field.Name))
continue;
var firstCof = await configObservationService.GetConfigObservationItemsByName(field.Name);
var conf = firstCof.FirstOrDefault();
if (conf == null)
continue;
var alarmObs = new PatientObservationAlarm
{
Patient = patient,
PatientId = patient.Id,
AlarmConfig = conf.Alarm,
InactivationState = new InactivationState
{
Audio = AlarmEnum.AudioVideoState.Enabled,
Acknowledge = true,
Visual = AlarmEnum.AudioVideoState.Enabled
},
EventPhase = AlarmEnum.EventPhase.Continue,
Type = AlarmEnum.ObservationAlarmType.Sp,
Expires = conf.Expires,
State = AlarmEnum.ObservationAlarmState.Active,
Time = DateTime.UtcNow,
Persist = false,
MessageTime = DateTime.UtcNow,
Code = conf.Code,
PriorityLevel = conf.DemoConfig?.PriorityAlarm,
Name = conf.Name,
ParentData = new ParentDataClass
{
Code = conf.ParentCode,
Name = conf.ParentName,
CodingSystem = conf.CodingSystem
},
Units = conf.Units,
Value = GenerateValueRandom(conf, null) ?? 0
};
var obs = await alarmService.Value.MapObservationsByName(alarmObs);
if (obs != null)
listToReturn.Add(obs);
}
return listToReturn;
}
///
/// Generates a list of patient observations for the specified patient based on the provided data fields, using the corresponding configuration items to populate observation values, thresholds, and metadata. Fields without a name or without a matching configuration are skipped. When a configuration includes demo settings, the resulting observation is adjusted with a randomized initial date and, if required, an end time.
///
/// The patient to associate the generated observations with.
/// The list of fields used to look up observation configurations and drive observation generation.
/// A task that returns the list of generated instances; entries are omitted when no configuration is found for a field.
public async Task> GenerateObservationByField(Patient patient, List dataFields)
{
var listToReturn = new List();
var rnd = new Random();
foreach (var field in dataFields)
{
if (string.IsNullOrEmpty(field.Name))
continue;
var conf = await configObservationService.GetConfigObservationItemsByName(field.Name);
var firstCof = conf.FirstOrDefault();
if (firstCof == null)
continue;
var patientObs = new PatientObservation
{
Patient = patient,
PatientId = patient.Id,
Max = firstCof.MaxAlert,
Min = firstCof.MinAlert,
MaxWarn = firstCof.MaxWarn,
MinWarn = firstCof.MinWarn,
ShowOnExpired = firstCof.ShowOnExpired,
Expires = firstCof.Expires,
UiConfiguration = firstCof.UiConfiguration,
MessageTime = DateTime.UtcNow,
Code = firstCof.Code,
ColorOnExpired = firstCof.ColorOnExpired,
AlertColor = firstCof.AlertColor,
WarnColor = firstCof.WarnColor,
CodingSystem = firstCof.CodingSystem,
Alarm = firstCof.Alarm,
InsertMode = firstCof.InsertMode,
Name = field.Name,
Time = DateTime.UtcNow,
ParentData = new ParentDataClass
{
Code = firstCof.ParentCode,
Name = firstCof.ParentName,
CodingSystem = firstCof.CodingSystem
},
Units = firstCof.Units,
Value = GenerateValueRandom(firstCof, null) ?? 0
};
var result = await configObservationService.Map(patientObs, true);
if (firstCof.DemoConfig?.RequireInitDate == true && result != null)
{
var rndRestNmbHours = rnd.Next(3, 23);
var initDate = DateTime.UtcNow.AddHours(-rndRestNmbHours);
// Si se requiere fecha de fin, devolvemos un objeto con ambas
if (firstCof.DemoConfig?.RequireEndDate == true)
{
result.Time = initDate;
result.EndTime = initDate.AddHours(1);
}
// Si no, solo devolvemos la fecha inicial
result.Time = initDate;
}
if (result != null)
listToReturn.Add(result);
}
return listToReturn;
}
///
/// Generates a for the given patient and grouped field, producing time-spaced observations for each configured name and result type based on the field's regularity.
///
/// The patient to associate the generated grouped observation with.
/// The grouped field configuration that defines the names, results, regularity, and maximum number of observations to generate.
/// A task that returns the populated containing the generated observations.
public async Task GenerateGroupedObservation(Patient patient, GroupedField groupedField)
{
if (groupedField.Names.IsNullOrEmpty() && groupedField.Name != null) groupedField.Names.Add(groupedField.Name);
var rnd = new Random();
var startTime = DateTime.UtcNow;
var go = new GroupedObservation
{
Name = groupedField.Name,
PatientId = patient.Id,
Group = groupedField.Group,
Observations = []
};
foreach (var groupedFieldName in groupedField.Names)
{
var conf = await configObservationService.GetConfigObservationItemsByName(groupedFieldName);
var firstCof = conf.FirstOrDefault();
if (firstCof == null)
continue;
foreach (var result in groupedField.Result)
{
object? prevValue = null;
for (var i = 0; i <= groupedField.Max; i++)
{
var time = startTime;
time = groupedField.Regularity switch
{
GroupedObservationEnum.Regularity.Day => time.AddDays(-i),
GroupedObservationEnum.Regularity.Minute => time.AddMinutes(-i),
GroupedObservationEnum.Regularity.Second => time.AddSeconds(-i),
_ => time.AddHours(-i)
};
var val = new GroupedObservation.GroupedObservationObs
{
Name = groupedFieldName,
MaxAlert = firstCof?.MaxAlert,
MinAlert = firstCof?.MinAlert,
Time = time,
IsFilled = false
};
var value = new GroupedObservation.GroupedObservationObsValue(
GenerateValueRandom(firstCof, prevValue) ?? rnd.Next(0, 30), time);
prevValue = value.Value;
var propertyInfo = val.GetType().GetProperty(result.ToString());
if (propertyInfo != null && propertyInfo.CanWrite) propertyInfo.SetValue(val, value);
var valueType = await configObservationService.GroupedObservationStatus(
groupedField,
result,
groupedFieldName,
val,
firstCof?.MaxAlert,
firstCof?.MinAlert
);
value.Type = valueType;
go.Observations.Add(
val
);
}
if (firstCof?.DemoConfig?.RequireInitDate.HasValue == true && firstCof.DemoConfig.RequireInitDate.Value)
break;
}
}
return go;
}
///
/// Generates a random value (or list of values) for a given configuration, falling back to "-" when no configuration is available. When the configuration specifies an array, produces multiple random values using the configured count; otherwise returns a single random value.
///
/// The configuration observation whose DemoConfig drives the value generation. If null or its DemoConfig is null, the method returns "-".
/// The previous value, passed through to PickSingleValue as context for the new random value generation.
/// A list of generated values when the configuration indicates an array, or a single generated value otherwise. Null is returned when no value could be picked.
private static object? GenerateValueRandom(ConfigObservation? firstCof, object? prevValue)
{
if (firstCof?.DemoConfig == null)
return "-";
// 1. Determinar cuántos valores necesitamos
var count = firstCof.DemoConfig?.ValueIsArray == true ? firstCof.DemoConfig?.RandomCount ?? 1 : 1;
var results = new List