using System.Security.Claims;
using FluentAssertions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using TakeoutSaaS.Module.Authorization.Policies;

namespace TakeoutSaaS.Integration.Tests.Authorization;

public sealed class PermissionAuthorizationHandlerTests
{
    [Theory]
    [InlineData("platform-announcement:create")]
    [InlineData("platform-announcement:publish")]
    [InlineData("platform-announcement:revoke")]
    [InlineData("tenant-announcement:publish")]
    [InlineData("tenant-announcement:revoke")]
    public async Task GivenUserWithPermission_WhenAuthorize_ThenSucceeds(string permission)
    {
        // Arrange
        var requirement = new PermissionRequirement(new[] { permission });
        var identity = new ClaimsIdentity(new[]
        {
            new Claim(PermissionAuthorizationHandler.PermissionClaimType, permission)
        }, "Test");
        var user = new ClaimsPrincipal(identity);
        var context = new AuthorizationHandlerContext(new[] { requirement }, user, null);
        var handler = new PermissionAuthorizationHandler();

        // Act
        await handler.HandleAsync(context);

        // Assert
        context.HasSucceeded.Should().BeTrue();
    }

    [Fact]
    public async Task GivenUserWithoutPermission_WhenAuthorize_ThenFails()
    {
        // Arrange
        var requirement = new PermissionRequirement(new[] { "platform-announcement:create" });
        var user = new ClaimsPrincipal(new ClaimsIdentity(authenticationType: "Test"));
        var context = new AuthorizationHandlerContext(new[] { requirement }, user, null);
        var handler = new PermissionAuthorizationHandler();

        // Act
        await handler.HandleAsync(context);

        // Assert
        context.HasSucceeded.Should().BeFalse();
    }

    [Fact]
    public async Task GivenAuthenticatedUserWithoutPermission_WhenEvaluatingPolicy_ThenForbidden()
    {
        // Arrange
        var services = new ServiceCollection();
        services.AddAuthorization();
        services.AddSingleton<IAuthorizationPolicyProvider, PermissionAuthorizationPolicyProvider>();
        services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();
        var provider = services.BuildServiceProvider();

        var policyProvider = provider.GetRequiredService<IAuthorizationPolicyProvider>();
        var policy = await policyProvider.GetPolicyAsync(
            PermissionAuthorizationPolicyProvider.BuildPolicyName(new[] { "platform-announcement:create" }));

        var user = new ClaimsPrincipal(new ClaimsIdentity(authenticationType: "Test"));
        var authenticateResult = AuthenticateResult.Success(new AuthenticationTicket(user, "Test"));
        var httpContext = new DefaultHttpContext { RequestServices = provider, User = user };
        var evaluator = provider.GetRequiredService<IPolicyEvaluator>();

        // Act
        var result = await evaluator.AuthorizeAsync(policy!, authenticateResult, httpContext, resource: null);

        // Assert
        result.Forbidden.Should().BeTrue();
    }
}
