using ZB.MOM.WW.MxGateway.Server.Security.Authentication;
using ZB.MOM.WW.MxGateway.Server.Security.Authorization;
using ZB.MOM.WW.MxGateway.Tests.TestSupport;

namespace ZB.MOM.WW.MxGateway.Tests.Security.Authorization;

/// <summary>
///     Unit tests for <see cref="GatewayBrowseScopeProvider"/>, the host seam that feeds the
///     calling API key's <c>BrowseSubtrees</c> constraint into the shared library's Galaxy
///     browse RPCs via <c>IGalaxyBrowseScopeProvider</c>.
/// </summary>
public sealed class GatewayBrowseScopeProviderTests
{
    /// <summary>
    ///     With an ambient identity whose effective constraints carry a browse subtree,
    ///     the provider returns exactly that subtree list to the library.
    /// </summary>
    [Fact]
    public void ResolveBrowseSubtrees_WithCurrentIdentity_ReturnsConstraintBrowseSubtrees()
    {
        StubIdentityAccessor accessor = new(CreateIdentity(["AreaA"]));
        GatewayBrowseScopeProvider provider = new(accessor);

        IReadOnlyList<string>? result = provider.ResolveBrowseSubtrees(new TestServerCallContext());

        Assert.Equal(["AreaA"], result);
    }

    /// <summary>
    ///     With no ambient identity, the provider falls back to the empty browse-subtree
    ///     list, which the library treats as "no scoping" rather than denying everything.
    /// </summary>
    [Fact]
    public void ResolveBrowseSubtrees_WithNoCurrentIdentity_ReturnsEmptyList()
    {
        StubIdentityAccessor accessor = new(current: null);
        GatewayBrowseScopeProvider provider = new(accessor);

        IReadOnlyList<string>? result = provider.ResolveBrowseSubtrees(new TestServerCallContext());

        Assert.NotNull(result);
        Assert.Empty(result);
    }

    private static ApiKeyIdentity CreateIdentity(IReadOnlyList<string> browseSubtrees) =>
        new(
            KeyId: "operator01",
            KeyPrefix: "mxgw_operator01",
            DisplayName: "Operator",
            Scopes: new HashSet<string>(StringComparer.Ordinal),
            Constraints: ApiKeyConstraints.Empty with { BrowseSubtrees = browseSubtrees });

    private sealed class StubIdentityAccessor(ApiKeyIdentity? current) : IGatewayRequestIdentityAccessor
    {
        /// <inheritdoc />
        public ApiKeyIdentity? Current { get; } = current;

        /// <inheritdoc />
        public IDisposable Push(ApiKeyIdentity identity) => throw new NotSupportedException();
    }
}
