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

namespace e_suite.Modules.RoleManager.UnitTests;

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

    [Test]
    public void CreateRole_DomainIdNotSet_ThrowsInvalidOperationException()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 2562,
            UserDisplayName = "Testy McTester",
        };

        var newRole = new CreateRole
        {
            
        };

        //Assert
        var actualResult = Assert.ThrowsAsync<InvalidOperationException>(async () =>
        {
            //Act
            await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None);
        });
        Assert.That(actualResult!.Message, Is.EqualTo("DomainId cannot be null"));
    }

    [Test]
    public void CreateRole_DomainDoesNotExist_ThrowsNotFoundException()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 2562,
            UserDisplayName = "Testy McTester",
        };

        var newRole = new CreateRole
        {
            DomainId = new GeneralIdRef
            {
                Guid = new Guid("2f244fdd-f996-4936-872b-19b782a13e53")
            }
        };

        //Assert
        var actualResult = Assert.ThrowsAsync<NotFoundException>(async () =>
        {
            //Act
            await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None);
        });
        Assert.That(actualResult!.Message, Is.EqualTo("Unable to find domain"));
    }

    [Test]
    public void CreateRole_RoleAlreadyExists_ThrowsExistsException()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 2562,
            UserDisplayName = "Testy McTester",
        };

        var roleGuid = "ef8a2d5a-8842-4cc2-af5b-ef82c43b172c";

        var role = new Role
        {
            Id = 234,
            Guid = new Guid(roleGuid)
        } ;

        RoleManagerRepository.Roles.Add(role);

        var newRole = new CreateRole
        {
            Guid = role.Guid,
            DomainId = new GeneralIdRef
            {
                Guid = new Guid("2f244fdd-f996-4936-872b-19b782a13e53")
            }
        };

        //Assert
        var actualResult = Assert.ThrowsAsync<ExistsException>(async () =>
        {
            //Act
            await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None);
        });
        Assert.That(actualResult!.Message, Is.EqualTo($"Role with guid '{roleGuid}' already exists"));
    }

    [Test]
    public void CreateRole_RoleNameAlreadyExists_ThrowsExistsException()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 2562,
            UserDisplayName = "Testy McTester",
        };

        var roleName = "My testing Role";

        var domain = new Domain
        {
            Id = 1,
            Guid = new Guid("3099cfcc-451d-4ff6-a96f-064065532c91"),
            Name = "Test Domain",
        };
        DomainRepository.Domains.Add(domain);


        var role = new Role
        {
            Id = 234,
            Guid = new Guid("d95eef36-cabb-4856-b413-9f3b54375734"),
            Name = roleName,
            Domain = domain,
            DomainId = domain.Id
        };
        RoleManagerRepository.Roles.Add(role);

        var newRole = new CreateRole
        {
            Guid = new Guid("05b45bd7-9d87-42a9-a4c7-011c3265f5b5"),
            DomainId = new GeneralIdRef
            {
                Guid = domain.Guid
            },
            Name = roleName
        };

        //Assert
        var actualResult = Assert.ThrowsAsync<ExistsException>(async () =>
        {
            //Act
            await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None);
        });
        Assert.That(actualResult!.Message, Is.EqualTo($"Role with name '{roleName}' already exists"));
    }

    [Test]
    public async Task CreateRole_EverythingOK_RoleIsCreated()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 2562,
            UserDisplayName = "Testy McTester",
        };

        var roleName = "My testing Role";

        var domain = new Domain
        {
            Id = 1,
            Guid = new Guid("3099cfcc-451d-4ff6-a96f-064065532c91"),
            Name = "Test Domain",
        };
        DomainRepository.Domains.Add(domain);

        var newRole = new CreateRole
        {
            Guid = new Guid("05b45bd7-9d87-42a9-a4c7-011c3265f5b5"),
            DomainId = new GeneralIdRef
            {
                Guid = domain.Guid
            },
            Name = roleName
        };

        //Act
        await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None);

        //Assert
        Assert.That(RoleManagerRepository.Roles, Has.Count.EqualTo(1));
        var actualRole = RoleManagerRepository.Roles[0];
        Assert.That(actualRole.Name, Is.EqualTo(newRole.Name));
        Assert.That(actualRole.Guid, Is.EqualTo(newRole.Guid));
    }

    [Test]
    public async Task CreateRole_GuidNotSupplied_GuidIsAssigned()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 2562,
            UserDisplayName = "Testy McTester",
        };

        var roleName = "My testing Role";

        var domain = new Domain
        {
            Id = 1,
            Guid = new Guid("3099cfcc-451d-4ff6-a96f-064065532c91"),
            Name = "Test Domain",
        };
        DomainRepository.Domains.Add(domain);

        var newRole = new CreateRole
        {
            DomainId = new GeneralIdRef
            {
                Guid = domain.Guid
            },
            Name = roleName
        };

        //Act
        await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None);

        //Assert
        Assert.That(RoleManagerRepository.Roles, Has.Count.EqualTo(1));
        var actualRole = RoleManagerRepository.Roles[0];
        Assert.That(actualRole.Guid, Is.Not.Null);
    }

    [Test]
    public async Task CreateRole_SoftDeletedRoleExists_RoleIsUnDeletedAnd()
    {
        //Arrange
        var auditUserDetails = new AuditUserDetails
        {
            UserId = 2562,
            UserDisplayName = "Testy McTester",
        };

        var roleName = "My testing Role";

        var domain = new Domain
        {
            Id = 1,
            Guid = new Guid("3099cfcc-451d-4ff6-a96f-064065532c91"),
            Name = "Test Domain",
        };
        DomainRepository.Domains.Add(domain);


        var role = new Role
        {
            Id = 234,
            Guid = new Guid("d95eef36-cabb-4856-b413-9f3b54375734"),
            Name = roleName,
            Domain = domain,
            DomainId = domain.Id,
            Deleted = true
        };
        RoleManagerRepository.Roles.Add(role);

        var newRole = new CreateRole
        {
            Guid = role.Guid,
            DomainId = new GeneralIdRef
            {
                Guid = domain.Guid
            },
            Name = "Modified RoleName"
        };
        
        //Act
        await RoleManager.CreateRole(auditUserDetails, newRole, CancellationToken.None);
        
        //Assert
        Assert.That(RoleManagerRepository.RoleEdited, Is.Not.Null);
        Assert.That(RoleManagerRepository.RoleEdited!.Deleted, Is.False);
        Assert.That(RoleManagerRepository.RoleEdited!.Name, Is.EqualTo(newRole.Name));
    }
}