using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.GroupedObservations;
using adas_core.Domain.Models.MongoModels;
using adas_core.Infrastructure.Repositories;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
using Moq;
using static NUnit.Framework.Is;
using static adas_core.Domain.Enums.GroupedObservationEnum;
using Options = Microsoft.Extensions.Options.Options;

namespace adas_core.Test.Repositories;

[TestFixture]
[Order(1)]
[Category("Integration")]
public class ObservationRepositoryTest
{
    /// <summary>
    /// One-time setup that initializes the integration test environment for the <see cref="ObservationRepository"/>.
    /// Resets the <c>patients_observations</c> collection, creates the repository with mocked logging and configured API settings,
    /// and seeds it with six <see cref="PatientObservation"/> records covering different codes, coding systems, and timestamps
    /// (including observations without a <c>SystemId</c>).
    /// </summary>
    [OneTimeSetUp]
        public async Task Init()
        {
            _optionsApiSettings = Options.Create(_apiSettings);
    
            var patientObservation1 = new PatientObservation
            {
                Id = Id,
                PatientId = PatientId,
                Code = "code1",
                CodingSystem = "SNM",
                Name = "name1",
                Status = StatusEnum.Type.Ok,
                Time = Now,
                Value = "value1",
                SystemId = "systemId1"
            };
    
            var patientObservation2 = new PatientObservation
            {
                PatientId = PatientId,
                Code = "code2",
                CodingSystem = "MDC",
                Name = "name2",
                Status = StatusEnum.Type.Ok,
                Time = Now,
                Value = "value2"
            };
    
            var patientObservation3 = new PatientObservation
            {
                PatientId = PatientId,
                Code = "code1",
                CodingSystem = "SNM",
                Name = "name1",
                Status = StatusEnum.Type.Ok,
                Time = Now.AddDays(-1),
                Value = "value3",
                SystemId = "systemId1"
            };
    
            var patientObservation4 = new PatientObservation
            {
                PatientId = PatientId,
                Code = "code2",
                CodingSystem = "MDC",
                Name = "name2",
                Status = StatusEnum.Type.Ok,
                Time = Now.AddDays(-1),
                Value = "value4"
            };
    
            var patientObservation5 = new PatientObservation
            {
                PatientId = PatientId,
                Code = "code1",
                CodingSystem = "SNM",
                Name = "name1",
                Status = StatusEnum.Type.Ok,
                Time = Now.AddDays(-2),
                Value = "value5",
                SystemId = "systemId1"
            };
    
            var patientObservation6 = new PatientObservation
            {
                PatientId = PatientId,
                Code = "code2",
                CodingSystem = "MDC",
                Name = "name2",
                Status = StatusEnum.Type.Ok,
                Time = Now.AddDays(-2),
                Value = "value6"
            };
    
            await IntegrationDb.Database.DropCollectionAsync("patients_observations");
            await IntegrationDb.Database.CreateCollectionAsync("patients_observations");
    
            _logger = new Mock<ILogger<ObservationRepository>>();
    
            _repository = new ObservationRepository(_optionsApiSettings, IntegrationDb.Database, _logger.Object);
    
            await _repository.InsertOneAsync(patientObservation1);
            await _repository.InsertOneAsync(patientObservation2);
            await _repository.InsertOneAsync(patientObservation3);
            await _repository.InsertOneAsync(patientObservation4);
            await _repository.InsertOneAsync(patientObservation5);
            await _repository.InsertOneAsync(patientObservation6);
        }

    private ObservationRepository _repository;

    private readonly ApiSettings _apiSettings = new()
    {
        PatientsObservations = "patients_observations"
    };

    private IOptions<ApiSettings> _optionsApiSettings;
    private Mock<ILogger<ObservationRepository>> _logger;

    private static readonly DateTime Now = DateTime.UtcNow;
    private static readonly ObjectId PatientId = ObjectId.GenerateNewId();
    private static readonly ObjectId Id = ObjectId.GenerateNewId();


    /// <summary>
    /// Verifies that the repository's last observations lookup returns a non-null list containing the expected number of observations for the specified patient, system ("SNM"), and observation code ("code1").
    /// </summary>
    [Test]
        public async Task FindLastObservations_Return_List()
        {
            var result = await _repository.FindLastObservations(PatientId, "SNM", "code1");
    
            var patientObservations = result.ToList();
            Assert.That(patientObservations, Not.Null);
            Assert.That(patientObservations.Count(), EqualTo(2));
        }

