using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FluentAssertions;
using Xunit;

namespace MontoyaTech.Rest.Net.Tests
{
    public class RouteMatcherTests
    {
        [Fact]
        public void SyntaxWithPathShouldNotMatchRoot()
        {
            RouteMatcher.Matches("http://localhost/", "/test", out _).Should().BeFalse();
        }

        [Fact]
        public void SyntaxWithRootShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/", "/", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWithRootCatchAllShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/test1/test2", "/**", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxCatchAllEmptyShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/test1", "/test1/**", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWithRootWildcardShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/test1", "/*", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWildCardEmptyShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/test1", "/test1/*", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWithRootWildcardShouldNotMatch()
        {
            RouteMatcher.Matches("http://localhost/test1/test2", "/*", out _).Should().BeFalse();
        }

        [Fact]
        public void SyntaxWithRootNotShouldNotMatch()
        {
            RouteMatcher.Matches("http://localhost/test1", "/!test1", out _).Should().BeFalse();
        }

        [Fact]
        public void SyntaxWithRootNotShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/test2", "/!test1", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWithArgumentShouldNotMatch()
        {
            RouteMatcher.Matches("http://localhost/test1/test2", "/{a}", out _).Should().BeFalse();
        }

        [Fact]
        public void SyntaxWithArgumentShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/test1", "/{a}", out string[] arguments).Should().BeTrue();
            arguments.Length.Should().Be(1);
            arguments[0].Should().Be("test1");
        }

        [Fact]
        public void SyntaxWithArgumentsShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/a/1/2/d", "/a/{b}/{c}/d", out string[] arguments).Should().BeTrue();
            arguments.Length.Should().Be(2);
            arguments[0].Should().Be("1");
            arguments[1].Should().Be("2");
        }

        [Fact]
        public void SyntaxWithArgumentsUrlEncodedShouldDecode()
        {
            RouteMatcher.Matches("http://localhost/a/b%20c", "/a/{name}", out string[] arguments).Should().BeTrue();
            arguments.Length.Should().Be(1);
            arguments[0].Should().Be("b c");
        }

        [Fact]
        public void SyntaxWithWildcardShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/1/2/3", "/1/*/3", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWithWildcardShouldNotMatch()
        {
            RouteMatcher.Matches("http://localhost/1/2/3", "/1/*", out _).Should().BeFalse();
        }

        [Fact]
        public void SyntaxWithCatchallShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/1/2/3", "/1/**", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWithOrShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/a/b", "/a/b|c", out _).Should().BeTrue();
            RouteMatcher.Matches("http://localhost/a/c", "/a/b|c", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWithOrShouldNotMatch()
        {
            RouteMatcher.Matches("http://localhost/a/d", "/a/b|c", out _).Should().BeFalse();
        }

        [Fact]
        public void SyntaxWithNotAndShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/a/d", "/a/!b&!c", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWithNotAndShouldNotMatch()
        {
            RouteMatcher.Matches("http://localhost/a/b", "/a/!b&!c", out _).Should().BeFalse();
        }

        [Fact]
        public void SyntaxWithSegmentShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/a", "/a", out _).Should().BeTrue();
        }

        [Fact]
        public void SyntaxWithMultipleSegmentsShouldMatch()
        {
            RouteMatcher.Matches("http://localhost/a/b/c", "/a/b/c", out _).Should().BeTrue();
        }
    }
}