using System.Text;
using NATS.Server.Internal.Avl;
using NATS.Server.Internal.Gsl;
using NATS.Server.Internal.SubjectTree;
using NATS.Server.Internal.SysMem;
using NATS.Server.Internal.TimeHashWheel;

namespace NATS.Server.Core.Tests.Internal;

public class InternalDsParityBatch2Tests
{
    [Fact]
    public void SubjectTreeHelper_IntersectGSL_matches_interested_subjects_once()
    {
        var tree = new SubjectTree<int>();
        tree.Insert("foo.bar"u8.ToArray(), 1);
        tree.Insert("foo.baz"u8.ToArray(), 2);
        tree.Insert("other.subject"u8.ToArray(), 3);

        var sublist = new GenericSubjectList<int>();
        sublist.Insert("foo.*", 1);
        sublist.Insert("foo.bar", 2); // overlap should not duplicate callback for same subject

        var seen = new HashSet<string>(StringComparer.Ordinal);
        SubjectTreeHelper.IntersectGSL(tree, sublist, (subject, _) =>
        {
            seen.Add(Encoding.UTF8.GetString(subject));
        });

        seen.Count.ShouldBe(2);
        seen.ShouldContain("foo.bar");
        seen.ShouldContain("foo.baz");
    }

    [Fact]
    public void SubjectTree_Dump_outputs_node_and_leaf_structure()
    {
        var tree = new SubjectTree<int>();
        tree.Insert("foo.bar"u8.ToArray(), 1);
        tree.Insert("foo.baz"u8.ToArray(), 2);

        using var sw = new StringWriter();
        tree.Dump(sw);
        var dump = sw.ToString();

        dump.ShouldContain("NODE");
        dump.ShouldContain("LEAF");
        dump.ShouldContain("Prefix:");
    }

    [Fact]
    public void SequenceSet_Encode_supports_destination_buffer_reuse()
    {
        var set = new SequenceSet();
        set.Insert(1);
        set.Insert(65);
        set.Insert(1024);

        var buffer = new byte[set.EncodeLength() + 32];
        var written = set.Encode(buffer);
        written.ShouldBe(set.EncodeLength());

        var (decoded, bytesRead) = SequenceSet.Decode(buffer.AsSpan(0, written));
        bytesRead.ShouldBe(written);
        decoded.Exists(1).ShouldBeTrue();
        decoded.Exists(65).ShouldBeTrue();
        decoded.Exists(1024).ShouldBeTrue();
    }

    [Fact]
    public void HashWheelEntry_struct_exposes_sequence_and_expiration()
    {
        var entry = new HashWheel.HashWheelEntry(42, 99);
        entry.Sequence.ShouldBe((ulong)42);
        entry.Expires.ShouldBe(99);
    }

    [Fact]
    public void SystemMemory_returns_positive_memory_value()
    {
        SystemMemory.Memory().ShouldBeGreaterThan(0);
    }

    [Fact]
    public void SimpleSubjectList_works_with_empty_marker_values()
    {
        var list = new SimpleSubjectList();
        list.Insert("foo.bar", new SimpleSublistValue());
        list.HasInterest("foo.bar").ShouldBeTrue();
    }
}