    /// <summary>
    /// Verifies that FindLastObservationsByCodingSystem returns a non-null list of the expected count
    /// of the most recent observations for the specified patient filtered by the "SNM" coding system.
    /// </summary>
    [Test]
        public async Task FindLastObservationsByCodingSystem_Return_List()
        {
            var result = await _repository.FindLastObservationsByCodingSystem(PatientId, "SNM");
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(3));
        }


    /// <summary>
    /// Verifies that the AggregatedPatientLastObservations method returns a non-null list containing the expected number of aggregated last observations for the specified patient.
    /// </summary>
    [Test]
        public async Task AggregatedPatientLastObservations_Null_Filter_Return_List()
        {
            var result = await _repository.AggregatedPatientLastObservations(PatientId, 2);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(4));
        }

    /// <summary>
    /// Verifies that the AggregatedPatientLastObservations repository method returns a non-null filtered list with the expected number of entries when a name filter is provided.
    /// </summary>
    [Test]
        public async Task AggregatedPatientLastObservations_Filter_Return_List()
        {
            var filter = new List<string> { "name1" };
    
            var result = await _repository.AggregatedPatientLastObservations(PatientId, 2, filter);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(2));
        }

    /// <summary>
    /// Verifies that AggregatedPatientLastObservations returns an empty list when the provided filter does not match any observations.
    /// </summary>
    [Test]
        public async Task AggregatedPatientLastObservations_Filter_Not_Find_Return_Empty_List()
        {
            var filter = new List<string> { "name3" };
    
            var result = await _repository.AggregatedPatientLastObservations(PatientId, 2, filter);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Empty);
        }

    /// <summary>
    /// Verifies that <c>AggregatedPatientLastObservationsByLastDate</c> returns a non-null list of aggregated patient last observations for a given patient and date, even when no filter is applied.
    /// </summary>
    [Test]
        public async Task AggregatedPatientLastObservationsByLastDate_Null_Filter_Return_List()
        {
            var result = await _repository.AggregatedPatientLastObservationsByLastDate(PatientId, 2, Now);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(4));
        }

    /// <summary>
    /// Verifies that _repository.AggregatedPatientLastObservationsByLastDate returns a non-null list containing the expected number of aggregated patient last observations when a filter is provided.
    /// </summary>
    [Test]
        public async Task AggregatedPatientLastObservationsByLastDate_Filter_Return_List()
        {
            var filter = new List<string> { "name1" };
    
            var result = await _repository.AggregatedPatientLastObservationsByLastDate(PatientId, 2, Now, filter);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(2));
        }

    /// <summary>
    /// Verifies that AggregatedPatientLastObservationsByLastDate returns an empty list when the provided filter does not match any patient observations.
    /// </summary>
    [Test]
        public async Task AggregatedPatientLastObservationsByLastDate_Filter_Not_Find_Return_Empty_List()
        {
            var filter = new List<string> { "name3" };
    
            var result = await _repository.AggregatedPatientLastObservationsByLastDate(PatientId, 2, Now, filter);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Empty);
        }

    /// <summary>
    /// Verifies that AggregatedPatientLastObservationsByField returns a non-null list of aggregated patient last observations
    /// when the filter is <c>null</c>, confirming the expected fallback behavior and default result set.
    /// </summary>
    [Test]
        public async Task AggregatedPatientLastObservationsByField_Null_Filter_Return_List()
        {
            var result = await _repository.AggregatedPatientLastObservationsByField(PatientId, null);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(6));
        }

    /// <summary>
    /// Tests that filtering aggregated patient last observations by a specific field returns a non-null list containing the expected number of results.
    /// </summary>
    [Test]
        public async Task AggregatedPatientLastObservationsByField_Filter_Return_List()
        {
            var field = new List<Field> { new() { Name = "name1" } };
    
            var result = await _repository.AggregatedPatientLastObservationsByField(PatientId, field);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(1));
        }


    /// <summary>
    /// Verifies that _repository.AggregatedPatientLastObservationsByField returns an empty list when the filter field has <c>OnlyExpired</c> set to <c>true</c>, indicating no expired observations are available for the patient.
    /// </summary>
    [Test]
        public async Task AggregatedPatientLastObservationsByField_Filter_OnlyExpired_Return_Empty_List()
        {
            var field = new List<Field> { new() { Name = "name1", OnlyExpired = true } };
    
            var result = await _repository.AggregatedPatientLastObservationsByField(PatientId, field);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Empty);
        }


    /// <summary>
    /// Verifies that the <c>DeleteByPatientId</c> repository method removes all
    /// <see cref="PatientObservation"/> records associated with a given patient identifier.
    /// The test inserts a single observation, confirms it is persisted, deletes it by
    /// patient id, and asserts that no records remain for that patient.
    /// </summary>
    [Test]
        public async Task DeleteByPatientId()
        {
            var patientObservation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = ObjectId.GenerateNewId(),
                Code = "code",
                CodingSystem = "MDC",
                Name = "name",
                Status = StatusEnum.Type.Ok,
                Time = Now,
                Value = "value"
            };
    
            await _repository.InsertOneAsync(patientObservation);
    
            var result = await _repository.Collection.FindAsync(t => t.PatientId == patientObservation.PatientId);
    
            Assert.That(result, Not.Null);
            Assert.That(result.ToList(), Has.Count.EqualTo(1));
    
            await _repository.DeleteByPatientId(patientObservation.PatientId);
    
            var resultDelete = await _repository.Collection.FindAsync(t => t.PatientId == patientObservation.PatientId);
    
            Assert.That(resultDelete, Not.Null);
            Assert.That(resultDelete.ToList(), Empty);
        }

    /// <summary>
    /// Verifies that FindByPatientIdAsync returns a non-null cursor containing the expected number of records for the specified patient identifier.
    /// </summary>
    [Test]
        public async Task FindByPatientIdAsync_Return_Cursor()
        {
            var result = await _repository.FindByPatientIdAsync(PatientId);
    
            Assert.That(result, Not.Null);
            Assert.That(result.ToList(), Has.Count.EqualTo(6));
        }

    /// <summary>
    /// Verifies that <see cref="DeleteAsync"/> correctly removes a patient observation from the repository by inserting a record, confirming its presence, deleting it, and ensuring it is no longer retrievable.
    /// </summary>
    [Test]
        public async Task DeleteAsync()
        {
            var patientObservation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = ObjectId.GenerateNewId(),
                Code = "code",
                CodingSystem = "MDC",
                Name = "name",
                Status = StatusEnum.Type.Ok,
                Time = Now,
                Value = "value"
            };
    
            await _repository.InsertOneAsync(patientObservation);
    
            var result = await _repository.Collection.FindAsync(t => t.Id == patientObservation.Id);
    
            Assert.That(result, Not.Null);
            Assert.That(result.ToList(), Has.Count.EqualTo(1));
    
            await _repository.DeleteAsync(patientObservation.Id);
    
            var resultDelete = await _repository.Collection.FindAsync(t => t.Id == patientObservation.Id);
    
            Assert.That(resultDelete, Not.Null);
            Assert.That(resultDelete.ToList(), Empty);
        }

    /// <summary>
    /// Verifies that the repository's <c>DeleteOlderDaysAsync</c> method removes <see cref="PatientObservation"/> records older than the specified day threshold while keeping more recent ones, and that <c>DeleteByPatientId</c> subsequently clears the remaining records associated with the same patient.
    /// </summary>
    [Test]
        public async Task DeleteOlderDaysAsync()
        {
            var patientObservation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = ObjectId.GenerateNewId(),
                Code = "code",
                CodingSystem = "MDC",
                Name = "name",
                Status = StatusEnum.Type.Ok,
                Time = Now,
                Value = "value"
            };
    
            var patientObservationOld = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientObservation.PatientId,
                Code = "code",
                CodingSystem = "MDC",
                Name = "name",
                Status = StatusEnum.Type.Ok,
                Time = Now.AddDays(-15),
                Value = "value"
            };
    
            await _repository.InsertOneAsync(patientObservation);
            await _repository.InsertOneAsync(patientObservationOld);
    
            var result = await _repository.Collection.FindAsync(t => t.Name == patientObservation.Name);
    
            Assert.That(result, Not.Null);
            Assert.That(result.ToList(), Has.Count.EqualTo(2));
    
            await _repository.DeleteOlderDaysAsync(patientObservation.Name, 10);
    
            var resultDelete = await _repository.Collection.FindAsync(t => t.Name == patientObservation.Name);
    
            Assert.That(resultDelete, Not.Null);
            Assert.That(resultDelete.ToList(), Has.Count.EqualTo(1));
    
            await _repository.DeleteByPatientId(patientObservation.PatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == patientObservation.PatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Empty);
        }

    /// <summary>
    /// Verifies that <c>DeleteOlderSecondsAsync</c> removes <c>PatientObservation</c> entries whose timestamp is older than the specified number of seconds, keeping more recent entries with the same name intact, and that <c>DeleteByPatientId</c> clears all remaining observations for the given patient.
    /// </summary>
    [Test]
        public async Task DeleteOlderSecondsAsync()
        {
            var patientObservation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = ObjectId.GenerateNewId(),
                Code = "code",
                CodingSystem = "MDC",
                Name = "name",
                Status = StatusEnum.Type.Ok,
                Time = Now,
                Value = "value"
            };
    
            var patientObservationOld = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientObservation.PatientId,
                Code = "code",
                CodingSystem = "MDC",
                Name = "name",
                Status = StatusEnum.Type.Ok,
                Time = Now.AddSeconds(-15),
                Value = "value"
            };
    
    
            await _repository.InsertOneAsync(patientObservation);
            await _repository.InsertOneAsync(patientObservationOld);
    
            var result = await _repository.Collection.FindAsync(t => t.Name == patientObservation.Name);
    
            Assert.That(result, Not.Null);
            Assert.That(result.ToList(), Has.Count.EqualTo(2));
    
            await _repository.DeleteOlderSecondsAsync(patientObservation.Name, 10);
    
            var resultDelete = await _repository.Collection.FindAsync(t => t.Name == patientObservation.Name);
    
            Assert.That(resultDelete, Not.Null);
            Assert.That(resultDelete.ToList(), Has.Count.EqualTo(1));
    
            await _repository.DeleteByPatientId(patientObservation.PatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == patientObservation.PatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Empty);
        }

    /// <summary>
    /// Verifies that the repository's <c>DeleteOlderNumberAsync</c> method retains only the most recent specified count of <see cref="PatientObservation"/> records sharing the same name, deleting the older entries, and that <c>DeleteByPatientId</c> subsequently removes all remaining records for the patient.
    /// </summary>
    [Test]
        public async Task DeleteOlderNumberAsync()
        {
            var patientObservation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = ObjectId.GenerateNewId(),
                Code = "code",
                CodingSystem = "MDC",
                Name = "name",
                Status = StatusEnum.Type.Ok,
                Time = Now,
                Value = "value"
            };
    
            var patientObservationOld1 = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientObservation.PatientId,
                Code = "code",
                CodingSystem = "MDC",
                Name = "name",
                Status = StatusEnum.Type.Ok,
                Time = Now.AddSeconds(-10),
                Value = "value"
            };
    
            var patientObservationOld2 = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = patientObservation.PatientId,
                Code = "code",
                CodingSystem = "MDC",
                Name = "name",
                Status = StatusEnum.Type.Ok,
                Time = Now.AddSeconds(-15),
                Value = "value"
            };
    
    
            await _repository.InsertOneAsync(patientObservation);
            await _repository.InsertOneAsync(patientObservationOld1);
            await _repository.InsertOneAsync(patientObservationOld2);
    
            var result = await _repository.Collection.FindAsync(t => t.Name == patientObservation.Name);
    
            Assert.That(result, Not.Null);
            Assert.That(result.ToList(), Has.Count.EqualTo(3));
    
            await _repository.DeleteOlderNumberAsync(patientObservation.Name, 2);
    
            var resultDelete = await _repository.Collection.FindAsync(t => t.Name == patientObservation.Name);
    
            Assert.That(resultDelete, Not.Null);
            Assert.That(resultDelete.ToList(), Has.Count.EqualTo(2));
    
            await _repository.DeleteByPatientId(patientObservation.PatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == patientObservation.PatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Empty);
        }

    /// <summary>
    /// Verifies that _repository.<c>ExistBySystemId</c> returns a valid result when checking existence by the given patient and system identifiers.
    /// </summary>
    [Test]
        public async Task ExistBySystemId_Return_List()
        {
            var result = await _repository.ExistBySystemId(PatientId, "systemId1");
    
            //Assert.That(result, Is.Not.Null);
            Assert.That(result, True);
        }

    /// <summary>
    /// Verifies that FindLastObservationBeforeDate returns a non-null observation whose timestamp is earlier than the specified date, confirming a matching record is retrieved successfully.
    /// </summary>
    [Test]
        public async Task FindLastObservationBeforeDate_Return_Obs()
        {
            var result = await _repository.FindLastObservationBeforeDate(PatientId, "name1", Now);
    
            Assert.That(result, Not.Null);
            Assert.That(result!.Time, LessThan(Now));
        }

    /// <summary>
    /// Verifies that the repository's <c>FindAnyWithSameDate</c> method returns a non-null list containing exactly one observation
    /// when searching for observations associated with the specified patient, name, and date.
    /// </summary>
    [Test]
        public async Task FindAnyWithSameDate_Return_List_Obs()
        {
            var result = await _repository.FindAnyWithSameDate(PatientId, "name1", Now);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(1));
        }

    /// <summary>
    /// Tests that the repository returns a non-null list of two observations for a patient, found before the specified date (yesterday).
    /// </summary>
    [Test]
        public async Task FindAnyBeforeDate_Return_List_Obs()
        {
            var result = await _repository.FindAnyBeforeDate(PatientId, Now.AddDays(-1));
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(2));
        }

    /// <summary>
    /// Verifies that AggregatedPatientActiveIntravenousLinesObservations returns a non-null, empty list of observations for the specified patient when no filter criteria are provided.
    /// </summary>
    [Test]
        public async Task AggregatedPatientActiveIntravenousLinesObservations_Null_Filter_Return_List_Obs()
        {
            var result = await _repository.AggregatedPatientActiveIntravenousLinesObservations(PatientId);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that _repository.AggregatedPatientActiveIntravenousLinesObservations returns an empty list of observations when the filter value is not the Patient Intravenous Lines value.
    /// </summary>
    [Test]
        public async Task
            AggregatedPatientActiveIntravenousLinesObservations_Filter_Not_PatientIntravenousLineasValue_Return_List_Obs()
        {
            var result = await _repository.AggregatedPatientActiveIntravenousLinesObservations(PatientId);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that Repository.AggregatedPatientActiveIntravenousLinesObservations returns the expected list of active intravenous lines observations
    /// when filtering by patient id and the observation value is a <c>PatientIntravenousLinesValue</c> instance.
    /// The test inserts a single matching observation, asserts that exactly one record is returned, and confirms successful cleanup by deletion.
    /// </summary>
    [Test]
        public async Task
            AggregatedPatientActiveIntravenousLinesObservations_Filter_PatientIntravenousLineasValue_Return_List_Obs()
        {
            var intravenousLines = new PatientIntravenousLinesValue
            {
                Action = "action1", Duration = "duration1", InsertTime = Now, RemoveTime = Now, Location = "location1",
                Type = "type1"
            };
    
            var patientObservation = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = ObjectId.GenerateNewId(),
                Code = "codeIntra",
                CodingSystem = "MDC",
                Name = "IntravenousLinesObs",
                Status = StatusEnum.Type.Ok,
                Time = Now,
                Value = intravenousLines
            };
    
            await _repository.InsertOneAsync(patientObservation);
    
            var result =
                await _repository.AggregatedPatientActiveIntravenousLinesObservations(patientObservation.PatientId);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(1));
    
            await _repository.DeleteByPatientId(patientObservation.PatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == patientObservation.PatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that the repository method <c>FindAllLastPatientObservationTime</c> returns a non-null collection containing at least one last patient observation time record.
    /// </summary>
    [Test]
        public async Task FindAllLastPatientObservationTime_Return_List()
        {
            var result = await _repository.FindAllLastPatientObservationTime();
    
            Assert.That(result, Not.Null);
            Assert.That(result.ToList(), Not.Empty);
        }

    /// <summary>
    /// Verifies that the repository's <c>FindById</c> method returns <c>null</c> when the requested entity does not exist in the data store.
    /// </summary>
    [Test]
        public async Task FindById_Return_null()
        {
            var result = await _repository.FindById(ObjectId.GenerateNewId());
    
            Assert.That(result, Null);
        }

    /// <summary>
    /// Verifies that the repository's <c>FindById</c> method returns a non-null entity whose identifier matches the requested <c>Id</c>.
    /// </summary>
    [Test]
        public async Task FindById_Return_Obs()
        {
            var result = await _repository.FindById(Id);
    
            Assert.That(result, Not.Null);
            Assert.That(result!.Id, EqualTo(Id));
        }

    /// <summary>
    /// Verifies that the repository's <c>UpdateExpiredObservations</c> method correctly marks all non-expired observations belonging to a patient as expired.
    /// The test inserts five fresh observations, asserts that none are expired, invokes the update, and then asserts that all five have been flagged as expired before cleaning up the inserted data.
    /// </summary>
    [Test]
        public async Task UpdateExpiredObservations()
        {
            var newPatientId = ObjectId.GenerateNewId();
    
            var lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameUpdate",
                    Status = StatusEnum.Type.Ok,
                    Time = Now.AddHours(-i),
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var list = _repository.Collection.Find(p => p.PatientId == newPatientId).ToList();
    
            Assert.That(list, Not.Null);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(list.Count(l => l.Expired), EqualTo(0));
                Assert.That(list.Count(l => !l.Expired), EqualTo(5));
            };
            await _repository.UpdateExpiredObservations(list);
    
            var result = await _repository.Collection.FindAsync(p => p.PatientId == newPatientId);
            var listResult = result.ToList();
            Assert.That(listResult, Not.Null);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(listResult.Count(l => l.Expired), EqualTo(5));
                Assert.That(listResult.Count(l => !l.Expired), EqualTo(0));
            };
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
            var resultClearList = resultClear.ToList();
            Assert.That(resultClearList, Not.Null);
            Assert.That(resultClearList, Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that the repository's <c>FindAll</c> method returns a non-null and non-empty collection of patient observations.
    /// </summary>
    [Test]
        public async Task FindAll_Return_List_Obs()
        {
            var result = await _repository.FindAll();
    
            var patientObservations = result as PatientObservation[] ?? result.ToArray();
            Assert.That(patientObservations, Not.Null);
            Assert.That(patientObservations, Not.Empty);
        }

    /// <summary>
    /// Verifies that the repository's <c>FindNotExpired</c> method returns a non-empty collection of patient observations for the provided observation names.
    /// </summary>
    [Test]
        public async Task FindNotExpired_Return_List_Obs()
        {
            var result = await _repository.FindNotExpired(["name1", "name2", "name2"]);
    
            var patientObservations = result as PatientObservation[] ?? result.ToArray();
            Assert.That(patientObservations, Not.Null);
            Assert.That(patientObservations.Count(), GreaterThan(0));
        }

    /// <summary>
    /// Verifies that _repository.ExpireExpiredObservations" correctly marks the supplied
    /// configuration observations as expired so that a subsequent _repository.FindNotExpired
    /// call returns only the remaining non-expired observations, deduplicating the requested names.
    /// </summary>
    [Test]
        public async Task ExpireExpiredObservations()
        {
            var configObservationItems = new List<ConfigObservation>
            {
                new()
                {
                    Id = ObjectId.GenerateNewId(),
                    Name = "name1",
                    Expires = 480
                },
                new()
                {
                    Id = ObjectId.GenerateNewId(),
                    Name = "name2",
                    Expires = 480
                },
                new()
                {
                    Id = ObjectId.GenerateNewId(),
                    Name = "name3",
                    Expires = 480
                },
                new()
                {
                    Id = ObjectId.GenerateNewId(),
                    Name = "name4",
                    Expires = 480
                }
            };
    
            await _repository.ExpireExpiredObservations(configObservationItems);
    
            var result = await _repository.FindNotExpired(["name1", "name2", "name2"]);
    
            var patientObservations = result as PatientObservation[] ?? result.ToArray();
            Assert.That(patientObservations, Not.Null);
            Assert.That(patientObservations.ToList(), Has.Count.EqualTo(2));
        }

    /// <summary>
    /// Verifies that the repository's <c>FindByName</c> method returns a non-null, non-empty list of <see cref="PatientObservation"/> objects when searching by the name "name1".
    /// </summary>
    [Test]
        public async Task FindByName_Return_List_Obs()
        {
            var result = await _repository.FindByName("name1");
    
            var patientObservations = result as PatientObservation[] ?? result.ToArray();
            Assert.That(patientObservations, Not.Null);
            Assert.That(patientObservations.Count(), GreaterThan(0));
        }

    /// <summary>
    /// Verifies that <c>AggregatedPatientGroupedObservations</c> returns a non-null, empty list when called with a default <see cref="GroupedField"/> instance for the given patient.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Null_groupedField_Return_List_Emty()
        {
            var groupedField = new GroupedField();
    
            var result = await _repository.AggregatedPatientGroupedObservations(PatientId, groupedField);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(result, Not.Null);
                Assert.That(!result.Any(), True);
            };
        }

    /// <summary>
    /// Tests that AggregatedPatientGroupedObservations returns 9 grouped results when 30 hourly observations
    /// are aggregated for a patient using the First result selection strategy with a maximum of 8 groups.
    /// Verifies successful aggregation and ensures all inserted test observations are removed by patient id.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Hour_Firs_Return_List_9()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.First],
                Max = 8
            };
    
            const int lastNumber = 30;
    
            var newPatientId = ObjectId.GenerateNewId();
    
            for (var i = 0; i < lastNumber; i++)
            {
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = Now.AddHours(-i),
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(9));
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that AggregatedPatientGroupedObservations returns up to 8 hourly grouped observations
    /// using the <c>First</c> result selection and the <c>Last</c> since filter for a given patient.
    /// Inserts 30 observations, asserts the aggregated result count is 8, and confirms cleanup by patient id removes all inserted records.
    /// </summary>
    /// <returns>A task that completes when the test finishes, including assertions and cleanup.</returns>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Hour_Firs_Since_Last_Return_List_8()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.First],
                Max = 8,
                Since = Since.Last
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 30;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = Now.AddHours(-i),
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(8));
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that inserting five patient observations with hourly regularity and aggregating them using the first result returns a list of four or five grouped entries, and ensures the inserted observations are removed by patient id.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_Firs_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.First],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = Now.AddHours(-i),
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            //Assert.That(result, Has.Count.EqualTo(5));
            Assert.That(result, Has.Count.EqualTo(5).Or.EqualTo(4));
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }


    /// <summary>
    /// Verifies that <c>AggregatedPatientGroupedObservations</c> returns a non-empty list when patient observations are grouped by a field with second-level regularity and the aggregation selects only the first result per group, and that the inserted observations are fully removed by the cleanup step.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_second_Firs_Return_List()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Second,
                Result = [Result.First],
                Max = 60
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 120;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = Now.AddSeconds(-i),
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Not.Empty);
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that the aggregated grouped observations query, configured with minute regularity, the <c>First</c> result and a maximum of 8, returns a list of exactly 8 entries even when 30 underlying observations exist for the patient.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Minute_Firs_Return_List_8()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Minute,
                Result = [Result.First],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 30;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = Now.AddMinutes(-i),
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(8));
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that <c>AggregatedPatientGroupedObservations</c> returns at most the configured maximum number of entries
    /// when grouping patient observations by day and selecting the first result, even when more observations exist.
    /// Also confirms that observations inserted for the test patient are removed by the cleanup step.
    /// </summary>
    /// <returns>A task that completes when the aggregation result is validated and the test data is cleaned up.</returns>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Day_Firs_Return_List_8()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Day,
                Result = [Result.First],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 30;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = Now.AddDays(-i),
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(8));
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that <c>AggregatedPatientGroupedObservations</c> returns a list of 9 entries containing the "first" marker when grouping 30 patient observations by a shift-regularity field with a max of 8 and <c>Result.First</c> selected, and that all inserted observations are removed by the cleanup call.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Shift_Firs_Return_List_9()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Shift,
                Result = [Result.First],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 30;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = Now.AddHours(-i),
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(9));
            Assert.That(result.FindAll(r => r.Contains("first")), Has.Count.EqualTo(9));
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Tests that <c>AggregatedPatientGroupedObservations</c> returns a list of 5 entries when 5 observations are inserted per hour and the <c>Result.Last</c> aggregation rule is applied.
    /// Inserts two observations for each of the last 5 hours (at minutes 15 and 30), runs the aggregation for a new patient, and verifies the result count is 5 and that every entry contains the "last" marker.
    /// Cleanup is performed by deleting the inserted observations by patient id and asserting that the collection is empty afterwards.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_last_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.Last],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 30, 00, 00);
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 15, 00, 00);
    
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = $"value-{i}",
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(5));
            //Assert.That(result, Has.Count.EqualTo(5).Or.EqualTo(4));
            Assert.That(result.FindAll(r => r.Contains("last")), Has.Count.EqualTo(5));
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Verifies that the AggregatedPatientGroupedObservations method correctly aggregates patient observations
    /// into hourly groups and returns the sum of values for each hour when five hours of data are inserted.
    /// </summary>
    /// <returns>A task that represents the asynchronous test execution.</returns>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_sum_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.Sum],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 30, 00, 00);
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 5,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 15, 00, 00);
    
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 5,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
    
                Assert.That(result, Not.Null);
            };
    
            Assert.That(result, Has.Count.EqualTo(5));
            //Assert.That(result, Has.Count.EqualTo(5).Or.EqualTo(4));
            Assert.That(result.FindAll(r => r.Contains("sum")), Has.Count.EqualTo(5));
    
    
            for (var i = 0; i < lastNumber; i++) Assert.That(result[i]["sum"].ToInt32(), EqualTo(10).Or.EqualTo(5));
        }

    /// <summary>
    /// Verifies that when five hourly <see cref="PatientObservation"/> records are inserted with two values per hour (5 and 3),
    /// AggregatedPatientGroupedObservations returns a list of five entries, each containing the minimum value of 3.
    /// Also confirms that observations are cleaned up by patient id after the test executes.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_Min_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.Min],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 30, 00, 00);
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 5,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 15, 00, 00);
    
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 3,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(5));
            //Assert.That(result, Has.Count.EqualTo(5).Or.EqualTo(4));
            Assert.That(result.FindAll(r => r.Contains("min")), Has.Count.EqualTo(5));
            for (var i = 0; i < lastNumber; i++) Assert.That(result[i]["min"]["value"].ToInt32(), EqualTo(3));
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    /// <summary>
    /// Tests that <c>AggregatedPatientGroupedObservations</c> correctly groups observations by hour and returns the
    /// maximum value for each group, producing one aggregated result per hour when inserting two observations
    /// (with different values) for each of five consecutive hours.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_Max_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.Max],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 30, 00, 00);
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 5,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 15, 00, 00);
    
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 3,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
    
                Assert.That(result, Not.Null);
            };
    
            Assert.That(result, Has.Count.EqualTo(5));
            //Assert.That(result, Has.Count.EqualTo(5).Or.EqualTo(4));
            Assert.That(result.FindAll(r => r.Contains("max")), Has.Count.EqualTo(5));
            for (var i = 0; i < lastNumber; i++) Assert.That(result[i]["max"]["value"].ToInt32(), EqualTo(5).Or.EqualTo(3));
        }

    /// <summary>
    /// Tests that _repository.AggregatedPatientGroupedObservations returns a list of 5 aggregated results when grouping hourly observations by average over a 5-hour period.
    /// Inserts 10 observations across 5 different hours (two per hour with values 5 and 3), verifies the result count is 5, and asserts that each entry contains the "average" field with a value of 3 or 4.
    /// Cleans up by deleting all observations for the test patient after verification.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_Average_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.Average],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 30, 00, 00);
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 5,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 15, 00, 00);
    
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 3,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
    
                Assert.That(result, Not.Null);
            };
            Assert.That(result, Has.Count.EqualTo(5));
            //Assert.That(result, Has.Count.EqualTo(5).Or.EqualTo(4));
            Assert.That(result.FindAll(r => r.Contains("average")), Has.Count.EqualTo(5));
    
            for (var i = 0; i < lastNumber; i++) Assert.That(result[i]["average"].ToInt32(), EqualTo(4).Or.EqualTo(3));
        }

    /// <summary>
    /// Verifies that <c>AggregatedPatientGroupedObservations</c> groups observations by hour using the <c>Count</c> result and returns a list with one entry per hour bucket for the inserted records.
    /// Inserts ten observations (two per hour for five consecutive hours) for a new patient, runs the aggregation, and asserts that the result contains five entries each reporting a count of 1 or 2.
    /// Also confirms that cleanup via <c>DeleteByPatientId</c> removes the inserted observations for the generated patient.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_Count_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.Count],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 30, 00, 00);
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 5,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 15, 00, 00);
    
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 3,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
    
                Assert.That(result, Not.Null);
            };
    
            Assert.That(result, Has.Count.EqualTo(5));
            //Assert.That(result.Count, Is.EqualTo(5).Or.EqualTo(4));
            Assert.That(result.FindAll(r => r.Contains("count")), Has.Count.EqualTo(5));
            for (var i = 0; i < lastNumber; i++) Assert.That(result[i]["count"].ToInt32(), EqualTo(2).Or.EqualTo(1));
        }

    /// <summary>
    /// Verifies that aggregated patient observations grouped by hour with half-hour result granularity return the expected list of grouped entries for a newly inserted patient.
    /// Inserts two sets of observations at different minute offsets across the last five hours, then asserts the aggregation result count matches the expected number of groups and the "all" subset is returned.
    /// Also validates cleanup by ensuring no observations remain for the test patient after deletion.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_HalfHour_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.HalfHour],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 31, 00, 00);
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 5,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 15, 00, 00);
    
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 3,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
    
                Assert.That(result, Not.Null);
            };
    
            Assert.That(result, Has.Count.EqualTo(5));
            //Assert.That(result, Has.Count.EqualTo(5).Or.EqualTo(3));
    
            Assert.That(result.FindAll(r => r.Contains("all")), Has.Count.EqualTo(5).Or.EqualTo(3));
            //lastNumber = result.Count;
    
            //for (var i = 0; i < lastNumber; i++)
            //{
            //    Assert.Multiple(() =>
            //    {
            //        Assert.That(result[i]["all"][0]["value"].ToInt32(), Is.EqualTo(3));
            //        Assert.That(result[i]["all"][1]["value"].ToInt32(), Is.EqualTo(5).Or.EqualTo(3));
            //    });
            //}
        }

    /// <summary>
    /// Verifies that <c>AggregatedPatientGroupedObservations</c> returns up to 5 hourly aggregated entries
    /// when using the <c>LastFilled</c> result option, ensuring each hour contains the most recently filled
    /// observation value (either 5 or 3 depending on insertion order) and that the inserted test data is
    /// cleaned up afterwards.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_LastFilled_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.LastFilled],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            var lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 31, 00, 00);
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 5,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 15, 00, 00);
    
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 3,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
    
                Assert.That(result, Not.Null);
            };
    
            Assert.That(result, Has.Count.EqualTo(5));
            //Assert.That(result, Has.Count.EqualTo(5).Or.EqualTo(4));
            Assert.That(result.FindAll(r => r.Contains("lastfilled")), Has.Count.EqualTo(5).Or.Count.EqualTo(3));
            lastNumber = result.Count;
            for (var i = 0; i < lastNumber; i++)
                Assert.That(result[i]["lastfilled"]["value"].ToInt32(), EqualTo(5).Or.EqualTo(3));
        }

    /// <summary>
    /// Tests that the repository's aggregated patient grouped observations, configured with hourly regularity and the LastAll result option, returns a list of 5 entries when 5 hours of data are inserted (with two observations per hour at minutes 15 and 31), and verifies that cleanup by patient ID removes all inserted records.
    /// </summary>
    [Test]
        public async Task AggregatedPatientGroupedObservations_Insert_5_Hour_LastAll_Return_List_5()
        {
            var groupedField = new GroupedField
            {
                Name = "nameG",
                Group = "nameGroup",
                Regularity = Regularity.Hour,
                Result = [Result.LastAll],
                Max = 8
            };
    
            var newPatientId = ObjectId.GenerateNewId();
    
            const int lastNumber = 5;
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 31, 00, 00);
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 5,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            for (var i = 0; i < lastNumber; i++)
            {
                var time = new DateTime(Now.Year, Now.Month, Now.Day, Now.AddHours(-i).Hour, 15, 00, 00);
    
    
                var obs = new PatientObservation
                {
                    Id = ObjectId.GenerateNewId(),
                    PatientId = newPatientId,
                    Code = "code",
                    CodingSystem = "SNM",
                    Name = "nameG",
                    Status = StatusEnum.Type.Ok,
                    Time = time,
                    Value = 3,
                    SystemId = "systemId1"
                };
    
                await _repository.InsertOneAsync(obs);
            }
    
            var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);
    
            Assert.That(result, Not.Null);
            Assert.That(result, Has.Count.EqualTo(5));
            //Assert.That(result, Has.Count.EqualTo(5).Or.EqualTo(4));
    
            await _repository.DeleteByPatientId(newPatientId);
    
            var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);
    
            Assert.That(resultClear, Not.Null);
            Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
        }

    [Test]
    public async Task AggregatedPatientGroupedObservations_Times_Firs_Return_List_8()
    {
        var groupedField = new GroupedField
        {
            Name = "nameG",
            Group = "nameGroup",
            Regularity = Regularity.Times,
            Result = [Result.First],
            Max = 8
        };

        var newPatientId = ObjectId.GenerateNewId();

        const int lastNumber = 30;

        for (var i = 0; i < lastNumber; i++)
        {
            var obs = new PatientObservation
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = newPatientId,
                Code = "code",
                CodingSystem = "SNM",
                Name = "nameG",
                Status = StatusEnum.Type.Ok,
                Time = DateTime.Now,
                Value = $"value-{i}",
                SystemId = "systemId1"
            };

            await _repository.InsertOneAsync(obs);
        }

        //Thread.Sleep(TimeSpan.FromSeconds(1));

        await _repository.FindAll();

        var result = await _repository.AggregatedPatientGroupedObservations(newPatientId, groupedField);

        Assert.That(result,
            Has.Count.AnyOf(8,
                7)); //TODO: RevisarHay algún test que interfiere en el resultado. La primera vez que se lanza devuelve 7 y la segunda 8 

        await _repository.DeleteByPatientId(newPatientId);

        var resultClear = await _repository.Collection.FindAsync(t => t.PatientId == newPatientId);

        Assert.That(resultClear.ToList(), Empty);
    }
}