using System.Security.Claims;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using SIGCM2.Api.Middleware;
using Xunit;

namespace SIGCM2.Api.Tests.Audit;

/// UDT-010 Batch 4 — AuditActorMiddleware unit tests (Strict TDD).
/// Reads ActorUserId from the JWT "sub" claim after auth middleware populates HttpContext.User.
public sealed class AuditActorMiddlewareTests
{
    [Fact]
    public async Task Invoke_AuthenticatedUserWithSubClaim_SetsActorUserId()
    {
        var ctx = new DefaultHttpContext();
        ctx.User = new ClaimsPrincipal(new ClaimsIdentity(new[]
        {
            new Claim("sub", "42"),
            new Claim("rol", "admin"),
        }, authenticationType: "Bearer"));

        var mw = new AuditActorMiddleware(_ => Task.CompletedTask);
        await mw.InvokeAsync(ctx);

        ctx.Items["audit:actorUserId"].Should().Be(42);
    }

    [Fact]
    public async Task Invoke_AnonymousRequest_LeavesActorUserIdNull()
    {
        var ctx = new DefaultHttpContext();
        // User is an unauthenticated ClaimsPrincipal by default
        var mw = new AuditActorMiddleware(_ => Task.CompletedTask);

        await mw.InvokeAsync(ctx);

        ctx.Items.TryGetValue("audit:actorUserId", out var value).Should().BeFalse();
        value.Should().BeNull();
    }

    [Fact]
    public async Task Invoke_AuthenticatedWithoutSubClaim_LeavesActorUserIdNull()
    {
        var ctx = new DefaultHttpContext();
        ctx.User = new ClaimsPrincipal(new ClaimsIdentity(new[]
        {
            new Claim("name", "admin"),
        }, authenticationType: "Bearer"));

        var mw = new AuditActorMiddleware(_ => Task.CompletedTask);
        await mw.InvokeAsync(ctx);

        ctx.Items.TryGetValue("audit:actorUserId", out _).Should().BeFalse();
    }

    [Fact]
    public async Task Invoke_SubClaimIsNonNumeric_LeavesActorUserIdNull()
    {
        var ctx = new DefaultHttpContext();
        ctx.User = new ClaimsPrincipal(new ClaimsIdentity(new[]
        {
            new Claim("sub", "not-an-int"),
        }, authenticationType: "Bearer"));

        var mw = new AuditActorMiddleware(_ => Task.CompletedTask);
        await mw.InvokeAsync(ctx);

        ctx.Items.TryGetValue("audit:actorUserId", out _).Should().BeFalse();
    }

    [Fact]
    public async Task Invoke_CallsNextDelegate()
    {
        var ctx = new DefaultHttpContext();
        var nextCalled = false;
        var mw = new AuditActorMiddleware(_ =>
        {
            nextCalled = true;
            return Task.CompletedTask;
        });

        await mw.InvokeAsync(ctx);

        nextCalled.Should().BeTrue();
    }
}
