using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Authorization;

namespace ZB.MOM.WW.OtOpcUa.Core.Tests.Authorization;

[Trait("Category", "Unit")]
public sealed class UserAuthorizationStateTests
{
    private static readonly DateTime Now = new(2026, 4, 19, 12, 0, 0, DateTimeKind.Utc);

    private static UserAuthorizationState Fresh(DateTime resolved) => new()
    {
        SessionId = "s",
        ClusterId = "c1",
        LdapGroups = ["cn=ops"],
        MembershipResolvedUtc = resolved,
        AuthGenerationId = 1,
        MembershipVersion = 1,
    };

    [Fact]
    public void FreshlyResolved_Is_NotStale_NorNeedsRefresh()
    {
        var session = Fresh(Now);

        session.IsStale(Now.AddMinutes(1)).ShouldBeFalse();
        session.NeedsRefresh(Now.AddMinutes(1)).ShouldBeFalse();
    }

    [Fact]
    public void NeedsRefresh_FiresAfter_FreshnessInterval()
    {
        var session = Fresh(Now);

        session.NeedsRefresh(Now.AddMinutes(16)).ShouldBeFalse("past freshness but also past the 5-min staleness ceiling — should be Stale, not NeedsRefresh");
    }

    [Fact]
    public void NeedsRefresh_TrueBetween_Freshness_And_Staleness_Windows()
    {
        // Custom: freshness=2 min, staleness=10 min → between 2 and 10 min NeedsRefresh fires.
        var session = Fresh(Now) with
        {
            MembershipFreshnessInterval = TimeSpan.FromMinutes(2),
            AuthCacheMaxStaleness = TimeSpan.FromMinutes(10),
        };

        session.NeedsRefresh(Now.AddMinutes(5)).ShouldBeTrue();
        session.IsStale(Now.AddMinutes(5)).ShouldBeFalse();
    }

    [Fact]
    public void IsStale_TrueAfter_StalenessWindow()
    {
        var session = Fresh(Now);

        session.IsStale(Now.AddMinutes(6)).ShouldBeTrue("default AuthCacheMaxStaleness is 5 min");
    }
}
