using e_suite.API.Common.exceptions;
using e_suite.API.Common.models;
using e_suite.Database.Audit;
using e_suite.Database.Core.Tables.Domain;
using e_suite.Database.Core.Tables.Mail;
using e_suite.Modules.MailTemplatesManager.UnitTests.Helpers;
using eSuite.Core.MailService;
using eSuite.Core.Miscellaneous;
using Moq;
using NUnit.Framework;

namespace e_suite.Modules.MailTemplatesManager.UnitTests;

[TestFixture]
public class PostMailTemplateUnitTests : MailTemplatesManagerTestBase
{
    [SetUp]
    public override async Task Setup()
    {
        await base.Setup();
    }

    [Test]
    public void PostMailTemplate_WhenDomainNotExisting_ThrowNotFoundException()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 666,
            UserDisplayName = "Testy McTester",
            Comment = string.Empty
        };

        var postMailTemplate = new PostMailTemplate()
        {

        };

        //Assert
        var actualResult = Assert.ThrowsAsync<NotFoundException>(
            //Act
            async () => await MailTemplateManager.PostMailTemplate(postMailTemplate, auditUserDetails, CancellationToken.None));

        Assert.That(actualResult!.Message, Is.EqualTo("Unable to find domain"));
    }

    [Test]
    public async Task PostMailTemplate_DomainFoundAndTemplateNotFound_InsertsMailTemplate()
    {
        //Arrange
        var dbDomain = new Domain
        {
            Id = 100,
            Guid = new Guid("c7645f28-c492-4bd5-9b2e-68b9a2eb3e39"),
            Name = "Testing domain"
        };

        DomainRepositoryMock.Setup(x => x.GetDomainById(It.IsAny<IGeneralIdRef>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync(dbDomain);

        var auditUserDetails = new AuditUserDetails
        {
            UserId = 666,
            UserDisplayName = "Testy McTester",
            Comment = string.Empty
        };

        var postMailTemplate = new PostMailTemplate
        {
            MailType = MailType.ConfirmEmailAddress,
            Subject = "This is the subject",
            TemplateDefinition = "This is an email template",
            Domain = new GeneralIdRef
            {
                Id = dbDomain.Id,
                Guid = dbDomain.Guid
            }
        };

        MailTemplate actualMailTemplate = null!;
        AuditUserDetails actualauditUserDetail = null!;

        MailTemplatesManagerRepositoryMock
            .Setup(x => x.InsertMailTemplateAsync(It.IsAny<MailTemplate>(), auditUserDetails,
                It.IsAny<CancellationToken>())).Callback<MailTemplate, AuditUserDetails, CancellationToken>(
                (mailtemplate, auditUserDetails, cancellationToken) =>
                {
                    actualMailTemplate = mailtemplate;
                    actualauditUserDetail = auditUserDetails;
                });

        //Act
        await MailTemplateManager.PostMailTemplate(postMailTemplate, auditUserDetails, CancellationToken.None);

        //Assert
        MailTemplatesManagerRepositoryMock.Verify(
            x => x.InsertMailTemplateAsync(It.IsAny<MailTemplate>(), auditUserDetails, It.IsAny<CancellationToken>()),
            Times.Once);
        Assert.That(actualauditUserDetail, Is.Not.Null);
        Assert.That(actualMailTemplate, Is.Not.Null);
        Assert.That(actualMailTemplate.Subject, Is.EqualTo(postMailTemplate.Subject));
        Assert.That(actualMailTemplate.TemplateDefinition, Is.EqualTo(postMailTemplate.TemplateDefinition));
        Assert.That(actualMailTemplate.DomainId, Is.EqualTo(postMailTemplate.Domain.Id));
        Assert.That(actualMailTemplate.MailType, Is.EqualTo(postMailTemplate.MailType));
    }

    [Test]
    public async Task PostMailTemplate_TemplateExists_UpdatesExistingTemplate()
    {
        //Arrange
        var dbDomain = new Domain
        {
            Id = 100,
            Guid = new Guid("c7645f28-c492-4bd5-9b2e-68b9a2eb3e39"),
            Name = "Testing domain"
        };

        DomainRepositoryMock.Setup(x => x.GetDomainById(It.IsAny<IGeneralIdRef>(), It.IsAny<CancellationToken>()))
            .ReturnsAsync(dbDomain);

        var auditUserDetails = new AuditUserDetails
        {
            UserId = 666,
            UserDisplayName = "Testy McTester",
            Comment = string.Empty
        };

        var postMailTemplate = new PostMailTemplate
        {
            MailType = MailType.ConfirmEmailAddress,
            Subject = "This is the subject",
            TemplateDefinition = "This is an email template",
            Domain = new GeneralIdRef
            {
                Id = dbDomain.Id,
                Guid = dbDomain.Guid
            }
        };
        
        var domainMailTemplate = new MailTemplate
        {
            DomainId = 100,
            Domain = dbDomain,
            MailType = MailType.ConfirmEmailAddress,
            Subject = "Confirm Email Address (Domain level)",
            TemplateDefinition = "This is the message Content"
        };

        MailTemplatesManagerRepositoryMock.Setup(x =>
            x.GetMailTemplate(dbDomain.Id, MailType.ConfirmEmailAddress, It.IsAny<CancellationToken>())).ReturnsAsync(domainMailTemplate);


        MailTemplate actualMailTemplate = null!;
        AuditUserDetails actualauditUserDetail = null!;
        MailTemplatesManagerRepositoryMock
            .Setup(x => x.UpdateMailTemplateAsync(It.IsAny<MailTemplate>(), auditUserDetails,
                It.IsAny<CancellationToken>())).Callback<MailTemplate, AuditUserDetails, CancellationToken>(
                (mailtemplate, auditUserDetails, cancellationToken) =>
                {
                    actualMailTemplate = mailtemplate;
                    actualauditUserDetail = auditUserDetails;
                });

        //Act
        await MailTemplateManager.PostMailTemplate(postMailTemplate, auditUserDetails, CancellationToken.None);

        //Assert
        MailTemplatesManagerRepositoryMock.Verify(
            x => x.InsertMailTemplateAsync(It.IsAny<MailTemplate>(), auditUserDetails, It.IsAny<CancellationToken>()),
            Times.Never);


        Assert.That(actualauditUserDetail, Is.Not.Null);
        Assert.That(actualMailTemplate, Is.Not.Null);
        Assert.That(actualMailTemplate.Subject, Is.EqualTo(postMailTemplate.Subject));
        Assert.That(actualMailTemplate.TemplateDefinition, Is.EqualTo(postMailTemplate.TemplateDefinition));
        Assert.That(actualMailTemplate.DomainId, Is.EqualTo(postMailTemplate.Domain.Id));
        Assert.That(actualMailTemplate.MailType, Is.EqualTo(postMailTemplate.MailType));
    }
}