using adas_core.Application.Customizations.HRYC;
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.MongoModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using Moq;
using Options = Microsoft.Extensions.Options.Options;

namespace adas_core.Test.Customizations.HRYC;

[TestFixture]
public class CalculatedObservationsTest
{
    [SetUp]
    public void Setup()
    {
        _observationServiceMock = new Mock<IObservationService>();

        var observationServiceLazy = new Lazy<IObservationService>(() => _observationServiceMock.Object);


        _patientServiceMock = new Mock<IPatientService>();
        var patientServiceLazy = new Lazy<IPatientService>(() => _patientServiceMock.Object);

        _lightBeaconServiceMock = new Mock<ILightBeaconService>();
        var lightBeaconServiceLazy = new Lazy<ILightBeaconService>(() => _lightBeaconServiceMock.Object);


        var listAlertNewsObsConfig = new List<ConfigObservation>
        {
            new()
            {
                Name = "Alarm_NEWS_ALERT",
                Alarm = new AlarmConfig { Enabled = true, Beacon = new AlarmItem { Enabled = true, Color = "RED" } }
            },
            new()
            {
                Name = "Alarm_NEWS_OFF",
                Alarm = new AlarmConfig { Enabled = true, Beacon = new AlarmItem { Enabled = true, Color = "NONE" } }
            },
            new()
            {
                Name = "Alarm_NEWS_WARNING",
                Alarm = new AlarmConfig { Enabled = true, Beacon = new AlarmItem { Enabled = true, Color = "YELLOW" } }
            }
        };
        _configObservationServiceMock = new Mock<IConfigObservationService>();
        _configObservationServiceMock
            .Setup(x => x.Get(It.IsAny<PatientObservation>(), It.IsAny<bool>()))
            .ReturnsAsync((PatientObservation patientObservation, bool _) =>
            {
                // Busca el elemento en la lista que coincida con la propiedad "Name" recibida como parámetro
                var configItem = listAlertNewsObsConfig.FirstOrDefault(c => c.Name == patientObservation.Name);

                // Si se encuentra el elemento, devuélvelo; de lo contrario, devuelve null
                return configItem;
            });
        _optionsApiSettings = Options.Create(_apiSettings);

        _logger = new Mock<ILogger<CalculatedObservations>>();

        _optionsApiSettings.Value.HighFrequencyVentilation = _highFrequencyVentilationValues;
        _optionsApiSettings.Value.InvasiveVentilation = _invasiveVentilationValues;
        _optionsApiSettings.Value.NonInvasiveVentilation = _nonInvasiveVentilationValues;

        var serviceCollection = new ServiceCollection();
        serviceCollection.AddSingleton(observationServiceLazy);
        serviceCollection.AddSingleton(patientServiceLazy);
        serviceCollection.AddSingleton(lightBeaconServiceLazy);
        serviceCollection.AddSingleton(_configObservationServiceMock.Object);
        serviceCollection.AddSingleton(_optionsApiSettings);
        serviceCollection.AddSingleton(_logger.Object);

        var serviceProvider = serviceCollection.BuildServiceProvider();

        _calculatedObservations = new CalculatedObservations(serviceProvider);

        _patientId = ObjectId.GenerateNewId();
        _patientPocId = ObjectId.GenerateNewId();
        _patientUnitId = ObjectId.GenerateNewId();
        _patient = new Patient { Id = _patientId, UnitId = _patientUnitId, PointOfCareId = _patientPocId };
        _patientServiceMock.Setup(m => m.FindById(_patientId, It.IsAny<bool>()))
            .ReturnsAsync(_patient);
    }

    private CalculatedObservations _calculatedObservations;
    private Mock<IObservationService> _observationServiceMock;
    private Mock<IPatientService> _patientServiceMock;
    private Mock<ILightBeaconService> _lightBeaconServiceMock;
    private Mock<IConfigObservationService> _configObservationServiceMock;
    private Mock<ILogger<CalculatedObservations>> _logger;

    private readonly ApiSettings _apiSettings = new()
    {
        ConfigObservation = new ConfigObservationSettings
        {
            IgnoreUnknownObservation = false
        }
    };

    private IOptions<ApiSettings> _optionsApiSettings;

