using System.Reflection;
using NATS.Server.Subscriptions;

namespace NATS.Server.Core.Tests;

public class SubListAllocationGuardTests
{
    [Fact]
    public void Remote_subscription_dictionary_uses_dedicated_routed_sub_key_type()
    {
        var field = typeof(SubList).GetField("_remoteSubs", BindingFlags.Instance | BindingFlags.NonPublic);

        field.ShouldNotBeNull();
        field.FieldType.IsGenericType.ShouldBeTrue();
        field.FieldType.GetGenericArguments()[0].Name.ShouldBe("RoutedSubKey");
    }

    [Fact]
    public void Has_remote_interest_supports_exact_and_wildcard_subjects_per_account()
    {
        using var sl = new SubList();
        sl.ApplyRemoteSub(new RemoteSubscription("orders.created", null, "r1", "A"));
        sl.ApplyRemoteSub(new RemoteSubscription("orders.*", null, "r2", "A"));
        sl.ApplyRemoteSub(new RemoteSubscription("payments.*", null, "r3", "B"));

        sl.HasRemoteInterest("A", "orders.created").ShouldBeTrue();
        sl.HasRemoteInterest("A", "orders.updated").ShouldBeTrue();
        sl.HasRemoteInterest("A", "payments.created").ShouldBeFalse();
        sl.HasRemoteInterest("B", "payments.posted").ShouldBeTrue();
        sl.HasRemoteInterest("B", "orders.created").ShouldBeFalse();
    }

    [Fact]
    public void Match_remote_reflects_queue_weight_updates_for_existing_remote_queue_sub()
    {
        using var sl = new SubList();
        var sub = new RemoteSubscription("orders.*", "workers", "r1", "A", QueueWeight: 1);
        sl.ApplyRemoteSub(sub);

        sl.MatchRemote("A", "orders.created").Count.ShouldBe(1);

        sl.UpdateRemoteQSub(sub with { QueueWeight = 4 });

        var matches = sl.MatchRemote("A", "orders.created");
        matches.Count.ShouldBe(4);
        matches.ShouldAllBe(match => match.Queue == "workers");
    }

    [Fact]
    public void Match_merges_queue_groups_from_multiple_matching_nodes_by_queue_name()
    {
        using var sl = new SubList();
        sl.Insert(new Subscription { Subject = "orders.created", Queue = "workers", Sid = "1" });
        sl.Insert(new Subscription { Subject = "orders.*", Queue = "workers", Sid = "2" });
        sl.Insert(new Subscription { Subject = "orders.>", Queue = "audit", Sid = "3" });

        var result = sl.Match("orders.created");

        result.PlainSubs.ShouldBeEmpty();
        result.QueueSubs.Length.ShouldBe(2);
        result.QueueSubs.Single(group => group[0].Queue == "workers").Length.ShouldBe(2);
        result.QueueSubs.Single(group => group[0].Queue == "audit").Length.ShouldBe(1);
    }
}
