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

#nullable disable

using System;
using Xunit;

namespace Microsoft.AspNetCore.Razor.Language.Legacy;

public class HtmlBlockTest() : ParserTestBase(layer: TestProject.Layer.Compiler, validateSpanEditHandlers: true, useLegacyTokenizer: true)
{
    [Fact]
    public void HandlesUnbalancedTripleDashHTMLComments()
    {
        ParseDocumentTest(
@"@{
    <!-- Hello, I'm a comment that shouldn't break razor --->
}");
    }

    [Fact]
    public void HandlesOpenAngleAtEof()
    {
        ParseDocumentTest("""
            @{
            <
            """);
    }

    [Fact]
    public void HandlesOpenAngleWithProperTagFollowingIt()
    {
        ParseDocumentTest("""
            @{
            <
            </html>
            """);
    }

    [Fact]
    public void TagWithoutCloseAngleDoesNotTerminateBlock()
    {
        ParseDocumentTest("""
            @{<                      
               
            """);
    }

    [Fact]
    public void AllowsStartAndEndTagsToDifferInCase()
    {
        ParseDocumentTest("@{<li><p>Foo</P></lI>}");
    }

    [Fact]
    public void ReadsToEndOfLineIfFirstCharacterAfterTransitionIsColon()
    {
        ParseDocumentTest("""
            @{@:<li>Foo Bar Baz
            bork}
            """);
    }

    [Fact]
    public void StopsParsingSingleLineBlockAtEOFIfNoEOLReached()
    {
        ParseDocumentTest("@{@:foo bar");
    }

    [Fact]
    public void StopsAtMatchingCloseTagToStartTag()
    {
        ParseDocumentTest("@{<a><b></b></a><c></c>}");
    }

    [Fact]
    public void ParsesUntilMatchingEndTagIfFirstNonWhitespaceCharacterIsStartTag()
    {
        ParseDocumentTest("@{<baz><boz><biz></biz></boz></baz>}");
    }

    [Fact]
    public void AllowsUnclosedTagsAsLongAsItCanRecoverToAnExpectedEndTag()
    {
        ParseDocumentTest("@{<foo><bar><baz></foo>}");
    }

    [Fact]
    public void WithSelfClosingTagJustEmitsTag()
    {
        ParseDocumentTest("@{<foo />}");
    }

    [Fact]
    public void CanHandleSelfClosingTagsWithinBlock()
    {
        ParseDocumentTest("@{<foo><bar /></foo>}");
    }

    [Fact]
    public void SupportsTagsWithAttributes()
    {
        ParseDocumentTest("@{<foo bar=\"baz\"><biz><boz zoop=zork/></biz></foo>}");
    }

    [Fact]
    public void AllowsCloseAngleBracketInAttributeValueIfDoubleQuoted()
    {
        ParseDocumentTest("@{<foo><bar baz=\">\" /></foo>}");
    }

    [Fact]
    public void AllowsCloseAngleBracketInAttributeValueIfSingleQuoted()
    {
        ParseDocumentTest("@{<foo><bar baz=\'>\' /></foo>}");
    }

    [Fact]
    public void AllowsSlashInAttributeValueIfDoubleQuoted()
    {
        ParseDocumentTest("@{<foo><bar baz=\"/\"></bar></foo>}");
    }

    [Fact]
    public void AllowsSlashInAttributeValueIfSingleQuoted()
    {
        ParseDocumentTest("@{<foo><bar baz=\'/\'></bar></foo>}");
    }

    [Fact]
    public void TerminatesAtEOF()
    {
        ParseDocumentTest("@{<foo>");
    }

    [Fact]
    public void SupportsCommentAsBlock()
    {
        ParseDocumentTest("@{<!-- foo -->}");
    }

    [Fact]
    public void SupportsCommentWithExtraDashAsBlock()
    {
        ParseDocumentTest("@{<!-- foo --->}");
    }

    [Fact]
    public void SupportsCommentWithinBlock()
    {
        ParseDocumentTest("@{<foo>bar<!-- zoop -->baz</foo>}");
    }

