using adas_core.Application.Repositories.Interfaces;
using adas_core.Application.Services;
using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.MongoModels;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Moq;

namespace adas_core.Test.Services;

[TestFixture]
[NonParallelizable]
internal class HistoricalConfigChangesServiceTest
{
    /// <summary>
    /// Initializes the mock repository, mock logger, and the <see cref="HistoricalConfigChangesService"/> instance under test prior to each unit test execution.
    /// </summary>
    [SetUp]
        public void Setup()
        {
            _mockRepo = new Mock<IHistoricalConfigChangesRepository>();
            _mockLogger = new Mock<ILogger<HistoricalConfigChangesService>>();
            _service = new HistoricalConfigChangesService(_mockRepo.Object, _mockLogger.Object, _httpContextAccessor.Object,
                _auditService.Object);
        }

    private HistoricalConfigChangesService _service;
    private Mock<IHistoricalConfigChangesRepository> _mockRepo;
    private Mock<ILogger<HistoricalConfigChangesService>> _mockLogger;
    private readonly Mock<IHttpContextAccessor> _httpContextAccessor = new();
    private readonly Mock<ILocalAuditService> _auditService = new();


    /// <summary>
    /// Verifies that <see cref="FindLastConfigChanges"/> returns the last configuration change retrieved from the repository for the specified configuration type.
    /// </summary>
    /// <param name="configType">The type of configuration whose last historical changes are being retrieved.</param>
    /// <returns>A task that represents the asynchronous test execution.</returns>
    [Test]
        public async Task FindLastConfigChanges_ReturnsLastConfigChange()
        {
            // Arrange
            var configType = DisplayConfigEnums.ConfigTypes.ObservationCfg;
            var mockResult = new List<HistoricalConfigChanges>
            {
                new() // Mock object with desired properties
            };
            _mockRepo.Setup(r => r.FindLastHistoricalConfigChangesByType(configType, 10)).ReturnsAsync(mockResult);
    
            // Act
            var result = await _service.FindLastConfigChanges(configType);
    
            // Assert
            Assert.That(result, Is.Not.Null);
            // Further assertions based on the expected result
        }

    /// <summary>
    /// Verifies that the service returns <c>null</c> when the underlying repository throws an exception while inserting a <see cref="HistoricalConfigChanges"/> entity.
    /// </summary>
    [Test]
        public async Task InsertOne_WhenExceptionOccurs_ReturnsNull()
        {
            // Arrange
            var mockChange = new HistoricalConfigChanges();
            _mockRepo.Setup(r => r.InsertOneAsync(mockChange)).Throws(new Exception());
    
            // Act
            var result = await _service.InsertOne(mockChange);
    
            // Assert
            Assert.That(result, Is.Null);
        }


    /// <summary>
    /// Verifies that the service's <c>GetAll</c> method returns all historical configuration changes retrieved from the repository.
    /// </summary>
    [Test]
        public async Task GetAll_ReturnsAllConfigChanges()
        {
            // Arrange
            var mockResult = new List<HistoricalConfigChanges>
            {
                new(),
                new()
            };
            _mockRepo.Setup(r => r.FindAll()).ReturnsAsync(mockResult);
    
            // Act
            var result = await _service.GetAll();
    
            // Assert
            Assert.That(result, Has.Count.EqualTo(2));
        }

    /// <summary>
    /// Verifies that the service's <c>GetByType</c> method returns the expected number of historical configuration changes for the specified configuration type.
    /// </summary>
    [Test]
        public async Task GetByType_ReturnsCorrectAmountOfConfigs()
        {
            // Arrange
            var configType = DisplayConfigEnums.ConfigTypes.ObservationCfg;
            var mockResult = new List<HistoricalConfigChanges>
            {
                new(),
                new(),
                new()
            };
            _mockRepo.Setup(r => r.FindLastHistoricalConfigChangesByType(configType, 3)).ReturnsAsync(mockResult);
    
            // Act
            var result = await _service.GetByType(configType, 3);
    
            // Assert
            Assert.That(result, Has.Count.EqualTo(3));
        }

    /// <summary>
    /// Verifies that the service returns the expected number of historical configuration changes for a given user,
    /// confirming the repository result is correctly forwarded to the caller.
    /// </summary>
    [Test]
        public async Task GetByUser_ReturnsCorrectConfigs()
        {
            // Arrange
            var user = "TestUser";
            var mockResult = new List<HistoricalConfigChanges>
            {
                new(),
                new()
            };
            _mockRepo.Setup(r => r.FindLastHistoricalConfigChangesByUser(user, null, 2)).ReturnsAsync(mockResult);
    
            // Act
            var result = await _service.GetByUser(user, null, 2);
    
            // Assert
            Assert.That(result, Has.Count.EqualTo(2));
        }

    /// <summary>
    /// Verifies that the service returns null when an exception is thrown while updating a historical configuration change, ensuring graceful error handling.
    /// </summary>
    [Test]
        public async Task UpdateHistoricalConfigChange_WhenExceptionOccurs_ReturnsNull()
        {
            // Arrange
            var mockChange = new HistoricalConfigChanges();
            _mockRepo.Setup(r => r.Update(mockChange)).Throws(new Exception());
    
            // Act
            var result = await _service.UpdateHistoricalConfigChange(mockChange);
    
            // Assert
            Assert.That(result, Is.Null);
        }
}