namespace RpgRoller.Tests;

public sealed class ServiceAuthTests
{
    [Fact]
    public void Register_ValidatesRequiredFieldsAndDuplicates()
    {
        using var harness = ServiceTestSupport.CreateHarness();
        var service = harness.Service;

        var invalidUsername = service.Register("", "Password123", "Display");
        var invalidDisplay = service.Register("user", "Password123", "");
        var invalidPassword = service.Register("user", "short", "Display");
        var valid = service.Register("user", "Password123", "Display");
        var duplicate = service.Register("user", "Password123", "Display 2");

        Assert.False(invalidUsername.Succeeded);
        Assert.False(invalidDisplay.Succeeded);
        Assert.False(invalidPassword.Succeeded);
        Assert.True(valid.Succeeded);
        Assert.False(duplicate.Succeeded);
    }

    [Fact]
    public void Login_ValidatesCredentialsAndSessionLookup()
    {
        using var harness = ServiceTestSupport.CreateHarness();
        var service = harness.Service;
        service.Register("user", "Password123", "Display");

        var invalidUser = service.Login("missing", "Password123");
        var invalidPassword = service.Login("user", "bad-password");
        var valid = service.Login("user", "Password123");

        Assert.False(invalidUser.Succeeded);
        Assert.False(invalidPassword.Succeeded);
        Assert.True(valid.Succeeded);

        var sessionUser = service.GetUserBySession(valid.Value.SessionToken);
        Assert.NotNull(sessionUser);

        service.Logout(valid.Value.SessionToken);
        Assert.Null(service.GetUserBySession(valid.Value.SessionToken));
    }

    [Fact]
    public void Login_RehashesPasswordWhenHasherRequestsIt()
    {
        var hasher = new ServiceTestSupport.RehashingPasswordHasher();
        using var harness = ServiceTestSupport.CreateHarness(hasher);
        var service = harness.Service;

        service.Register("user", "Password123", "Display");
        var login = service.Login("user", "Password123");

        Assert.True(login.Succeeded);
        Assert.Equal(2, hasher.HashCalls);
    }

    [Fact]
    public void GetUsernames_RequiresAuthAndReturnsSortedUsernames()
    {
        using var harness = ServiceTestSupport.CreateHarness();
        var service = harness.Service;

        service.Register("zoe", "Password123", "Zoe");
        service.Register("amy", "Password123", "Amy");
        service.Register("bob", "Password123", "Bob");

        var unauthorized = service.GetUsernames(string.Empty);
        Assert.False(unauthorized.Succeeded);

        var session = ServiceTestSupport.GetValue(service.Login("bob", "Password123")).SessionToken;
        var usernames = ServiceTestSupport.GetValue(service.GetUsernames(session));
        Assert.Equal(["amy", "bob", "zoe"], usernames);
    }
}