using NATS.Server.Subscriptions;

namespace NATS.Server.Core.Tests.Subscriptions;

public class SubjectTransformParityBatch3Tests
{
    [Fact]
    public void ValidateMapping_accepts_supported_templates_and_rejects_invalid_templates()
    {
        SubjectTransform.ValidateMapping("dest.$1").ShouldBeTrue();
        SubjectTransform.ValidateMapping("dest.{{partition(10)}}").ShouldBeTrue();
        SubjectTransform.ValidateMapping("dest.{{random(5)}}").ShouldBeTrue();

        SubjectTransform.ValidateMapping("dest.*").ShouldBeFalse();
        SubjectTransform.ValidateMapping("dest.{{wildcard()}}").ShouldBeFalse();
    }

    [Fact]
    public void NewSubjectTransformStrict_requires_all_source_wildcards_to_be_used()
    {
        SubjectTransform.NewSubjectTransformWithStrict("foo.*.*", "bar.$1", strict: true).ShouldBeNull();
        SubjectTransform.NewSubjectTransformWithStrict("foo.*.*", "bar.$1", strict: false).ShouldNotBeNull();
    }

    [Fact]
    public void NewSubjectTransformStrict_accepts_when_all_source_wildcards_are_used()
    {
        var transform = SubjectTransform.NewSubjectTransformStrict("foo.*.*", "bar.$2.$1");
        transform.ShouldNotBeNull();
        transform.Apply("foo.A.B").ShouldBe("bar.B.A");
    }

    [Fact]
    public void Random_transform_function_returns_bucket_in_range()
    {
        var transform = SubjectTransform.Create("*", "rand.{{random(3)}}");
        transform.ShouldNotBeNull();

        for (var i = 0; i < 20; i++)
        {
            var output = transform.Apply("foo");
            output.ShouldNotBeNull();
            var parts = output!.Split('.');
            parts.Length.ShouldBe(2);
            int.TryParse(parts[1], out var bucket).ShouldBeTrue();
            bucket.ShouldBeGreaterThanOrEqualTo(0);
            bucket.ShouldBeLessThan(3);
        }
    }

    [Fact]
    public void TransformTokenize_and_transformUntokenize_round_trip_wildcards()
    {
        var tokenized = SubjectTransform.TransformTokenize("foo.*.*");
        tokenized.ShouldBe("foo.$1.$2");

        var untokenized = SubjectTransform.TransformUntokenize(tokenized);
        untokenized.ShouldBe("foo.*.*");
    }

    [Fact]
    public void Reverse_produces_inverse_transform_for_reordered_wildcards()
    {
        var forward = SubjectTransform.Create("foo.*.*", "bar.$2.$1");
        forward.ShouldNotBeNull();

        var reverse = forward.Reverse();
        reverse.ShouldNotBeNull();

        var mapped = forward.Apply("foo.A.B");
        mapped.ShouldBe("bar.B.A");
        reverse.Apply(mapped!).ShouldBe("foo.A.B");
    }

    [Fact]
    public void TransformSubject_applies_transform_without_source_match_guard()
    {
        var transform = SubjectTransform.Create("foo.*", "bar.$1");
        transform.ShouldNotBeNull();

        transform.TransformSubject("baz.qux").ShouldBe("bar.qux");
    }
}
