// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ChangeSignature
{
    public partial class ChangeSignatureTests : AbstractChangeSignatureTests
    {
        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        public async Task ChangeSignature_Formatting_KeepCountsPerLine()
        {
            var markup = @"
class C
{
    void $$Method(int a, int b, int c,
        int d, int e,
        int f)
    {
        Method(1,
            2, 3,
            4, 5, 6);
    }
}";
            var updatedSignature = new[] { 5, 4, 3, 2, 1, 0 };
            var expectedUpdatedCode = @"
class C
{
    void Method(int f, int e, int d,
        int c, int b,
        int a)
    {
        Method(6,
            5, 4,
            3, 2, 1);
    }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")]
        public async Task ChangeSignature_Formatting_KeepTrivia()
        {
            var markup = @"
class C
{
    void $$Method(
        int a, int b, int c,
        int d, int e,
        int f)
    {
        Method(
            1, 2, 3,
            4, 5, 6);
    }
}";
            var updatedSignature = new[] { 1, 2, 3, 4, 5 };
            var expectedUpdatedCode = @"
class C
{
    void Method(
        int b, int c, int d,
        int e, int f)
    {
        Method(
            2, 3, 4,
            5, 6);
    }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")]
        public async Task ChangeSignature_Formatting_KeepTrivia_WithArgumentNames()
        {
            var markup = @"
class C
{
    void $$Method(
        int a, int b, int c,
        int d, int e,
        int f)
    {
        Method(
            a: 1, b: 2, c: 3,
            d: 4, e: 5, f: 6);
    }
}";
            var updatedSignature = new[] { 1, 2, 3, 4, 5 };
            var expectedUpdatedCode = @"
class C
{
    void Method(
        int b, int c, int d,
        int e, int f)
    {
        Method(
            b: 2, c: 3, d: 4,
            e: 5, f: 6);
    }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        public async Task ChangeSignature_Formatting_Method()
        {
            var markup = @"
class C
{
    void $$Method(int a, 
        int b)
    {
        Method(1,
            2);
    }
}";
            var updatedSignature = new[] { 1, 0 };
            var expectedUpdatedCode = @"
class C
{
    void Method(int b,
        int a)
    {
        Method(2,
            1);
    }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        public async Task ChangeSignature_Formatting_Constructor()
        {
            var markup = @"
class SomeClass
{
    $$SomeClass(int a,
        int b)
    {
        new SomeClass(1,
            2);
    }
}";
            var updatedSignature = new[] { 1, 0 };
            var expectedUpdatedCode = @"
class SomeClass
{
    SomeClass(int b,
        int a)
    {
        new SomeClass(2,
            1);
    }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        public async Task ChangeSignature_Formatting_Indexer()
        {
            var markup = @"
class SomeClass
{
    public int $$this[int a,
        int b]
    {
        get
        {
            return new SomeClass()[1,
                2];
        }
    }
}";
            var updatedSignature = new[] { 1, 0 };
            var expectedUpdatedCode = @"
class SomeClass
{
    public int this[int b,
        int a]
    {
        get
        {
            return new SomeClass()[2,
                1];
        }
    }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        public async Task ChangeSignature_Formatting_Delegate()
        {
            var markup = @"
class SomeClass
{
    delegate void $$MyDelegate(int a,
        int b);

    void M(int a,
        int b)
    {
        var myDel = new MyDelegate(M);
        myDel(1,
            2);
    }
}";
            var updatedSignature = new[] { 1, 0 };
            var expectedUpdatedCode = @"
class SomeClass
{
    delegate void MyDelegate(int b,
        int a);

    void M(int b,
        int a)
    {
        var myDel = new MyDelegate(M);
        myDel(2,
            1);
    }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        public async Task ChangeSignature_Formatting_AnonymousMethod()
        {
            var markup = @"
class SomeClass
{
    delegate void $$MyDelegate(int a,
        int b);

    void M()
    {
        MyDelegate myDel = delegate (int x,
            int y)
        {
            // Nothing
        };
    }
}";
            var updatedSignature = new[] { 1, 0 };
            var expectedUpdatedCode = @"
class SomeClass
{
    delegate void MyDelegate(int b,
        int a);

    void M()
    {
        MyDelegate myDel = delegate (int y,
            int x)
        {
            // Nothing
        };
    }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        public async Task ChangeSignature_Formatting_ConstructorInitializers()
        {
            var markup = @"
class B
{
    public $$B(int x, int y) { }
    public B() : this(1,
        2)
    { }
}

class D : B
{
    public D() : base(1,
        2)
    { }
}";
            var updatedSignature = new[] { 1, 0 };
            var expectedUpdatedCode = @"
class B
{
    public B(int y, int x) { }
    public B() : this(2,
        1)
    { }
}

class D : B
{
    public D() : base(2,
        1)
    { }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        public async Task ChangeSignature_Formatting_Attribute()
        {
            var markup = @"
[Custom(1,
    2)]
class CustomAttribute : System.Attribute
{
    public $$CustomAttribute(int x, int y) { }
}";
            var updatedSignature = new[] { 1, 0 };
            var expectedUpdatedCode = @"
[Custom(2,
    1)]
class CustomAttribute : System.Attribute
{
    public CustomAttribute(int y, int x) { }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")]
        public async Task ChangeSignature_Formatting_Attribute_KeepTrivia()
        {
            var markup = @"
[Custom(
    1, 2)]
class CustomAttribute : System.Attribute
{
    public $$CustomAttribute(int x, int y) { }
}";
            var updatedSignature = new[] { 1 };
            var expectedUpdatedCode = @"
[Custom(
    2)]
class CustomAttribute : System.Attribute
{
    public CustomAttribute(int y) { }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")]
        public async Task ChangeSignature_Formatting_Attribute_KeepTrivia_RemovingSecond()
        {
            var markup = @"
[Custom(
    1, 2)]
class CustomAttribute : System.Attribute
{
    public $$CustomAttribute(int x, int y) { }
}";
            var updatedSignature = new[] { 0 };
            var expectedUpdatedCode = @"
[Custom(
    1)]
class CustomAttribute : System.Attribute
{
    public CustomAttribute(int x) { }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")]
        public async Task ChangeSignature_Formatting_Attribute_KeepTrivia_RemovingBoth()
        {
            var markup = @"
[Custom(
    1, 2)]
class CustomAttribute : System.Attribute
{
    public $$CustomAttribute(int x, int y) { }
}";
            var updatedSignature = new int[] { };
            var expectedUpdatedCode = @"
[Custom(
)]
class CustomAttribute : System.Attribute
{
    public CustomAttribute() { }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        [WorkItem(28156, "https://github.com/dotnet/roslyn/issues/28156")]
        public async Task ChangeSignature_Formatting_Attribute_KeepTrivia_RemovingBeforeNewlineComma()
        {
            var markup = @"
[Custom(1
    , 2, 3)]
class CustomAttribute : System.Attribute
{
    public $$CustomAttribute(int x, int y, int z) { }
}";
            var updatedSignature = new[] { 1, 2 };
            var expectedUpdatedCode = @"
[Custom(2, 3)]
class CustomAttribute : System.Attribute
{
    public CustomAttribute(int y, int z) { }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }

        [WorkItem(946220, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/946220")]
        [Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
        public async Task ChangeSignature_Formatting_LambdaAsArgument()
        {
            var markup = @"class C
{
    void M(System.Action<int, int> f, int z$$)
    {
        M((x, y) => System.Console.WriteLine(x + y), 5);
    }
}";
            var updatedSignature = new[] { 0 };
            var expectedUpdatedCode = @"class C
{
    void M(System.Action<int, int> f)
    {
        M((x, y) => System.Console.WriteLine(x + y));
    }
}";
            await TestChangeSignatureViaCommandAsync(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: expectedUpdatedCode);
        }
    }
}
