// 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.Linq;
using Microsoft.CodeAnalysis;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests;

public class ComponentDeclarationRazorIntegrationTest : RazorIntegrationTestBase
{
    public ComponentDeclarationRazorIntegrationTest()
    {
        AdditionalSyntaxTrees.Add(Parse(AdditionalCode));
    }

    internal override RazorFileKind? FileKind => RazorFileKind.Component;

    internal override bool DeclarationOnly => true;

    [Fact]
    public void DeclarationConfiguration_IncludesFunctions()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@functions {
    public string Value { get; set; }
}");

        // Assert
        var property = component.GetMembers("Value").Single();
        AssertEx.Equal("public System.String Test.TestComponent.Value { get; set; }", property.ToTestDisplayString());
    }

    [Fact]
    public void DeclarationConfiguration_IncludesInject()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@inject string Value
");

        // Assert
        var property = component.GetMembers("Value").Single();
        AssertEx.Equal("private System.String Test.TestComponent.Value { get; set; }", property.ToTestDisplayString());
    }

    [Fact]
    public void DeclarationConfiguration_IncludesUsings()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@using System.Text
@inject StringBuilder Value
");

        // Assert
        var property = component.GetMembers("Value").Single();
        AssertEx.Equal("private System.Text.StringBuilder Test.TestComponent.Value { get; set; }", property.ToTestDisplayString());
    }

    [Fact]
    public void DeclarationConfiguration_IncludesInherits()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@inherits TestNamespace.BaseClass
");

        // Assert
        AssertEx.Equal("Test.TestComponent", component.ToTestDisplayString());
        AssertEx.Equal("TestNamespace.BaseClass", component.BaseType.ToTestDisplayString());
    }

    [Fact]
    public void DeclarationConfiguration_IncludesImplements()
    {
        // Arrange & Act
        var component = CompileToComponent(@"
@implements TestNamespace.IDoCoolThings
");

        // Assert
        AssertEx.Equal("Test.TestComponent", component.ToTestDisplayString());
        AssertEx.Equal("TestNamespace.IDoCoolThings", component.Interfaces.Single().ToTestDisplayString());
    }

    [Fact, WorkItem("https://github.com/dotnet/blazor/issues/453")]
    public void DeclarationConfiguration_FunctionsBlockHasLineMappings_MappingsApplyToError()
    {
        // Arrange & Act 1
        var generated = CompileToCSharp(@"
@functions {
    public StringBuilder Builder { get; set; }
}
");

        // Assert 1
        AssertSourceEquals(@"
// <auto-generated/>
#pragma warning disable 1591
#pragma warning disable 0414
#pragma warning disable 0649
#pragma warning disable 0169

namespace Test
{
    #line default
    using global::System;
    using global::System.Collections.Generic;
    using global::System.Linq;
    using global::System.Threading.Tasks;
    using global::Microsoft.AspNetCore.Components;
    #line default
    #line hidden
    #nullable restore
    public partial class TestComponent : global::Microsoft.AspNetCore.Components.ComponentBase
    #nullable disable
    {
        #pragma warning disable 1998
        protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
        {
        }
        #pragma warning restore 1998
#nullable restore
#line (1,13)-(3,1) ""x:\dir\subdir\Test\TestComponent.cshtml""

    public StringBuilder Builder { get; set; }

#line default
#line hidden
#nullable disable

    }
}
#pragma warning restore 1591
", generated);

        // Act 2
        CompileToAssembly(generated,
            // /dir/subdir/Test/TestComponent.cshtml(2,12): error CS0246: The type or namespace name 'StringBuilder' could not be found (are you missing a using directive or an assembly reference?)
            //     public StringBuilder Builder { get; set; }
            Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "StringBuilder").WithArguments("StringBuilder").WithLocation(2, 12));
    }

    private const string AdditionalCode =
    """
    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.Rendering;
    using System.Threading.Tasks;

    namespace TestNamespace;

    public class BaseClass : IComponent
    {
        public void Attach(RenderHandle renderHandle)
        {
        }

        protected virtual void BuildRenderTree(RenderTreeBuilder builder)
        {
        }

        public Task SetParametersAsync(ParameterView parameters)
        {
            throw new System.NotImplementedException();
        }
    }

    public interface IDoCoolThings
    {
    }
    """;
}