    [Fact]
    public void HtmlCommentSupportsMultipleDashes()
    {
        ParseDocumentTest(
@"<div><!--- Hello World ---></div>
<div><!---- Hello World ----></div>
<div><!----- Hello World -----></div>
<div><!----- Hello < --- > World </div> -----></div>
");
    }

    [Fact]
    public void ProperlyBalancesCommentStartAndEndTags()
    {
        ParseDocumentTest("@{<!--<foo></bar>-->}");
    }

    [Fact]
    public void TerminatesAtEOFWhenParsingComment()
    {
        ParseDocumentTest("@{<!--<foo>");
    }

    [Fact]
    public void OnlyTerminatesCommentOnFullEndSequence()
    {
        ParseDocumentTest("@{<!--<foo>--</bar>-->}");
    }

    [Fact]
    public void TerminatesCommentAtFirstOccurrenceOfEndSequence()
    {
        ParseDocumentTest("@{<foo><!--<foo></bar-->--></foo>}");
    }

    [Fact]
    public void TreatsMalformedTagsAsContent()
    {
        ParseDocumentTest("@{<foo></!-- bar --></foo>}");
    }


    [Fact]
    public void ParsesSGMLDeclarationAsEmptyTag()
    {
        ParseDocumentTest("@{<foo><!DOCTYPE foo bar baz></foo>}");
    }

    [Fact]
    public void TerminatesSGMLDeclarationAtFirstCloseAngle()
    {
        ParseDocumentTest("@{<foo><!DOCTYPE foo bar> baz></foo>}");
    }

    [Fact]
    public void ParsesXMLProcessingInstructionAsEmptyTag()
    {
        ParseDocumentTest("@{<foo><?xml foo bar baz?></foo>}");
    }

    [Fact]
    public void TerminatesXMLProcessingInstructionAtQuestionMarkCloseAnglePair()
    {
        ParseDocumentTest("@{<foo><?xml foo bar baz?> baz</foo>}");
    }

    [Fact]
    public void DoesNotTerminateXMLProcInstrAtCloseAngleUnlessPreceededByQuestionMark()
    {
        // ParseBlockDoesNotTerminateXMLProcessingInstructionAtCloseAngleUnlessPreceededByQuestionMark
        ParseDocumentTest("@{<foo><?xml foo bar> baz?></foo>}");
    }

    [Fact]
    public void SupportsScriptTagsWithLessThanSignsInThem()
    {
        ParseDocumentTest(@"@{<script>if(foo<bar) { alert(""baz"");)</script>}");
    }

    [Fact]
    public void SupportsScriptTagsWithSpacedLessThanSignsInThem()
    {
        ParseDocumentTest(@"@{<script>if(foo < bar) { alert(""baz"");)</script>}");
    }

    [Fact]
    public void AcceptsEmptyTextTag()
    {
        ParseDocumentTest("@{<text/>}");
    }

    [Fact]
    public void AcceptsTextTagAsOuterTagButDoesNotRender()
    {
        ParseDocumentTest("@{<text>Foo Bar <foo> Baz</text> zoop}");
    }

    [Fact]
    public void RendersLiteralTextTagIfDoubled()
    {
        ParseDocumentTest("@{<text><text>Foo Bar <foo> Baz</text></text> zoop}");
    }

    [Fact]
    public void DoesNotConsiderPsuedoTagWithinMarkupBlock()
    {
        ParseDocumentTest("@{<foo><text><bar></bar></foo>}");
    }

    [Fact]
    public void StopsParsingMidEmptyTagIfEOFReached()
    {
        ParseDocumentTest("@{<br/}");
    }

    [Fact]
    public void CorrectlyHandlesSingleLineOfMarkupWithEmbeddedStatement()
    {
        ParseDocumentTest("@{<div>Foo @if(true) {} Bar</div>}");
    }

    [Fact]
    public void IgnoresTagsInContentsOfScriptTag()
    {
        ParseDocumentTest(@"@{<script>foo<bar baz='@boz'></script>}");
    }

    [Fact]
    public void HandlesForwardSlashInAttributeContent()
    {
        ParseDocumentTest(@"@{<p / class=foo />}");
    }
}