    private readonly List<string> _highFrequencyVentilationValues = ["HNF"];
    private readonly List<string> _nonInvasiveVentilationValues = ["BIPAP", "CPAP"];
    private readonly List<string> _invasiveVentilationValues = [];
    private ObjectId _patientId = ObjectId.GenerateNewId();
    private ObjectId _patientPocId = ObjectId.GenerateNewId();
    private ObjectId _patientUnitId = ObjectId.GenerateNewId();
    private Patient _patient;

    [Test]
    public async Task Calculate_CheckBeaconOnNEWS_Should_Send_PowerOff()
    {
        var observation = new PatientObservation
        {
            Name = "NEWS",
            CodingSystem = "ADAS",
            Expires = 15,
            Value = 4,
            PatientId = _patientId,
            Time = DateTime.Now
        };
        var obsConfig = new ConfigObservation
        {
            Name = "Alarm_NewsOff",
            Alarm = new AlarmConfig
            {
                Enabled = true,
                Beacon = new AlarmItem
                {
                    Enabled = true,
                    BeaconColor = AlarmEnum.BeaconColor.None
                }
            }
        };

        _configObservationServiceMock.Setup(c => c.Get(It.IsAny<PatientObservation>(), false))
            .ReturnsAsync(obsConfig);

        await _calculatedObservations.Map(observation, false);
        _lightBeaconServiceMock.Verify(
            x => x.SendColor(It.Is<ObjectId>(l => l.Equals(_patient.PointOfCareId)), LightBeaconColor.Off),
            Times.Once);
    }

    [Test]
    public async Task Calculate_CheckBeaconOnNEWS_Should_Send_Yellow()
    {
        var observation = new PatientObservation
        {
            Name = "NEWS",
            CodingSystem = "ADAS",
            Expires = 15,
            Value = 6,
            PatientId = _patientId,
            Time = DateTime.Now
        };
        var obsConfig = new ConfigObservation
        {
            Name = "Alarm_NewsWarning",
            Alarm = new AlarmConfig
            {
                Enabled = true,
                Beacon = new AlarmItem
                {
                    Enabled = true,
                    BeaconColor = AlarmEnum.BeaconColor.Yellow
                }
            }
        };

        _configObservationServiceMock.Setup(c => c.Get(It.IsAny<PatientObservation>(), false))
            .ReturnsAsync(obsConfig);

        await _calculatedObservations.Map(observation, false);
        _lightBeaconServiceMock.Verify(
            x => x.SendColor(It.Is<ObjectId>(l => l.Equals(_patient.PointOfCareId)),
                LightBeaconColor.Yellow), Times.Once);
    }

    [Test]
    public async Task Calculate_CheckBeaconOnNEWS_Should_Send_Red()
    {
        var observation = new PatientObservation
        {
            Name = "NEWS",
            CodingSystem = "ADAS",
            Expires = 15,
            Value = 8,
            PatientId = _patientId,
            Time = DateTime.Now
        };

        var obsConfig = new ConfigObservation
        {
            Name = "Alarm_NewsAlert",
            Alarm = new AlarmConfig
            {
                Enabled = true,
                Beacon = new AlarmItem
                {
                    Enabled = true,
                    BeaconColor = AlarmEnum.BeaconColor.Red
                }
            }
        };

        _configObservationServiceMock.Setup(c => c.Get(It.IsAny<PatientObservation>(), false))
            .ReturnsAsync(obsConfig);

        await _calculatedObservations.Map(observation, false);
        _lightBeaconServiceMock.Verify(
            x => x.SendColor(It.Is<ObjectId>(l => l.Equals(_patient.PointOfCareId)), LightBeaconColor.Red),
            Times.Once);
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_FR_Returns_NEWS_EXTR_HI_Resp_Rate()
    {
        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = _patientId,
            Value = 90,
            Name = "FR"
        };

        var observationVent = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = _patientId,
            Value = 90,
            Name = "Vent_Rat"
        };

