using System.Text;
using System.Text.Json;
using e_suite.API.Common;
using e_suite.MessageProcessor.Handlers;
using e_suite.Messaging.Common;
using e_suite.Messaging.Common.models;
using e_suite.Service.Sentinel;
using e_suite.UnitTestCore;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using RabbitMQ.Client.Events;

namespace e_suite.MessageProcessor.UnitTests;

[TestFixture]
public class DatabaseQueueHandlerUnitTests : TestBase
{
    protected Mock<ISentinelMaintenance> SentinelMaintenanceMock { get; set; } = null!;
    protected Mock<IPerformanceMaintenance> PerformanceMaintenanceMock { get; set; } = null!;
    protected Mock<IUserManagerMaintenance> UserManagerMaintenanceMock { get; set; } = null!;
    protected Mock<ILogger> LoggerMock {get; set; } = null!;
    protected DatabaseQueueHandler DatabaseQueueHandler { get; set; } = null!;

    [SetUp]
    public override Task Setup()
    {
        SentinelMaintenanceMock = new Mock<ISentinelMaintenance>();
        PerformanceMaintenanceMock = new Mock<IPerformanceMaintenance>();
        UserManagerMaintenanceMock = new Mock<IUserManagerMaintenance>();
        LoggerMock = new Mock<ILogger>();
        _fakeClock = new FakeClock();

        DatabaseQueueHandler = new DatabaseQueueHandler(SentinelMaintenanceMock.Object, PerformanceMaintenanceMock.Object, UserManagerMaintenanceMock.Object, _fakeClock, LoggerMock.Object);

        return base.Setup();
    }

    private byte[] ObjectToStream<T>(T item)
    {
        var json = JsonSerializer.Serialize(item);
        return Encoding.UTF8.GetBytes(json);
    }

    [Test]
    public async Task OnReceived_ClearOldSentinelData_CallsSentinelMaintenance()
    {
        //Arrange
        var message = new DatabaseMessage
        {
            MessageType = DatabaseMessageTypes.ClearOldSentinelData
        };

        var body = ObjectToStream(message);

        var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body);

        //Act
        await DatabaseQueueHandler.OnReceived(MessageQueueNames.Database, eventArgs);

        //Assert
        SentinelMaintenanceMock.Verify( x => x.ClearOldSentinelData(), Times.Once);
    }

    [Test]
    public async Task OnReceived_ClearOldPerformanceData_CallsPerformanceMaintenance()
    {
        //Arrange
        var message = new DatabaseMessage
        {
            MessageType = DatabaseMessageTypes.ClearOldPerformanceData
        };

        var body = ObjectToStream(message);

        var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body);

        //Act
        await DatabaseQueueHandler.OnReceived(MessageQueueNames.Database, eventArgs);

        //Assert
        PerformanceMaintenanceMock.Verify(x => x.ClearOldPerformanceData(), Times.Once);
    }

    [Test]
    public async Task OnReceived_ClearOldEmailActions_CallsUserManagerMaintenance()
    {
        //Arrange
        var message = new DatabaseMessage
        {
            MessageType = DatabaseMessageTypes.ClearOldEmailActions
        };

        var body = ObjectToStream(message);

        var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body);

        //Act
        await DatabaseQueueHandler.OnReceived(MessageQueueNames.Database, eventArgs);

        //Assert
        UserManagerMaintenanceMock.Verify(x => x.ClearOldEmailActions(), Times.Once);
    }

    [Test]
    public async Task OnReceived_ClearOldSingleUserGuids_CallsUserManagerMaintenance()
    {
        //Arrange
        var message = new DatabaseMessage
        {
            MessageType = DatabaseMessageTypes.ClearOldSingleUserGuids
        };

        var body = ObjectToStream(message);

        var eventArgs = new BasicDeliverEventArgs(string.Empty, 0, false, string.Empty, string.Empty, null!, body);

        //Act
        await DatabaseQueueHandler.OnReceived(MessageQueueNames.Database, eventArgs);

        //Assert
        UserManagerMaintenanceMock.Verify(x => x.ClearOldSingleUserGuids(), Times.Once);
    }
}