using e_suite.API.Common.exceptions;
using e_suite.Database.Core.Tables.Domain;
using e_suite.Database.Core.Tables.UserManager;
using NUnit.Framework;
using UserManager.UnitTests.Helpers;

namespace UserManager.UnitTests.UserManager;

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

    [Test]
    public async Task LinkSsoProfileToUser_UserExists_LinksSsoProividerToUser()
    {
        //Arrange
        var user = new User
        {
            Email = "testuser@sun-strategy.com",
            Domain = new Domain()
        };

        await UserManagerRepository.AddUser(AuditUserDetails, user, default);

        var ssoSubject = "ssoUserId12345";

        //Act
        await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 1, ssoSubject, false, CancellationToken.None);

        //Assert
        Assert.That(user.SsoProviderId, Is.EqualTo(1));
        Assert.That(user.SsoProvider, Is.Null);
        Assert.That(user.SsoSubject, Is.EqualTo(ssoSubject));
    }

    [Test]
    public async Task LinkSsoProfileToUser_DomainLevelSsoProvider_DoesNotSetUserSsoProviderId()
    {
        //Arrange
        var user = new User
        {
            Email = "testuser@sun-strategy.com",
            Domain = new Domain{ SsoProviderId = 1}
        };

        await UserManagerRepository.AddUser(AuditUserDetails, user, default);

        var ssoSubject = "ssoUserId12345";

        //Act
        await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, user.Domain.SsoProviderId.Value, ssoSubject, false, CancellationToken.None);

        //Assert
        Assert.That(user.SsoProviderId, Is.Null);
        Assert.That(user.SsoProvider, Is.Null);
        Assert.That(user.SsoSubject, Is.EqualTo(ssoSubject));
    }

    [TestCase(false)]
    [TestCase(true)]
    public async Task LinkSsoProfileToUser_setEmailConfirmedIsFalse_DoesNotChangeTheValueOfEmailConfirmed( bool emailConfirmed)
    {
        //Arrange
        var user = new User
        {
            Email = "testuser@sun-strategy.com",
            EmailConfirmed = emailConfirmed,
            Domain = new Domain()
        };

        await UserManagerRepository.AddUser(AuditUserDetails, user, default);

        var ssoSubject = "ssoUserId12345";

        //Act
        await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 1, ssoSubject, false, CancellationToken.None);

        //Assert
        Assert.That(user.EmailConfirmed, Is.EqualTo(emailConfirmed));
    }

    [Test]
    public async Task LinkSsoProfileToUser_setEmailConfirmedIsTrue_SetsEmailConfirmedTrue()
    {
        //Arrange
        var user = new User
        {
            Email = "testuser@sun-strategy.com",
            EmailConfirmed = false,
            Domain = new Domain()
        };

        await UserManagerRepository.AddUser(AuditUserDetails, user, default);

        var ssoSubject = "ssoUserId12345";

        //Act
        await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 1, ssoSubject, true, CancellationToken.None);

        //Assert
        Assert.That(user.EmailConfirmed, Is.EqualTo(true));
    }

    [Test]
    public void LinkSsoProfileToUser_UserIsNull_ThrowsNullReferenceException()
    {
        //Arrange
        var actualSsoProvider = UserManagerRepository.SsoProviders.First();

        User user = null!;

        //Act & Assert
        Assert.ThrowsAsync<NullReferenceException>(async () =>
        {
            await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 1, "ssoUserId12345", false, CancellationToken.None);
        });
    }

    [Test]
    public async Task LinkSsoProfileToUser_SsoProviderIdInvalid_ThrowsNotFoundException()
    {
        //Arrange
        var actualSsoProvider = UserManagerRepository.SsoProviders.First();

        var user = new User
        {
            Email = "testuser@sun-strategy.com",
            Domain = new Domain()
        };

        await UserManagerRepository.AddUser(AuditUserDetails, user, default);

        //Act & Assert
        Assert.ThrowsAsync<NotFoundException>(async () =>
        {
            await UserManager.LinkSsoProfileToUser(AuditUserDetails, user, 2, "ssoUserId12345", false, CancellationToken.None);
        });

        Assert.That(user.SsoProvider, Is.Null);
        Assert.That(user.SsoProviderId, Is.Null);
        Assert.That(user.SsoSubject, Is.EqualTo(string.Empty));
    }
}