// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.Rewrite.ApacheModRewrite;
using Microsoft.AspNetCore.Rewrite.PatternSegments;

namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite;

public class TestStringParserTests
{
    [Fact]
    public void ConditionParser_SingleServerVariable()
    {
        var serverVar = "%{HTTPS}";

        var result = TestStringParser.Parse(serverVar);

        var list = new List<PatternSegment>();
        list.Add(new IsHttpsModSegment());
        var expected = new Pattern(list);
        AssertPatternsEqual(expected, result);
    }

    [Fact]
    public void ConditionParser_MultipleServerVariables()
    {
        var serverVar = "%{HTTPS}%{REQUEST_URI}";
        var result = TestStringParser.Parse(serverVar);

        var list = new List<PatternSegment>();
        list.Add(new IsHttpsModSegment());
        list.Add(new UrlSegment());
        var expected = new Pattern(list);
        AssertPatternsEqual(expected, result);
    }

    [Fact]
    public void ConditionParser_ParseLiteral()
    {
        var serverVar = "Hello!";
        var result = TestStringParser.Parse(serverVar);

        var list = new List<PatternSegment>();
        list.Add(new LiteralSegment(serverVar));
        var expected = new Pattern(list);
        AssertPatternsEqual(expected, result);
    }

    [Fact]
    public void ConditionParser_ParseConditionParameters()
    {
        var serverVar = "%1";
        var result = TestStringParser.Parse(serverVar);

        var list = new List<PatternSegment>();
        list.Add(new ConditionMatchSegment(1));
        var expected = new Pattern(list);
        AssertPatternsEqual(expected, result);
    }

    [Fact]
    public void ConditionParser_ParseMultipleConditionParameters()
    {
        var serverVar = "%1%2";
        var result = TestStringParser.Parse(serverVar);

        var list = new List<PatternSegment>();
        list.Add(new ConditionMatchSegment(1));
        list.Add(new ConditionMatchSegment(2));
        var expected = new Pattern(list);
        AssertPatternsEqual(expected, result);
    }

    [Fact]
    public void ConditionParser_ParseRuleVariable()
    {
        var serverVar = "$1";
        var result = TestStringParser.Parse(serverVar);

        var list = new List<PatternSegment>();
        list.Add(new RuleMatchSegment(1));
        var expected = new Pattern(list);
        AssertPatternsEqual(expected, result);
    }
    [Fact]
    public void ConditionParser_ParseMultipleRuleVariables()
    {
        var serverVar = "$1$2";
        var result = TestStringParser.Parse(serverVar);

        var list = new List<PatternSegment>();
        list.Add(new RuleMatchSegment(1));
        list.Add(new RuleMatchSegment(2));
        var expected = new Pattern(list);
        AssertPatternsEqual(expected, result);
    }

    [Fact]
    public void ConditionParser_ParserComplexRequest()
    {
        var serverVar = "%{HTTPS}/$1";
        var result = TestStringParser.Parse(serverVar);

        var list = new List<PatternSegment>();
        list.Add(new IsHttpsModSegment());
        list.Add(new LiteralSegment("/"));
        list.Add(new RuleMatchSegment(1));
        var expected = new Pattern(list);
        AssertPatternsEqual(expected, result);
    }

    [Theory]
    [InlineData(@"%}", "Cannot parse '%}' to integer at string index: '1'")] // no } at end
    [InlineData(@"%{", "Missing close brace for parameter at string index: '2'")] // no closing }
    [InlineData(@"%a", "Cannot parse '%a' to integer at string index: '1'")] // invalid character after %
    [InlineData(@"$a", "Cannot parse '$a' to integer at string index: '1'")] // invalid character after $
    [InlineData(@"%{asdf", "Missing close brace for parameter at string index: '6'")] // no closing } with characters
    public void ConditionParser_InvalidInput(string testString, string expected)
    {
        var ex = Assert.Throws<FormatException>(() => TestStringParser.Parse(testString));
        Assert.Equal(expected, ex.Message);
    }

    private static void AssertPatternsEqual(Pattern p1, Pattern p2)
    {
        Assert.Equal(p1.PatternSegments.Count, p2.PatternSegments.Count);

        for (int i = 0; i < p1.PatternSegments.Count; i++)
        {
            var s1 = p1.PatternSegments[i];
            var s2 = p2.PatternSegments[i];

            Assert.Equal(s1.GetType(), s2.GetType());
        }
    }
}
