using Grpc.Core;
using ZB.MOM.WW.MxGateway.Contracts.Proto;
using ZB.MOM.WW.MxGateway.Server.Grpc;

namespace ZB.MOM.WW.MxGateway.Tests.Gateway.Grpc;

public sealed class MxAccessGrpcRequestValidatorTests
{
    private static MxCommandRequest DrainRequest(uint maxEvents) => new()
    {
        SessionId = "session-1",
        Command = new MxCommand
        {
            Kind = MxCommandKind.DrainEvents,
            DrainEvents = new DrainEventsCommand { MaxEvents = maxEvents },
        },
    };

    /// <summary>
    /// Verifies a DrainEvents request within the per-request ceiling passes validation, including the
    /// <c>max_events = 0</c> "worker default cap" sentinel.
    /// </summary>
    /// <param name="maxEvents">The requested drain-events ceiling to validate.</param>
    [Theory]
    [InlineData(0u)]
    [InlineData(1u)]
    [InlineData(10_000u)]
    public void ValidateInvoke_AllowsDrainEvents_WithinCeiling(uint maxEvents)
    {
        MxAccessGrpcRequestValidator validator = new();
        validator.ValidateInvoke(DrainRequest(maxEvents));
    }

    /// <summary>
    /// Verifies a DrainEvents request above the per-request ceiling is rejected with InvalidArgument
    /// so one accepted request cannot pack an unbounded reply frame.
    /// </summary>
    [Fact]
    public void ValidateInvoke_RejectsDrainEvents_AboveCeiling()
    {
        MxAccessGrpcRequestValidator validator = new();
        RpcException exception = Assert.Throws<RpcException>(() => validator.ValidateInvoke(DrainRequest(10_001)));
        Assert.Equal(StatusCode.InvalidArgument, exception.StatusCode);
        Assert.Contains("max_events", exception.Status.Detail, StringComparison.Ordinal);
    }
}
