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

namespace adas_core.Test.Services;

[TestFixture]
public class ConfigUnitsServiceTest
{
    /// <summary>
    /// Initializes the test dependencies and creates a new instance of <see cref="ConfigUnitsService"/> with mocked repository, options, and logger for use in unit tests.
    /// </summary>
    [SetUp]
        public void Setup()
        {
            //configUnitsServiceMock = new Mock<IConfigUnitsService>();
            _configUnitsRepositoryMock = new Mock<IConfigUnitsRepository>();
    
            _optionsApiSettings = Options.Create(_apiSettings);
    
            _logger = new Mock<ILogger<ConfigUnitsService>>();
    
            _configUnitsService = new ConfigUnitsService(
                _configUnitsRepositoryMock.Object,
                _optionsApiSettings,
                _logger.Object);
        }

    private ConfigUnitsService _configUnitsService;

    //Mock<IConfigUnitsService> configUnitsServiceMock;
    private Mock<IConfigUnitsRepository> _configUnitsRepositoryMock;

    private readonly ApiSettings _apiSettings = new()
    {
        ConfigObservation = new ConfigObservationSettings
        {
            Refresh = null
        }
    };

    private IOptions<ApiSettings> _optionsApiSettings;

    private Mock<ILogger<ConfigUnitsService>> _logger;

    private static readonly DateTime Now = DateTime.Now;

    /// <summary>
    /// Verifies that when <c>ConfigUnitsRequired</c> is set to <c>false</c>, the <see cref="ConfigUnitsService.Map"/> method returns the same observation instance without applying any unit mapping or transformation.
    /// </summary>
    [Test]
        public async Task Map_configUnitsRequired_false_Return_same_obs()
        {
            _optionsApiSettings.Value.ConfigUnitsRequired = false;
    
            var obs = new PatientObservation
            {
                Code = "code",
                CodingSystem = "SNM",
                Name = "name",
                Time = Now
            };
    
            var configUnitsService = new ConfigUnitsService(
                _configUnitsRepositoryMock.Object,
                _optionsApiSettings,
                _logger.Object);
    
            var result = await configUnitsService.Map(obs);
    
            Assert.That(obs, Is.EqualTo(result));
        }

    /// <summary>
    /// Verifies that mapping a patient observation that does not contain units returns the same observation unchanged, confirming the mapping logic preserves the original data when no unit conversion is applicable.
    /// </summary>
    [Test]
        public async Task Map_not_units_Return_same_obs()
        {
            _optionsApiSettings.Value.ConfigUnitsRequired = true;
    
            var obs = new PatientObservation
            {
                Code = "code",
                CodingSystem = "SNM",
                Name = "name",
                Time = Now
            };
    
            var result = await _configUnitsService.Map(obs);
    
            Assert.That(obs, Is.EqualTo(result));
        }

    /// <summary>
    /// Verifies that the Map method returns the original observation unchanged with a null Units property when configuration units are required and no matching config unit is found for the observation's code.
    /// </summary>
    [Test]
        public async Task Map_Not_Find_Config_Return_same_obs()
        {
            _optionsApiSettings.Value.ConfigUnitsRequired = true;
    
            var obs = new PatientObservation
            {
                Code = "code",
                CodingSystem = "SNM",
                Name = "name",
                Time = Now
            };
    
            var configUnitItem = new ConfigUnitItem();
    
            var configUnits = new ConfigUnits
            {
                Id = "PV1",
                Items = [configUnitItem]
            };
    
            _configUnitsRepositoryMock.Setup(c => c.FindById(It.IsAny<string>())).ReturnsAsync(configUnits);
    
            var result = await _configUnitsService.Map(obs);
            using (Assert.EnterMultipleScope())
            {
                Assert.That(obs, Is.EqualTo(result));
                Assert.That(result.Units, Is.Null);
            };
        }

    /// <summary>
    /// Verifies that Map returns the configured unit value for a patient observation when
    /// ConfigUnitsRequired is enabled and a matching config unit is found in the repository.
    /// </summary>
    [Test]
        public async Task Map_configUnits_Return_obs_ConfigUnit()
        {
            _optionsApiSettings.Value.ConfigUnitsRequired = true;
    
            var obs = new PatientObservation
            {
                Code = "code",
                CodingSystem = "SNM",
                Name = "name",
                Time = Now,
                Units = "MDC_DIM_X_G_PER_KG"
            };
    
    
            var configUnitItem = new ConfigUnitItem
            {
                Code = "MDC_DIM_X_G_PER_KG",
                Value = "g/kg"
            };
    
            var configUnits = new ConfigUnits
            {
                Id = "PV1",
                Items = [configUnitItem]
            };
    
            _configUnitsRepositoryMock.Setup(c => c.FindById(It.IsAny<string>())).ReturnsAsync(configUnits);
    
            var result = await _configUnitsService.Map(obs);
    
            Assert.That(result.Units, Is.Not.Null);
            Assert.That(result.Units, Is.EqualTo("g/kg"));
        }
}