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

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

/// <summary>
/// Regression tests for CentralUI-002. Site-scoped Deployment permissions are
/// written as <c>SiteId</c> claims at login but were never read — Deployment
/// pages listed and acted on every site. <see cref="SiteScopeService"/> is the
/// shared helper that reads those claims; these tests pin its behaviour.
/// </summary>
public class SiteScopeServiceTests
{
    private sealed class StubAuthStateProvider : AuthenticationStateProvider
    {
        private readonly ClaimsPrincipal _user;
        public StubAuthStateProvider(ClaimsPrincipal user) => _user = user;
        public override Task<AuthenticationState> GetAuthenticationStateAsync()
            => Task.FromResult(new AuthenticationState(_user));
    }

    private static SiteScopeService ForUser(params Claim[] claims)
    {
        var identity = new ClaimsIdentity(claims, authenticationType: "TestCookie");
        return new SiteScopeService(new StubAuthStateProvider(new ClaimsPrincipal(identity)));
    }

    private static Claim Role(string role) => new(JwtTokenService.RoleClaimType, role);
    private static Claim SiteClaim(int id) => new(JwtTokenService.SiteIdClaimType, id.ToString());

    private static List<Site> Sites(params int[] ids)
        => ids.Select(id => new Site($"Site{id}", $"SITE-{id}") { Id = id }).ToList();

    [Fact]
    public async Task DeploymentUserWithNoSiteClaims_IsSystemWide()
    {
        var svc = ForUser(Role("Deployer"));

        Assert.True(await svc.IsSystemWideAsync());
        Assert.Empty(await svc.PermittedSiteIdsAsync());
    }

    [Fact]
    public async Task SystemWideUser_FilterSites_ReturnsAllSites()
    {
        var svc = ForUser(Role("Deployer"));

        var filtered = await svc.FilterSitesAsync(Sites(1, 2, 3));

        Assert.Equal(new[] { 1, 2, 3 }, filtered.Select(s => s.Id));
    }

    [Fact]
    public async Task ScopedUser_FilterSites_ReturnsOnlyPermittedSites()
    {
        // Regression: a Deployment user scoped to sites 1 and 3 must NOT see site 2.
        var svc = ForUser(Role("Deployer"), SiteClaim(1), SiteClaim(3));

        var filtered = await svc.FilterSitesAsync(Sites(1, 2, 3, 4));

        Assert.Equal(new[] { 1, 3 }, filtered.Select(s => s.Id).OrderBy(x => x));
    }

    [Fact]
    public async Task ScopedUser_IsSiteAllowed_OnlyForGrantedSites()
    {
        var svc = ForUser(Role("Deployer"), SiteClaim(5));

        Assert.True(await svc.IsSiteAllowedAsync(5));
        Assert.False(await svc.IsSiteAllowedAsync(6));
    }

    [Fact]
    public async Task ScopedUser_IsNotSystemWide_AndReportsItsPermittedIds()
    {
        var svc = ForUser(Role("Deployer"), SiteClaim(7), SiteClaim(9));

        Assert.False(await svc.IsSystemWideAsync());
        Assert.Equal(new[] { 7, 9 }, (await svc.PermittedSiteIdsAsync()).OrderBy(x => x));
    }

    [Fact]
    public async Task SystemWideUser_IsSiteAllowed_ForAnySite()
    {
        var svc = ForUser(Role("Deployer"));

        Assert.True(await svc.IsSiteAllowedAsync(1));
        Assert.True(await svc.IsSiteAllowedAsync(999));
    }
}
