using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Models;
using NATS.Server.JetStream.Validation;
using NATS.Server.JetStream;

namespace NATS.Server.JetStream.Tests.JetStream.Api;

public class JetStreamApiLimitsParityBatch1Tests
{
    [Fact]
    public void Constants_match_go_reference_values()
    {
        JetStreamApiLimits.JSMaxDescriptionLen.ShouldBe(4_096);
        JetStreamApiLimits.JSMaxMetadataLen.ShouldBe(128 * 1024);
        JetStreamApiLimits.JSMaxNameLen.ShouldBe(255);
        JetStreamApiLimits.JSDefaultRequestQueueLimit.ShouldBe(10_000);
    }

    [Theory]
    [InlineData(null, false)]
    [InlineData("", false)]
    [InlineData(" ", false)]
    [InlineData("ORDERS", true)]
    [InlineData("ORD ERS", false)]
    [InlineData("ORDERS.*", false)]
    [InlineData("ORDERS.>", false)]
    public void IsValidName_enforces_expected_rules(string? name, bool expected)
    {
        JetStreamConfigValidator.IsValidName(name).ShouldBe(expected);
    }

    [Fact]
    public void Stream_create_rejects_name_over_max_length()
    {
        var manager = new StreamManager();
        var response = manager.CreateOrUpdate(new StreamConfig
        {
            Name = new string('S', JetStreamApiLimits.JSMaxNameLen + 1),
            Subjects = ["a"],
        });

        response.Error.ShouldNotBeNull();
        response.Error!.Description.ShouldBe("invalid stream name");
    }

    [Fact]
    public void Stream_create_rejects_description_over_max_bytes()
    {
        var manager = new StreamManager();
        var response = manager.CreateOrUpdate(new StreamConfig
        {
            Name = "LIMITDESC",
            Subjects = ["a"],
            Description = new string('d', JetStreamApiLimits.JSMaxDescriptionLen + 1),
        });

        response.Error.ShouldNotBeNull();
        response.Error!.Description.ShouldBe("stream description is too long");
    }

    [Fact]
    public void Stream_create_rejects_metadata_over_max_bytes()
    {
        var manager = new StreamManager();
        var response = manager.CreateOrUpdate(new StreamConfig
        {
            Name = "LIMITMETA",
            Subjects = ["a"],
            Metadata = new Dictionary<string, string>
            {
                ["k"] = new string('m', JetStreamApiLimits.JSMaxMetadataLen),
            },
        });

        response.Error.ShouldNotBeNull();
        response.Error!.Description.ShouldBe("stream metadata exceeds maximum size");
    }

    [Fact]
    public void Consumer_create_rejects_durable_name_over_max_length()
    {
        var manager = new ConsumerManager();
        var response = manager.CreateOrUpdate("S", new ConsumerConfig
        {
            DurableName = new string('C', JetStreamApiLimits.JSMaxNameLen + 1),
        });

        response.Error.ShouldNotBeNull();
        response.Error!.Description.ShouldBe("invalid durable name");
    }

    [Fact]
    public void Consumer_create_rejects_metadata_over_max_bytes()
    {
        var manager = new ConsumerManager();
        var response = manager.CreateOrUpdate("S", new ConsumerConfig
        {
            DurableName = "C1",
            Metadata = new Dictionary<string, string>
            {
                ["k"] = new string('m', JetStreamApiLimits.JSMaxMetadataLen),
            },
        });

        response.Error.ShouldNotBeNull();
        response.Error!.Description.ShouldBe("consumer metadata exceeds maximum size");
    }
}
