// Tests for Account.SetServiceResponseThreshold / GetServiceResponseThreshold /
// IsServiceResponseOverdue / CheckServiceResponse.
// Go reference: server/accounts.go — SetServiceExportResponseThreshold (~line 2522),
//               ServiceExportResponseThreshold (~line 2510).

using NATS.Server.Auth;

namespace NATS.Server.Auth.Tests.Auth;

public class ResponseThresholdTests
{
    // ---------------------------------------------------------------------------
    // SetServiceResponseThreshold / GetServiceResponseThreshold
    // ---------------------------------------------------------------------------

    [Fact]
    public void SetServiceResponseThreshold_StoresThreshold()
    {
        // Go ref: accounts.go SetServiceExportResponseThreshold (~line 2522)
        var account = new Account("test");
        account.SetServiceResponseThreshold("svc.foo", TimeSpan.FromSeconds(5));

        account.ServiceResponseThresholds.ContainsKey("svc.foo").ShouldBeTrue();
        account.ServiceResponseThresholds["svc.foo"].ShouldBe(TimeSpan.FromSeconds(5));
    }

    [Fact]
    public void GetServiceResponseThreshold_ReturnsStored()
    {
        // Go ref: accounts.go ServiceExportResponseThreshold (~line 2510)
        var account = new Account("test");
        account.SetServiceResponseThreshold("svc.bar", TimeSpan.FromMilliseconds(200));

        account.GetServiceResponseThreshold("svc.bar").ShouldBe(TimeSpan.FromMilliseconds(200));
    }

    [Fact]
    public void GetServiceResponseThreshold_NotSet_ReturnsNull()
    {
        // Go ref: accounts.go ServiceExportResponseThreshold — returns error when export not found
        var account = new Account("test");

        account.GetServiceResponseThreshold("svc.unknown").ShouldBeNull();
    }

    // ---------------------------------------------------------------------------
    // IsServiceResponseOverdue
    // ---------------------------------------------------------------------------

    [Fact]
    public void IsServiceResponseOverdue_WithinThreshold_ReturnsFalse()
    {
        // Go ref: accounts.go respThresh check — elapsed < threshold ⇒ not overdue
        var account = new Account("test");
        account.SetServiceResponseThreshold("svc.a", TimeSpan.FromSeconds(10));

        account.IsServiceResponseOverdue("svc.a", TimeSpan.FromSeconds(9)).ShouldBeFalse();
    }

    [Fact]
    public void IsServiceResponseOverdue_ExceedsThreshold_ReturnsTrue()
    {
        // Go ref: accounts.go respThresh check — elapsed > threshold ⇒ overdue
        var account = new Account("test");
        account.SetServiceResponseThreshold("svc.b", TimeSpan.FromSeconds(1));

        account.IsServiceResponseOverdue("svc.b", TimeSpan.FromSeconds(2)).ShouldBeTrue();
    }

    [Fact]
    public void IsServiceResponseOverdue_NoThreshold_ReturnsFalse()
    {
        // Go ref: accounts.go — when no respThresh is set the timer never fires (never overdue)
        var account = new Account("test");

        account.IsServiceResponseOverdue("svc.unregistered", TimeSpan.FromHours(1)).ShouldBeFalse();
    }

    [Fact]
    public void SetServiceResponseThreshold_OverwritesPrevious()
    {
        // Go ref: accounts.go SetServiceExportResponseThreshold — se.respThresh = maxTime overwrites
        var account = new Account("test");
        account.SetServiceResponseThreshold("svc.c", TimeSpan.FromSeconds(5));
        account.SetServiceResponseThreshold("svc.c", TimeSpan.FromSeconds(30));

        account.GetServiceResponseThreshold("svc.c").ShouldBe(TimeSpan.FromSeconds(30));
    }

    // ---------------------------------------------------------------------------
    // CheckServiceResponse
    // ---------------------------------------------------------------------------

    [Fact]
    public void CheckServiceResponse_Found_NotOverdue()
    {
        // Go ref: accounts.go ServiceExportResponseThreshold + respThresh timer — within window
        var account = new Account("test");
        account.SetServiceResponseThreshold("svc.d", TimeSpan.FromSeconds(10));

        var result = account.CheckServiceResponse("svc.d", TimeSpan.FromSeconds(5));

        result.Found.ShouldBeTrue();
        result.IsOverdue.ShouldBeFalse();
        result.Threshold.ShouldBe(TimeSpan.FromSeconds(10));
        result.Elapsed.ShouldBe(TimeSpan.FromSeconds(5));
    }

    [Fact]
    public void CheckServiceResponse_Found_Overdue()
    {
        // Go ref: accounts.go respThresh timer fires — elapsed exceeded threshold
        var account = new Account("test");
        account.SetServiceResponseThreshold("svc.e", TimeSpan.FromSeconds(2));

        var result = account.CheckServiceResponse("svc.e", TimeSpan.FromSeconds(5));

        result.Found.ShouldBeTrue();
        result.IsOverdue.ShouldBeTrue();
        result.Threshold.ShouldBe(TimeSpan.FromSeconds(2));
        result.Elapsed.ShouldBe(TimeSpan.FromSeconds(5));
    }

    [Fact]
    public void CheckServiceResponse_NotFound()
    {
        // Go ref: accounts.go — no export defined, returns error; here Found=false
        var account = new Account("test");

        var result = account.CheckServiceResponse("svc.none", TimeSpan.FromSeconds(1));

        result.Found.ShouldBeFalse();
        result.IsOverdue.ShouldBeFalse();
        result.Threshold.ShouldBeNull();
        result.Elapsed.ShouldBe(TimeSpan.FromSeconds(1));
    }
}
