using System;
using System.Linq;
using System.Security.Claims;
using StellaOps.Auth.Abstractions;
using Xunit;

namespace StellaOps.Auth.Abstractions.Tests;

public class StellaOpsPrincipalBuilderTests
{
    [Fact]
    public void NormalizedScopes_AreSortedDeduplicatedLowerCased()
    {
        var builder = new StellaOpsPrincipalBuilder()
            .WithScopes(new[] { "Feedser.Jobs.Trigger", " feedser.jobs.trigger ", "AUTHORITY.USERS.MANAGE" })
            .WithAudiences(new[] { " api://feedser ", "api://cli", "api://feedser" });

        Assert.Equal(
            new[] { "authority.users.manage", "feedser.jobs.trigger" },
            builder.NormalizedScopes);

        Assert.Equal(
            new[] { "api://cli", "api://feedser" },
            builder.Audiences);
    }

    [Fact]
    public void Build_ConstructsClaimsPrincipalWithNormalisedValues()
    {
        var now = DateTimeOffset.UtcNow;
        var builder = new StellaOpsPrincipalBuilder()
            .WithSubject(" user-1 ")
            .WithClientId(" cli-01 ")
            .WithTenant(" default ")
            .WithName("  Jane Doe ")
            .WithIdentityProvider(" internal ")
            .WithSessionId(" session-123 ")
            .WithTokenId(Guid.NewGuid().ToString("N"))
            .WithAuthenticationMethod("password")
            .WithAuthenticationType(" custom ")
            .WithScopes(new[] { "Feedser.Jobs.Trigger", "AUTHORITY.USERS.MANAGE" })
            .WithAudience(" api://feedser ")
            .WithIssuedAt(now)
            .WithExpires(now.AddMinutes(5))
            .AddClaim(" custom ", " value ");

        var principal = builder.Build();
        var identity = Assert.IsType<ClaimsIdentity>(principal.Identity);

        Assert.Equal("custom", identity.AuthenticationType);
        Assert.Equal("Jane Doe", identity.Name);
        Assert.Equal("user-1", principal.FindFirstValue(StellaOpsClaimTypes.Subject));
        Assert.Equal("cli-01", principal.FindFirstValue(StellaOpsClaimTypes.ClientId));
        Assert.Equal("default", principal.FindFirstValue(StellaOpsClaimTypes.Tenant));
        Assert.Equal("internal", principal.FindFirstValue(StellaOpsClaimTypes.IdentityProvider));
        Assert.Equal("session-123", principal.FindFirstValue(StellaOpsClaimTypes.SessionId));
        Assert.Equal("value", principal.FindFirstValue("custom"));

        var scopeClaims = principal.Claims.Where(claim => claim.Type == StellaOpsClaimTypes.ScopeItem).Select(claim => claim.Value).ToArray();
        Assert.Equal(new[] { "authority.users.manage", "feedser.jobs.trigger" }, scopeClaims);

        var scopeList = principal.FindFirstValue(StellaOpsClaimTypes.Scope);
        Assert.Equal("authority.users.manage feedser.jobs.trigger", scopeList);

        var audienceClaims = principal.Claims.Where(claim => claim.Type == StellaOpsClaimTypes.Audience).Select(claim => claim.Value).ToArray();
        Assert.Equal(new[] { "api://feedser" }, audienceClaims);

        var issuedAt = principal.FindFirstValue("iat");
        Assert.Equal(now.ToUnixTimeSeconds().ToString(), issuedAt);

        var expires = principal.FindFirstValue("exp");
        Assert.Equal(now.AddMinutes(5).ToUnixTimeSeconds().ToString(), expires);
    }
}
