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.UserManager;
using e_suite.Modules.DomainManager.UnitTests.Helpers;
using eSuite.Core.Miscellaneous;
using NUnit.Framework;

namespace e_suite.Modules.DomainManager.UnitTests;

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

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

        var domain = new Domain
        {
            Guid = new Guid("4c465763-f93f-4496-9f4b-4029cb2642c0"),
            Id = 725,
            Name = "The Hard Place",
            Deleted = false
        };

        DomainManagerRepository.Domains.Add(domain);

        var createDomain = new CreateDomain
        {
            Guid = domain.Guid
        };

        //Assert
        var actualResult = Assert.ThrowsAsync<ExistsException>(async () =>
        {
            //Act
            await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None);
        });
        Assert.That(actualResult!.Message, Is.EqualTo("Domain already exists"));
    }

    [Test]
    public async Task CreateDomainAsync_WhenDeletedDomainExistsAndGuidProvided_DomainIsRestoredAndRenamed()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 100,
            UserDisplayName = "Testy McTester",
            Comment = string.Empty
        };

        var domain = new Domain
        {
            Guid = new Guid("4c465763-f93f-4496-9f4b-4029cb2642c0"),
            Id = 725,
            Name = "The Hard Place",
            Deleted = true
        };

        DomainManagerRepository.Domains.Add(domain);

        var createDomain = new CreateDomain
        {
            Guid = domain.Guid,
            Name = "The Hard Place Revisited"
        };

        //Act
        await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None);

        //Assert
        Assert.That(DomainManagerRepository.Domains, Has.Count.EqualTo(1));

        Assert.That(domain.Guid, Is.EqualTo(createDomain.Guid));
        Assert.That(domain.Name, Is.EqualTo(createDomain.Name));
        Assert.That(domain.Id, Is.EqualTo(725));
        Assert.That(domain.Deleted, Is.False);

        Assert.That(DomainManagerRepository.AddAdministratorRoleCalled, Is.Null);
    }

    [Test]
    public async Task CreateDomainAsync_WhenDeletedDomainExistsAndNameOnlyProvided_DomainIsRestored()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 100,
            UserDisplayName = "Testy McTester",
            Comment = string.Empty
        };

        var domain = new Domain
        {
            Guid = new Guid("4c465763-f93f-4496-9f4b-4029cb2642c0"),
            Id = 725,
            Name = "The Hard Place",
            Deleted = true
        };

        DomainManagerRepository.Domains.Add(domain);

        var createDomain = new CreateDomain
        {
            Name = domain.Name
        };

        //Act
        await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None);

        //Assert
        Assert.That(DomainManagerRepository.Domains, Has.Count.EqualTo(1));

        Assert.That(domain.Id, Is.EqualTo(725));
        Assert.That(domain.Deleted, Is.False);

        Assert.That(DomainManagerRepository.AddAdministratorRoleCalled, Is.Null);
    }

    [Test]
    public async Task CreateDomainAsync_WhenDomainIsNew_GetsCreated()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 100,
            UserDisplayName = "Testy McTester",
            Comment = string.Empty
        };

        var createDomain = new CreateDomain
        {
            Guid = new Guid("814758b1-d7a3-4708-96dd-338c5382c3f5"),
            Name = "Trotters Independent Traders"
        };

        //Act
        await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None);

        //Assert
        Assert.That(DomainManagerRepository.Domains, Has.Count.EqualTo(1));

        var domain = DomainManagerRepository.Domains.First();
        Assert.That(domain.Guid, Is.EqualTo(createDomain.Guid));
        Assert.That(domain.Name, Is.EqualTo(createDomain.Name));
        Assert.That(domain.SsoProvider, Is.Null);

        Assert.That(DomainManagerRepository.AddAdministratorRoleCalled, Is.EqualTo(domain));
        Assert.That(DomainManagerRepository.AddAdministratorRoleCalled, Is.Not.Null);
    }

    [Test]
    public async Task CreateDomainAsync_WhenDomainConsainsSsoProvider_GetsCreated()
    {
        //Arrange
        var ssoProviderId = 1;

        SoManagerRepository.SsoProviders.Add( new SsoProvider
        {
            Id = ssoProviderId
        });

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

        var createDomain = new CreateDomain
        {
            Guid = new Guid("814758b1-d7a3-4708-96dd-338c5382c3f5"),
            Name = "Trotters Independent Traders",
            SsoProviderId = new GeneralIdRef{ Id = ssoProviderId }
        };

        //Act
        await DomainManager.CreateDomainAsync(auditUserDetails, createDomain, CancellationToken.None);

        //Assert
        Assert.That(DomainManagerRepository.Domains, Has.Count.EqualTo(1));

        var domain = DomainManagerRepository.Domains.First();
        Assert.That(domain.SsoProvider, Is.Not.Null);


        Assert.That(domain.SsoProvider?.Id, Is.EqualTo(ssoProviderId));
    }
}