using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using ZB.MOM.WW.ScadaBridge.CentralUI.Auth;
using ZB.MOM.WW.ScadaBridge.Security;

namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Auth;

/// <summary>
/// Regression tests for CentralUI-024. Ten components each copy-pasted a
/// <c>GetCurrentUserAsync</c> helper using the magic string
/// <c>FindFirst("Username")</c>, and <c>NavMenu</c>/<c>Dashboard</c> used
/// <c>FindFirst("DisplayName")</c>. A rename of the claim type in
/// <see cref="JwtTokenService"/> (the single source of truth) would have
/// silently broken every call site. The shared
/// <see cref="ClaimsPrincipalExtensions"/> helpers now resolve the claim type
/// through the <c>JwtTokenService</c> constants.
/// </summary>
public class ClaimsPrincipalExtensionsTests
{
    private static ClaimsPrincipal Principal(params Claim[] claims)
        => new(new ClaimsIdentity(claims, authenticationType: "TestCookie"));

    [Fact]
    public void GetUsername_ResolvesTheJwtTokenServiceUsernameClaim()
    {
        var principal = Principal(
            new Claim(JwtTokenService.UsernameClaimType, "alice"));

        Assert.Equal("alice", principal.GetUsername());
    }

    [Fact]
    public void GetUsername_FallsBackToUnknown_WhenClaimAbsent()
    {
        var principal = Principal();

        Assert.Equal(ClaimsPrincipalExtensions.UnknownUser, principal.GetUsername());
    }

    [Fact]
    public void GetDisplayName_ResolvesTheJwtTokenServiceDisplayNameClaim()
    {
        var principal = Principal(
            new Claim(JwtTokenService.DisplayNameClaimType, "Alice Anderson"));

        Assert.Equal("Alice Anderson", principal.GetDisplayName());
    }

    [Fact]
    public void GetDisplayName_IsNull_WhenClaimAbsent()
    {
        Assert.Null(Principal().GetDisplayName());
    }

    [Fact]
    public async Task GetCurrentUsernameAsync_ReadsUsernameFromAuthState()
    {
        var principal = Principal(
            new Claim(JwtTokenService.UsernameClaimType, "bob"));
        var provider = new StubAuthStateProvider(
            new AuthenticationState(principal));

        Assert.Equal("bob", await provider.GetCurrentUsernameAsync());
    }

    [Fact]
    public void Username_LookupTracksAJwtTokenServiceRename()
    {
        // The lookup must NOT use a hard-coded "Username" literal: if the
        // constant's *value* is ever changed, the helper must follow it. Build a
        // principal whose claim carries the JwtTokenService constant's current
        // value and confirm the helper finds it via that same constant.
        var principal = Principal(
            new Claim(JwtTokenService.UsernameClaimType, "carol"));

        Assert.Equal("carol",
            principal.FindFirst(JwtTokenService.UsernameClaimType)?.Value);
        Assert.Equal("carol", principal.GetUsername());
    }

    private sealed class StubAuthStateProvider : AuthenticationStateProvider
    {
        private readonly AuthenticationState _state;
        public StubAuthStateProvider(AuthenticationState state) => _state = state;
        public override Task<AuthenticationState> GetAuthenticationStateAsync()
            => Task.FromResult(_state);
    }
}
