using e_suite.API.Common.exceptions;
using e_suite.API.Common.models;
using e_suite.Database.Core.Extensions;
using e_suite.Database.Core.Tables.UserManager;
using eSuite.Core.Miscellaneous;
using NUnit.Framework;
using System.Data;
using UserManager.UnitTests.Helpers;

namespace UserManager.UnitTests.UserManager;

[TestFixture]
public class EditUserUnitTests : UserManagerTestBase<object>
{
    [SetUp]
    public override async Task Setup()
    {
        await base.Setup();
    }

    [Test]
    public async Task EditUser_ExistingUser_UpdatesCorrectly()
    {
        //Arrange
        var domain = UserManagerRepository.Domains[1];

        var user = new User
        {
            Id = 8472,
            Guid = new Guid("6deef5e4-9af3-4966-bf8d-e48dc6ea0f73"),
            DomainId = domain.Id,
            Domain = domain
        };

        UserManagerRepository.Users.Add(user);

        var editUser = new EditUser
        {
            Id = new GeneralIdRef
            {
                Guid = user.Guid
            },
            Domain = domain.ToGeneralIdRef()!,
            FirstName = "Testy",
            LastName = "McTester",
            MiddleNames = "The Tested",
            Email = "Testy@tester.tested"
        };

        //Act
        await UserManager.EditUser(AuditUserDetails, editUser, CancellationToken.None);

        //Assert
        var result = UserManagerRepository.Users.Single(x => x.Guid == user.Guid);

        Assert.Multiple(() =>
        {
            Assert.That(result.Guid, Is.EqualTo(user.Guid));
            Assert.That(result.Id, Is.EqualTo(user.Id));
            Assert.That(result.DomainId, Is.EqualTo(domain.Id));
            Assert.That(result.Domain, Is.EqualTo(domain));
            Assert.That(result.Active, Is.EqualTo(true));
            Assert.That(result.Email, Is.EqualTo(editUser.Email));
            Assert.That(result.FirstName, Is.EqualTo(editUser.FirstName));
            Assert.That(result.MiddleNames, Is.EqualTo(editUser.MiddleNames));
            Assert.That(result.LastName, Is.EqualTo(editUser.LastName));
        });
    }

    [Test]
    public void EditUser_ExistingUserIsDeleted_ThrowsException()
    {
        //Arrange
        var domain = UserManagerRepository.Domains[1];

        var user = new User
        {
            Id = 8472,
            Guid = new Guid("6deef5e4-9af3-4966-bf8d-e48dc6ea0f73"),
            DomainId = domain.Id,
            Domain = domain,
            Active = false
        };

        UserManagerRepository.Users.Add(user);

        var editUser = new EditUser
        {
            Id = new GeneralIdRef
            {
                Guid = user.Guid
            },
            Domain = domain.ToGeneralIdRef()!,
            FirstName = "Testy",
            LastName = "McTester",
            MiddleNames = "The Tested",
            Email = "Testy@tester.tested"
        };

        //Act & Assert
        var result = Assert.ThrowsAsync<DeletedRowInaccessibleException>(async () =>
            await UserManager.EditUser(AuditUserDetails, editUser, CancellationToken.None)
        );

        Assert.That(result!.Message, Is.EqualTo("This user is inactive so cannot be modified. You will need to create the user again."));
    }

    [Test]
    public void EditUser_UserDoesNotExist_ThrowsNotFoundException()
    {
        //Arrange
        var domain = UserManagerRepository.Domains[1];

        var user = new User
        {
            Id = 8472,
            Guid = new Guid("6deef5e4-9af3-4966-bf8d-e48dc6ea0f73"),
            DomainId = domain.Id,
            Domain = domain
        };

        var editUser = new EditUser
        {
            Id = new GeneralIdRef
            {
                Guid = user.Guid
            },
            Domain = domain.ToGeneralIdRef()!,
        };

        //Assert
        var result = Assert.ThrowsAsync<NotFoundException>(async () =>
        {
            //Act
            await UserManager.EditUser(AuditUserDetails, editUser, CancellationToken.None);
        });

        Assert.That(result!.Message, Is.EqualTo("unable to find user"));
    }

    [Test]
    public void EditUser_UserDomainDoesNotExist_ThrowsNotFoundException()
    {
        //Arrange
        var domain = UserManagerRepository.Domains[1];

        var user = new User
        {
            Id = 8472,
            Guid = new Guid("6deef5e4-9af3-4966-bf8d-e48dc6ea0f73"),
            DomainId = domain.Id,
            Domain = domain
        };

        UserManagerRepository.Users.Add(user);

        var editUser = new EditUser
        {
            Id = new GeneralIdRef
            {
                Guid = user.Guid
            },
            Domain = new GeneralIdRef
            {
                Id = 700
            },
        };

        //Assert
        //Assert
        var result = Assert.ThrowsAsync<NotFoundException>(async () =>
        {
            //Act
            await UserManager.EditUser(AuditUserDetails, editUser, CancellationToken.None);
        });

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