using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.MongoModels;
using adas_core.Infrastructure.Repositories;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using Moq;
using Options = Microsoft.Extensions.Options.Options;

namespace adas_core.Test.Repositories;

[TestFixture]
[Category("Integration")]
public class ConfigObservationRepositoryTest
{
    /// <summary>
    /// Initializes the integration test environment by recreating the "config_observations" MongoDB
    /// collection and seeding it with sample <see cref="ConfigObservation"/> records that cover
    /// different configuration scenarios, including coded and uncoded observations, parent coding
    /// system references, original name mappings, and observations with min/max alert thresholds
    /// and forced alert behavior.
    /// </summary>
    [OneTimeSetUp]
        public async Task Init()
        {
            _id = ObjectId.GenerateNewId();
            _optionsApiSettings = Options.Create(_apiSettings);
            _masterListMock = new Mock<IMasterListServiceFactory>();
    
            var testConfigObservation = new List<ConfigObservation>
            {
                new()
                {
                    Id = _id,
                    Name = "Hemoglobina",
                    Code = "12345",
                    CodingSystem = "SNM"
                },
    
                new()
                {
                    Id = ObjectId.GenerateNewId(),
                    Name = "Glucemia",
                    Code = "54321",
                    CodingSystem = "SNM",
                    OriginalName = "GLU"
                },
    
                new()
                {
                    Id = ObjectId.GenerateNewId(),
                    Name = "Sodio",
                    OriginalName = "Sodio"
                },
    
                new()
                {
                    Id = ObjectId.GenerateNewId(),
                    Name = "ph",
                    Code = "555",
                    CodingSystem = "MG4",
                    ParentCode = "3333",
                    ParentCodingSystem = "SNM"
                },
    
    
                new()
                {
                    Id = ObjectId.GenerateNewId(),
                    Name = "SOFA",
                    Code = "278061009",
                    OriginalName = "SOFA",
                    CodingSystem = "SNM",
                    MinAlert = 10,
                    MinWarn = 14
                },
    
    
                new()
                {
                    Id = ObjectId.GenerateNewId(),
                    Name = "FC",
                    Code = "147842",
                    //originalName = "MDC_ECG_CARD_BEAT_RATE",
                    CodingSystem = "MDC",
                    ParentCode = "69965",
                    ParentName = "MDC_DEV_MON_PHYSIO_MULTI_PARAM_MDS",
                    MinAlert = 60,
                    MaxAlert = 100,
                    ForceAlert = true
                }
            };
    
    
            await IntegrationDb.Database.DropCollectionAsync("config_observations");
            await IntegrationDb.Database.CreateCollectionAsync("config_observations");
    
            _repository =
                new ConfigObservationRepository(_optionsApiSettings, IntegrationDb.Database, _masterListMock.Object);
    
            await _repository.InsertManyAsync(testConfigObservation);
        }

    private ConfigObservationRepository _repository;
    private IMock<IMasterListServiceFactory> _masterListMock;
    private ObjectId _id;

    private readonly ApiSettings _apiSettings = new()
    {
        ConfigObservations = "config_observations"
    };

    private IOptions<ApiSettings> _optionsApiSettings;


    /// <summary>
    /// Verifies that the repository's FindById method returns a non-null configuration result when queried with a valid id.
    /// </summary>
    [Test]
        public async Task FindById_Find_Id_Return_Configs()
        {
            var result = await _repository.FindById(_id);
    
            Assert.That(result, Is.Not.Null);
        }

    /// <summary>
    /// Verifies that the <c>FindById</c> repository method returns <c>null</c> when invoked with a newly generated, non-existing identifier.
    /// </summary>
    [Test]
        public async Task FindById_Not_Find_Id_Return_Empty()
        {
            var result = await _repository.FindById(ObjectId.GenerateNewId());
    
            Assert.That(result, Is.Null);
        }

    /// <summary>
    /// Verifies that an existing <see cref="ConfigObservation"/> can be retrieved by its identifier and subsequently updated, ensuring the updated entity reflects the new values.
    /// </summary>
    [Test]
        public async Task Update_Find_Id_Return_Update_Configs()
        {
            var updateConfigObservation = new ConfigObservation
            {
                Id = _id,
                Name = "Hemoglobina 2",
                Code = "12345",
                CodingSystem = "SNM"
            };
    
            var result = await _repository.FindById(_id);
    
            Assert.That(result, Is.Not.Null);
            Assert.That(result.Name, Is.EqualTo("Hemoglobina"));
    
            var resultUpdate = await _repository.Update(updateConfigObservation);
    
            Assert.That(resultUpdate, Is.Not.Null);
            Assert.That(resultUpdate.Name, Is.EqualTo("Hemoglobina 2"));
        }

    /// <summary>
    /// Verifies that the repository's Update operation creates a new record when the provided identifier does not exist in the data store, instead of failing.
    /// </summary>
    [Test]
        public async Task Update_Not_Find_Id_Create_It()
        {
            var id2 = ObjectId.GenerateNewId();
            var updateConfigObservation = new ConfigObservation
            {
                Id = id2,
                Name = "Hemoglobina",
                Code = "12345",
                CodingSystem = "SNM"
            };
    
            await _repository.Update(updateConfigObservation);
            var resultfind = await _repository.FindById(id2);
            Assert.That(resultfind, Is.Not.Null);
        }


    /// <summary>
    /// Verifies that the base delete operation removes a <see cref="ConfigObservation"/> from the repository.
    /// The test confirms the entity is absent before insertion, present after insertion, and absent again after deletion.
    /// </summary>
    [Test]
        public async Task Delete_With_Base_DeleteAsync()
        {
            var iid = ObjectId.GenerateNewId();
            var deleteConfigObservation = new ConfigObservation
            {
                Id = iid,
                Name = "Hemoglobina3",
                Code = "123455",
                CodingSystem = "SNMM"
            };
    
            var result = await _repository.FindById(iid);
            Assert.That(result, Is.Null);
    
            await _repository.InsertOneAsync(deleteConfigObservation);
    
            var resultInsert = await _repository.FindById(iid);
            Assert.That(resultInsert, Is.Not.Null);
    
            await _repository.Delete(iid);
    
            var resultDelete = await _repository.FindById(iid);
            Assert.That(resultDelete, Is.Null);
        }
}