        var observationSpo2 = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = _patientId,
            Value = 90,
            Name = "SpO2"
        };

        var observationFiO2 = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = _patientId,
            Value = 90,
            Name = "FiO2"
        };

        _observationServiceMock
            .Setup(l => l.FindLastObservations(_patientId, 1, new List<string> { "Vent_Rate" }))
            .ReturnsAsync([observationVent]);
        _observationServiceMock
            .Setup(l => l.FindLastObservations(_patientId, 1, new List<string> { "FiO2", "SpO2" }))
            .ReturnsAsync([observationSpo2, observationFiO2]);

        await _calculatedObservations.Map(observation, false);
        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "NEWS_EXTR_HI_Resp_Rate" &&
            arg.CodingSystem == "ADAS" &&
            arg.Value.ToString() == "90"
        ), true, true));
    }

    [Test]
    public async Task Calculate_FR_Does_Not_Returns_NEWS_EXTR_HI_Resp_Rate_When_Invalid_Value()
    {
        var patientId = ObjectId.GenerateNewId();

        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = "90a",
            Name = "FR"
        };

        var observationVent = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 90,
            Name = "Vent_Rat"
        };

        var observationSpo2 = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 90,
            Name = "SpO2"
        };

        var observationFiO2 = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 90,
            Name = "FiO2"
        };

        _observationServiceMock
            .Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "Vent_Rate" }))
            .ReturnsAsync([observationVent]);

        _observationServiceMock
            .Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "FiO2", "SpO2" }))
            .ReturnsAsync([observationSpo2, observationFiO2]);

        Func<Task> act = () => _calculatedObservations.Map(observation, false);

        Assert.ThrowsAsync<FormatException>(act);
    }


    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_FR_Returns_NEWS_HI_Resp_Rate()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 23,
                Name = "FR"
            };

            var observationVent = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 90,
                Name = "Vent_Rat"
            };

            var observationSpo2 = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 90,
                Name = "SpO2"
            };

            var observationFiO2 = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 90,
                Name = "FiO2"
            };

            _observationServiceMock
                .Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "Vent_Rate" }))
                .ReturnsAsync([observationVent]);
            _observationServiceMock
                .Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "FiO2", "SpO2" }))
                .ReturnsAsync([observationSpo2, observationFiO2]);

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_HI_Resp_Rate" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "23"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_FR_Returns_NEWS_EXTR_LO_Resp_Rate()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 7,
                Name = "FR"
            };

            var observationVent = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 90,
                Name = "Vent_Rat"
            };

            var observationSpo2 = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 90,
                Name = "SpO2"
            };

            var observationFiO2 = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 90,
                Name = "FiO2"
            };

            _observationServiceMock
                .Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "Vent_Rate" }))
                .ReturnsAsync([observationVent]);
            _observationServiceMock
                .Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "FiO2", "SpO2" }))
                .ReturnsAsync([observationSpo2, observationFiO2]);

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_EXTR_LO_Resp_Rate" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "7"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_SpO2_Returns_NEWS_EXTR_LO_SpO2()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 90,
                Name = "SpO2"
            };

            var observationFr = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 90,
                Name = "FR"
            };

            _observationServiceMock
                .Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "FiO2", "FR" }))
                .ReturnsAsync([observation, observationFr]);


            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_EXTR_LO_SpO2" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "90"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_SpO2_Returns_NEWS_LO_SpO2()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 93,
                Name = "SpO2"
            };

            var observationFr = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 90,
                Name = "FR"
            };

            _observationServiceMock
                .Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "FiO2", "FR" }))
                .ReturnsAsync([observation, observationFr]);


            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_LO_SpO2" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "93"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_Temperature_Returns_NEWS_EXTR_LO_Temperature()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 30,
                Name = "Temperature"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_EXTR_LO_Temperature" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "30"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_Temperature_Returns_NEWS_HI_Temperature()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 40,
                Name = "Temperature"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_HI_Temperature" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "40"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_TAs_Returns_NEWS_EXTR_LO_TAs()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 80,
                Name = "TAs"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_EXTR_LO_TAs" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "80"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_TAs_Returns_NEWS_LO_TAs()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 95,
                Name = "TAs"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_LO_TAs" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "95"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_TAs_Returns_NEWS_EXTR_HI_TAs()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 240,
                Name = "TAs"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_EXTR_HI_TAs" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "240"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_FC_Returns_NEWS_EXTR_LO_FC()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 20,
                Name = "FC"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_EXTR_LO_FC" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "20"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_FC_Returns_NEWS_EXTR_HI_FC()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 140,
                Name = "FC"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_EXTR_HI_FC" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "140"
            ), true, true));
        }
    }

    [Ignore("old NEWS calc")]
    [Test]
    public async Task Calculate_FC_Returns_NEWS_HI_FC()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 120,
                Name = "FC"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
                arg.Name == "NEWS_HI_FC" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == "120"
            ), true, true));
        }
    }

    [Test]
    public async Task Check_MDC_VENT_RESP_RATE_IsInsertedBefore_And_RemoveFromList()
    {
        var patientId = ObjectId.GenerateNewId();
        var now = DateTime.Now;

        var listObsToOrder = new List<PatientObservation>
        {
            new()
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 7,
                Code = "151586",
                CodingSystem = "MDC",
                Name = "MDC_VENT_RESP_RATE",
                Time = now
            },
            new()
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 113,
                ParentData = new ParentDataClass
                {
                    Code = "69965",
                    CodingSystem = "MDC",
                    Name = "MDC_DEV_MON_PHYSIO_MULTI_PARAM_MDS"
                },
                Code = "151562",
                CodingSystem = "MDC",
                Name = "MDC_RESP_RATE",
                Time = now
            },
            new()
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = 11,
                ParentData = new ParentDataClass
                {
                    Code = "69965",
                    CodingSystem = "MDC",
                    Name = "MDC_DEV_MON_PHYSIO_MULTI_PARAM_MDS"
                },
                Code = "150456",
                CodingSystem = "MDC",
                Name = "MDC_PULS_OXIM_SAT_O2",
                Time = now
            }
        };

        var orderedList = await _calculatedObservations.PreMapList(listObsToOrder);
        Assert.That(orderedList.All(obs => obs.Name != "MDC_VENT_RESP_RATE"), Is.True);
        _observationServiceMock.Verify(o => o.InsertObservation(
            It.Is<PatientObservation>(obs =>
                obs.Code != null &&
                obs.Code == "151586"), true, true), Times.Once);
    }

    [Test]
    public async Task
        Check_Insert_Resp_Rate_Calculated_HasTimePlusOneSecond_And_Resp_Rate_Calculated_HasVentRateAsParent()
    {
        var patientId = ObjectId.GenerateNewId();
        var now = DateTime.Now;
        var nowPlusOneSecond = now.AddSeconds(1);

        var ventRate = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 7,
            Code = "151586",
            CodingSystem = "MDC",
            Name = "Vent_Rate",
            Time = now
        };
        var fr = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 113,
            ParentData = new ParentDataClass
            {
                Code = "69965",
                CodingSystem = "MDC",
                Name = "MDC_DEV_MON_PHYSIO_MULTI_PARAM_MDS"
            },
            Code = "151562",
            CodingSystem = "MDC",
            Name = "FR",
            Time = now
        };
        _observationServiceMock.Setup(o => o.FindLastObservations(patientId, 1, It.IsAny<List<string>>()))
            .ReturnsAsync([ventRate]);

        await _calculatedObservations.Map(ventRate, false);
        await _calculatedObservations.Map(fr, false);

        _observationServiceMock.Verify(o => o.InsertObservation(
            It.Is<PatientObservation>(obs =>
                obs.ParentData != null &&
                obs.ParentData.Name == "Vent_Rate" &&
                obs.Time == nowPlusOneSecond), true, true), Times.Once);
    }

    [Test]
    public async Task Calculate_Ventilation_Mode_Should_Return_INVASIVE()
    {
        var patientId = ObjectId.GenerateNewId();


        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = "PC-AC",
            Name = "Resp_Mode"
        };

        await _calculatedObservations.Map(observation, false);
        _observationServiceMock.Verify(o => o.InsertIfChanged("Resp_Type", It.Is<PatientObservation>(arg =>
            arg.Name == "Resp_Type" &&
            arg.CodingSystem == "ADAS" &&
            arg.Value.ToString() == RespirationType.Invasive.ToString()
        ), true, true));
    }

    [Test]
    public async Task Calculate_Ventilation_Mode_Should_Return_NON_INVASIVE()
    {
        {
            var patientId = ObjectId.GenerateNewId();

            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = _nonInvasiveVentilationValues[0].Trim(),
                Name = "Resp_Mode"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertIfChanged("Resp_Type", It.Is<PatientObservation>(arg =>
                arg.Name == "Resp_Type" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == RespirationType.NonInvasive.ToString()
            ), true, true));
        }
    }

    [Test]
    public async Task Calculate_Ventilation_Mode_Should_Return_HIGH_FREQUENCY()
    {
        {
            var patientId = ObjectId.GenerateNewId();


            var observation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientId,
                Value = _highFrequencyVentilationValues[0].Trim(),
                Name = "Resp_Mode",
                Code = "HNF"
            };

            await _calculatedObservations.Map(observation, false);
            _observationServiceMock.Verify(o => o.InsertIfChanged("Resp_Type", It.Is<PatientObservation>(arg =>
                arg.Name == "Resp_Type" &&
                arg.CodingSystem == "ADAS" &&
                arg.Value.ToString() == RespirationType.HighFrequencyVentilation.ToString()
            ), true, true));
        }
    }

    //[Test]
    //public void CalculateCam_Icu_Received_1_Return_Positivo() 
    //{
    //    var patientId = ObjectId.GenerateNewId();
    //    var now = DateTime.Now;


    //    var observation = new PatientObservation
    //    {
    //        id = ObjectId.GenerateNewId(),
    //        patientid = patientId,
    //        value = 1,
    //        name = "Cam_Icu"
    //    };

    //    calculatedObservations.Map(observation, false);

    //    observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
    //            arg.name == "Cam_IcuCalculated" &&
    //            arg.codingSystem == "ADAS" &&
    //            arg.value.ToString() == "Positivo"
    //        ), true, true));

    //}

    //[Test]
    //public void CalculateCam_Icu_Received_0_Return_Negativo()
    //{
    //    var patientId = ObjectId.GenerateNewId();
    //    var now = DateTime.Now;


    //    var observation = new PatientObservation
    //    {
    //        id = ObjectId.GenerateNewId(),
    //        patientid = patientId,
    //        value = 0,
    //        name = "Cam_Icu"
    //    };

    //    calculatedObservations.Map(observation, false);

    //    observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
    //            arg.name == "Cam_IcuCalculated" &&
    //            arg.codingSystem == "ADAS" &&
    //            arg.value.ToString() == "Negativo"
    //        ), true, true));

    //}

    //[Test]
    //public void CalculateCam_Icu_Received_different_0_1_Return_Value_null()
    //{
    //    var patientId = ObjectId.GenerateNewId();
    //    var now = DateTime.Now;


    //    var observation = new PatientObservation
    //    {
    //        id = ObjectId.GenerateNewId(),
    //        patientid = patientId,
    //        value=2,
    //        name = "Cam_Icu"
    //    };

    //    calculatedObservations.Map(observation, false);

    //    observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
    //            arg.name == "Cam_IcuCalculated" &&
    //            arg.codingSystem == "ADAS" &&
    //            arg.value==null
    //        ), true, true));

    //}

    //[Test]
    //public void CalculateCam_Icu_Received_null_Return_Value_null()
    //{
    //    var patientId = ObjectId.GenerateNewId();
    //    var now = DateTime.Now;


    //    var observation = new PatientObservation
    //    {
    //        id = ObjectId.GenerateNewId(),
    //        patientid = patientId,                
    //        name = "Cam_Icu"
    //    };

    //    calculatedObservations.Map(observation, false);

    //    observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
    //            arg.name == "Cam_IcuCalculated" &&
    //            arg.codingSystem == "ADAS" &&
    //            arg.value == null
    //        ), true, true));

    //}

    [Test]
    public async Task CalculateDiuresis_Weight_Received_D_3924_W_90_Return_43_6()
    {
        var patientId = ObjectId.GenerateNewId();

        var patientObservation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 90,
            Name = "Weight_Current"
        };

        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 3924,
            Name = "Diuresis"
        };

        _observationServiceMock.Setup(o => o.FindLastObservations(patientId, 1, It.IsAny<List<string>>()))
            .ReturnsAsync([patientObservation]);

        await _calculatedObservations.Map(observation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Diuresis_Weight" &&
            arg.PatientId == patientId &&
            Math.Abs((double)arg.Value - 43.6) < 0.1
        ), true, true));
    }

    [Test]
    public async Task CalculateDiuresis_Weight_D_3924_Receive_W_90_Return_43_6()
    {
        var patientId = ObjectId.GenerateNewId();

        var patientObservation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 3924,
            Name = "Diuresis"
        };

        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 90,
            Name = "Weight_Current"
        };

        _observationServiceMock.Setup(o => o.FindLastObservations(patientId, 1, It.IsAny<List<string>>()))
            .ReturnsAsync([patientObservation]);

        await _calculatedObservations.Map(observation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Diuresis_Weight" &&
            arg.PatientId == patientId &&
            Math.Abs((double)arg.Value - 43.6) <= 0
        ), true, true));
    }

    [Test]
    public async Task CalculateDiuresis_Weight_Received_W_90_D_Null_Return_Nothing()
    {
        var patientId = ObjectId.GenerateNewId();

        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 90,
            Name = "Weight_Current"
        };

        _observationServiceMock.Setup(o => o.FindLastObservations(patientId, 1, It.IsAny<List<string>>()))
            .ReturnsAsync([]);

        await _calculatedObservations.Map(observation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.IsAny<PatientObservation>(), true, true),
            Times.Never);
    }

    [Test]
    public async Task CalculateDiuresis_Weight_Received_D_3924_W_Null_Return_Nothing()
    {
        var patientId = ObjectId.GenerateNewId();

        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = 3924,
            Name = "Diuresis"
        };

        _observationServiceMock.Setup(s => s.FindLastObservations(It.IsAny<ObjectId>(), 1, It.IsAny<List<string>>()))
            .ReturnsAsync([]);

        await _calculatedObservations.Map(observation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Diuresis_Weight" &&
            arg.PatientId == patientId
        ), true, true), Times.Never);
    }

    [Test]
    public async Task CalculateAllergiesObservation_Received_AllergiesObs_Emty_Return_Allergies_Emty()
    {
        var patientId = ObjectId.GenerateNewId();

        List<PatientAllergiesValue> patientAllergiesValues = [];

        var patientObservation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = patientAllergiesValues,
            Name = "AllergiesObs"
        };

        await _calculatedObservations.Map(patientObservation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Allergies" &&
            arg.PatientId == patientId &&
            (string)arg.Value == string.Empty
        ), true, true));
    }

    [Test]
    public async Task CalculateAllergiesObservation_Received_AllergiesObs_Without_Farmacos_Return_Allergies()
    {
        var patientId = ObjectId.GenerateNewId();

        List<PatientAllergiesValue> patientAllergiesValues =
        [
            new()
            {
                Type = "Latex",
                Value = "Si",
                Notes = ""
            },

            new()
            {
                Type = "Alergia ambiental",
                Value = "Estacional",
                Notes = "epitelio de perro, mezcla de gramíneas salvajes,"
            }
        ];


        var patientObservation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = patientAllergiesValues,
            Name = "AllergiesObs"
        };

        await _calculatedObservations.Map(patientObservation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Allergies" &&
            arg.PatientId == patientId &&
            (string)arg.Value == "LATEX, AMBIENTAL"
        ), true, true));
    }

    [Test]
    public async Task CalculateAllergiesObservation_Received_AllergiesObs_With_1_Farmacos_Return_Allergies()
    {
        var patientId = ObjectId.GenerateNewId();

        List<PatientAllergiesValue> patientAllergiesValues =
        [
            new()
            {
                Type = "Alergia a fármacos",
                Value = "METILPREDNISOLONA",
                Notes = "Tolera dexametasona y actocortina"
            },

            new()
            {
                Type = "Latex",
                Value = "Si",
                Notes = ""
            },

            new()
            {
                Type = "Alergia ambiental",
                Value = "Estacional",
                Notes = "epitelio de perro, mezcla de gramíneas salvajes,"
            }
        ];


        var patientObservation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = patientAllergiesValues,
            Name = "AllergiesObs"
        };

        await _calculatedObservations.Map(patientObservation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Allergies" &&
            arg.PatientId == patientId &&
            (string)arg.Value == "LATEX, AMBIENTAL, FÁRMACOS (METILPREDNISOLONA)"
        ), true, true));
    }

    [Test]
    public async Task CalculateAllergiesObservation_Received_AllergiesObs_With_2_Farmacos_Return_Allergies()
    {
        var patientId = ObjectId.GenerateNewId();

        List<PatientAllergiesValue> patientAllergiesValues =
        [
            new()
            {
                Type = "Alergia a fármacos",
                Value = "METILPREDNISOLONA",
                Notes = "Tolera dexametasona y actocortina"
            },

            new()
            {
                Type = "Latex",
                Value = "Si",
                Notes = ""
            },

            new()
            {
                Type = "Alergia a fármacos",
                Value = "Penicilina/cefalosporinas"
            },

            new()
            {
                Type = "Alergia ambiental",
                Value = "Estacional",
                Notes = "epitelio de perro, mezcla de gramíneas salvajes,"
            }
        ];


        var patientObservation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Value = patientAllergiesValues,
            Name = "AllergiesObs"
        };

        await _calculatedObservations.Map(patientObservation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Allergies" &&
            arg.PatientId == patientId &&
            (string)arg.Value == "LATEX, AMBIENTAL, FÁRMACOS (METILPREDNISOLONA, PENICILINA/CEFALOSPORINAS)"
        ), true, true));
    }

    [Test]
    public async Task Calculate_Drainages_Received_volume_60_height_8_Return_DVE_height()
    {
        var patientId = ObjectId.GenerateNewId();


        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Name = "DrainagesObs",
            Value = new PatientDrainagesValue
            {
                Type = "Drenaje ventricular",
                Volume = 60,
                Height = 8
            }
        };

        await _calculatedObservations.Map(observation, false);
        int valueParsed;

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "DVE" &&
            arg.CodingSystem == "ADAS" &&
            arg.PatientId == patientId &&
            int.TryParse(arg.Value.ToString(), out valueParsed) && valueParsed == 60
        ), true, true));

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Drainage_Height" &&
            arg.CodingSystem == "ADAS" &&
            arg.PatientId == patientId &&
            int.TryParse(arg.Value.ToString(), out valueParsed) && valueParsed == 8
        ), true, true));
    }

    [Test]
    public async Task Calculate_Drainages_Received_volume_60_height_null_Return_DVE()
    {
        var patientId = ObjectId.GenerateNewId();


        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Name = "DrainagesObs",
            Value = new PatientDrainagesValue
            {
                Type = "Drenaje ventricular",
                Volume = 60
            }
        };

        await _calculatedObservations.Map(observation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "DVE" &&
            arg.CodingSystem == "ADAS" &&
            arg.PatientId == patientId &&
            int.Parse(arg.Value.ToString()!) == 60
        ), true, true));

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Drainage_Height" &&
            arg.CodingSystem == "ADAS" &&
            arg.PatientId == patientId
        ), true, true), Times.Never);
    }

    [Test]
    public async Task Calculate_Drainages_Received_volume_null_height_8_Return_height()
    {
        var patientId = ObjectId.GenerateNewId();


        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Name = "DrainagesObs",
            Value = new PatientDrainagesValue
            {
                Type = "Drenaje ventricular",
                Height = 8
            }
        };

        await _calculatedObservations.Map(observation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "DVE" &&
            arg.CodingSystem == "ADAS" &&
            arg.PatientId == patientId
        ), true, true), Times.Never);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Drainage_Height" &&
            arg.CodingSystem == "ADAS" &&
            arg.PatientId == patientId &&
            int.Parse(arg.Value.ToString()!) == 8
        ), true, true));
    }

    [Test]
    public async Task Calculate_Drainages_Received_volume_null_height_null_Return_nothing()
    {
        var patientId = ObjectId.GenerateNewId();


        var observation = new PatientObservation
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = patientId,
            Name = "DrainagesObs",
            Value = new PatientDrainagesValue
            {
                Type = "Drenaje ventricular"
            }
        };

        await _calculatedObservations.Map(observation, false);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "DVE" &&
            arg.CodingSystem == "ADAS" &&
            arg.PatientId == patientId
        ), true, true), Times.Never);

        _observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
            arg.Name == "Drainage_Height" &&
            arg.CodingSystem == "ADAS" &&
            arg.PatientId == patientId
        ), true, true), Times.Never);
    }
}