using FluentAssertions;
using Microsoft.AspNetCore.Http;
using NSubstitute;
using SIGCM2.Application.Audit;
using SIGCM2.Infrastructure.Audit;
using Xunit;

namespace SIGCM2.Application.Tests.Infrastructure.Audit;

/// UDT-010 Batch 4 — AuditContext (scoped IAuditContext impl) unit tests.
/// Reads audit fields from HttpContext.Items populated by CorrelationIdMiddleware + AuditActorMiddleware.
public sealed class AuditContextTests
{
    private static (AuditContext ctx, DefaultHttpContext http) Build()
    {
        var http = new DefaultHttpContext();
        var accessor = Substitute.For<IHttpContextAccessor>();
        accessor.HttpContext.Returns(http);
        return (new AuditContext(accessor), http);
    }

    [Fact]
    public void ReadsActorUserIdFromItems()
    {
        var (ctx, http) = Build();
        http.Items["audit:actorUserId"] = 42;

        ctx.ActorUserId.Should().Be(42);
    }

    [Fact]
    public void ActorUserId_IsNull_WhenNotPresent()
    {
        var (ctx, _) = Build();
        ctx.ActorUserId.Should().BeNull();
    }

    [Fact]
    public void ReadsIpAndUserAgentFromItems()
    {
        var (ctx, http) = Build();
        http.Items["audit:ip"] = "10.20.30.40";
        http.Items["audit:userAgent"] = "ua/1.0";

        ctx.Ip.Should().Be("10.20.30.40");
        ctx.UserAgent.Should().Be("ua/1.0");
    }

    [Fact]
    public void ReadsCorrelationIdFromItems()
    {
        var (ctx, http) = Build();
        var id = Guid.NewGuid();
        http.Items["audit:correlationId"] = id;

        ctx.CorrelationId.Should().Be(id);
    }

    [Fact]
    public void CorrelationId_IsEmpty_WhenNotPresent()
    {
        var (ctx, _) = Build();
        ctx.CorrelationId.Should().Be(Guid.Empty);
    }

    [Fact]
    public void AllFields_AreNull_WhenHttpContextIsNull()
    {
        var accessor = Substitute.For<IHttpContextAccessor>();
        accessor.HttpContext.Returns((HttpContext?)null);
        var ctx = new AuditContext(accessor);

        ctx.ActorUserId.Should().BeNull();
        ctx.ActorRoleId.Should().BeNull();
        ctx.Ip.Should().BeNull();
        ctx.UserAgent.Should().BeNull();
        ctx.CorrelationId.Should().Be(Guid.Empty);
    }

    [Fact]
    public void ActorRoleId_IsNull_Always_InB4()
    {
        // B4 middleware does not resolve rol code -> id; future batches may.
        var (ctx, http) = Build();
        http.Items["audit:actorUserId"] = 42;

        ctx.ActorRoleId.Should().BeNull();
    }
}
