using System.Diagnostics;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.MongoModels;
using adas_core.Infrastructure.Repositories;
using Microsoft.Extensions.Logging;
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 HistoricalConfigChangesRepositoryTest
{
    /// <summary>
    /// Performs one-time setup for the test fixture by initializing configuration options, a mocked logger, and the <see cref="HistoricalConfigChangesRepository"/> instance used across the tests.
    /// </summary>
    [OneTimeSetUp]
        public void Init()
        {
            _optionsApiSettings = Options.Create(_apiSettings);
            _logger = new Mock<ILogger<HistoricalConfigChangesRepository>>();
    
    
            _repository =
                new HistoricalConfigChangesRepository(_optionsApiSettings, IntegrationDb.Database, _logger.Object);
        }

    /// <summary>
    /// Resets the integration test environment by dropping and recreating the <c>historicalConfigChanges</c> collection and then reinitializing the test data. Used as a teardown step to ensure a clean state between tests.
    /// </summary>
    [TearDown]
        public async Task Cleanup()
        {
            await IntegrationDb.Database.DropCollectionAsync("historicalConfigChanges");
            await IntegrationDb.Database.CreateCollectionAsync("historicalConfigChanges");
    
            await InitializeData();
        }

    private HistoricalConfigChangesRepository _repository;

    private readonly ApiSettings _apiSettings = new()
    {
        HistoricalConfigChanges = "historicalConfigChanges"
    };

    private IOptions<ApiSettings> _optionsApiSettings;

    private Mock<ILogger<HistoricalConfigChangesRepository>> _logger;

    /// <summary>
    /// Seeds the repository with a series of historical configuration change records for an observation configuration
    /// (Hemoglobina), illustrating successive code updates from "54321" to "xxxxx" to "11111" to "99999" under the "adas" user.
    /// </summary>
    private async Task InitializeData()
        {
            var id = ObjectId.GenerateNewId();
            HistoricalConfigChanges historicalConfigChanges1 = new()
            {
                //Id = ObjectId.GenerateNewId(),
                ConfigType = DisplayConfigEnums.ConfigTypes.ObservationCfg,
                Time = DateTime.UtcNow,
                Username = "adas",
                OldConfig = new ConfigObservation
                {
                    Id = id,
                    Name = "Hemoglobina",
                    Code = "54321",
                    CodingSystem = "SNM"
                }.ToJson(),
                NewConfig = new ConfigObservation
                {
                    Id = id,
                    Name = "Hemoglobina",
                    Code = "xxxxx",
                    CodingSystem = "SNM"
                }.ToJson()
            };
    
            await _repository.InsertOneAsync(historicalConfigChanges1);
    
            HistoricalConfigChanges historicalConfigChanges2 = new()
            {
                //Id = ObjectId.GenerateNewId(),
                ConfigType = DisplayConfigEnums.ConfigTypes.ObservationCfg,
                Time = DateTime.UtcNow,
                Username = "adas",
                OldConfig = new ConfigObservation
                {
                    Id = id,
                    Name = "Hemoglobina",
                    Code = "xxxxx",
                    CodingSystem = "SNM"
                }.ToJson(),
                NewConfig = new ConfigObservation
                {
                    Id = id,
                    Name = "Hemoglobina",
                    Code = "11111",
                    CodingSystem = "SNM"
                }.ToJson()
            };
    
            await _repository.InsertOneAsync(historicalConfigChanges2);
    
            HistoricalConfigChanges historicalConfigChanges3 = new()
            {
                //Id = ObjectId.GenerateNewId(),
                ConfigType = DisplayConfigEnums.ConfigTypes.ObservationCfg,
                Time = DateTime.UtcNow,
                Username = "adas",
                OldConfig = new ConfigObservation
                {
                    Id = id,
                    Name = "Hemoglobina",
                    Code = "111111",
                    CodingSystem = "SNM"
                }.ToJson(),
                NewConfig = new ConfigObservation
                {
                    Id = id,
                    Name = "Hemoglobina",
                    Code = "99999",
                    CodingSystem = "SNM"
                }.ToJson()
            };
    
            await _repository.InsertOneAsync(historicalConfigChanges3);
        }


    /// <summary>
    /// Verifies that the repository's <c>FindAll</c> method returns a non-null collection containing exactly three historical configuration change records after a cleanup operation.
    /// </summary>
    [Test]
        public async Task Get_HistoricalConfigChanges_returns_count_3()
        {
            await Cleanup();
    
            var result = await _repository.FindAll();
    
            Assert.That(result, Is.Not.Null);
            Assert.That(result, Has.Count.EqualTo(3));
        }


    /// <summary>
    /// Verifies that the repository <c>Update</c> operation for a <see cref="HistoricalConfigChanges"/> document returns a non-null result whose properties correspond to the updated record, after cleaning up existing data and retrieving an existing entry to be modified.
    /// </summary>
    [Test]
        public async Task HistoricalConfigChanges_returns_diferent_document()
        {
            await Cleanup();
            var id = ObjectId.GenerateNewId();
            var resultList = await _repository.FindAll();
            var result = resultList.FirstOrDefault();
    
            Assert.That(result, Is.Not.Null);
    
            Debug.Assert(result != null, nameof(result) + " != null");
            HistoricalConfigChanges updatedHistoricalConfigChanges = new()
            {
                Id = result.Id,
                ConfigType = DisplayConfigEnums.ConfigTypes.ObservationCfg,
                Time = DateTime.UtcNow,
                Username = "admin",
                OldConfig = new ConfigObservation
                {
                    Id = id,
                    Name = "Hemoglobina",
                    Code = "12345",
                    CodingSystem = "SNM"
                }.ToJson(),
                NewConfig = new ConfigObservation
                {
                    Id = id,
                    Name = "Hemoglobina",
                    Code = "54321",
                    CodingSystem = "SNM"
                }.ToJson()
            };
    
    
            var updated = await _repository.Update(updatedHistoricalConfigChanges);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(updated, Is.Not.Null);
                Assert.That(result.Time, Is.EqualTo(updated?.Time));
                Assert.That(result.Id, Is.EqualTo(updated?.Id));
                Assert.That(result.Username, Is.EqualTo(updated?.Username));
                Assert.That(result.ConfigType, Is.EqualTo(updated?.ConfigType));
                Assert.That(result.OldConfig, Is.EqualTo(updated?.OldConfig));
                Assert.That(result.NewConfig, Is.EqualTo(updated?.NewConfig));
            };
        }

    /// <summary>
    /// Verifies that <see cref="_repository"/>.FindLastHistoricalConfigChangesByUser returns exactly three historical configuration changes for the user "adas" after cleanup.
    /// </summary>
    [Test]
        public async Task FindLastHistoricalConfigChangesByUser_returns_3()
        {
            await Cleanup();
            var result = await _repository.FindLastHistoricalConfigChangesByUser("adas");
    
            Assert.That(result, Is.Not.Null);
            Assert.That(result, Has.Count.EqualTo(3));
        }

    /// <summary>
    /// Verifies that deleting a historical config change entry reduces the total count of records from three to two in the repository.
    /// </summary>
    [Test]
        public async Task Delete_HistoricalConfigChanges_returns_count_2()
        {
            await Cleanup();
            var resultList = await _repository.FindAll();
            Assert.That(resultList, Has.Count.EqualTo(3));
    
            var result = resultList.FirstOrDefault();
            Assert.That(result, Is.Not.Null);
            Debug.Assert(result != null, nameof(result) + " != null");
            var deleted = await _repository.DeleteAsync(result.Id);
    
            Assert.That(deleted, Is.Not.Null);
    
            var resultAfterDelete = await _repository.FindAll();
            Assert.That(resultAfterDelete, Has.Count.EqualTo(2));
        }
}