﻿// 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.

using System;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Completion.CompletionProviders.Snippets;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets
{
    [Trait(Traits.Feature, Traits.Features.Completion)]
    public class CSharpConsoleSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests
    {
        protected override string ItemToCommit => "cw";

        [WpfFact]
        public async Task InsertConsoleSnippetInMethodTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method()
    {
        Wr$$
    }
}";

            var expectedCodeAfterCommit =
@"using System;

class Program
{
    public void Method()
    {
        Console.WriteLine($$);
    }
}";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }

        [WpfFact]
        public async Task InsertAsyncConsoleSnippetTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public async Task MethodAsync()
    {
        Wr$$
    }
}";

            var expectedCodeAfterCommit =
@"using System;

class Program
{
    public async Task MethodAsync()
    {
        await Console.Out.WriteLineAsync($$);
    }
}";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }

        [WpfFact]
        public async Task InsertConsoleSnippetGlobalTest()
        {
            var markupBeforeCommit =
@"$$
class Program
{
    public async Task MethodAsync()
    {
    }
}";

            var expectedCodeAfterCommit =
@"using System;

Console.WriteLine($$);
class Program
{
    public async Task MethodAsync()
    {
    }
}";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }

        [WpfFact]
        public async Task NoConsoleSnippetInBlockNamespaceTest()
        {
            var markupBeforeCommit =
@"
namespace Namespace
{
    $$
    class Program
    {
        public async Task MethodAsync()
        {
        }
    }
}";
            await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
        }

        [WpfFact]
        public async Task NoConsoleSnippetInFileScopedNamespaceTest()
        {
            var markupBeforeCommit =
@"
namespace Namespace;
$$
class Program
{
    public async Task MethodAsync()
    {
    }
}
";
            await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
        }

        [WpfFact]
        public async Task InsertConsoleSnippetInConstructorTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public Program()
    {
        var x = 5;
        $$
    }
}";

            var expectedCodeAfterCommit =
@"using System;

class Program
{
    public Program()
    {
        var x = 5;
        Console.WriteLine($$);
    }
}";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }

        [WpfFact]
        public async Task InsertConsoleSnippetInLocalFunctionTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method()
    {
        var x = 5;
        void LocalMethod()
        {
            $$
        }
    }
}";

            var expectedCodeAfterCommit =
@"using System;

class Program
{
    public void Method()
    {
        var x = 5;
        void LocalMethod()
        {
            Console.WriteLine($$);
        }
    }
}";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }

        [WpfFact]
        public async Task InsertConsoleSnippetInAnonymousFunctionTest()
        {
            var markupBeforeCommit =
@"public delegate void Print(int value);

static void Main(string[] args)
{
    Print print = delegate(int val) {
        $$
    };

}";

            var expectedCodeAfterCommit =
@"using System;

public delegate void Print(int value);

static void Main(string[] args)
{
    Print print = delegate(int val) {
        Console.WriteLine($$);
    };

}";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }

        [WpfFact]
        public async Task InsertConsoleSnippetInParenthesizedLambdaExpressionTest()
        {
            var markupBeforeCommit =
@"
Func<int, int, bool> testForEquality = (x, y) =>
{
    $$
    return x == y;
};";

            var expectedCodeAfterCommit =
@"
using System;

Func<int, int, bool> testForEquality = (x, y) =>
{
    Console.WriteLine($$);
    return x == y;
};";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }

        [WpfFact]
        public async Task NoConsoleSnippetInSwitchExpression()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method()
    {
       var operation = 2;  
  
        var result = operation switch  
        {
            $$
            1 => ""Case 1"",  
            2 => ""Case 2"",  
            3 => ""Case 3"",  
            4 => ""Case 4"",  
        };
    }
}";
            await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
        }

        [WpfFact]
        public async Task NoConsoleSnippetInSingleLambdaExpression()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method()
    {
       Func<int, int> f = x => $$;
    }
}";
            await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
        }

        [WpfFact]
        public async Task NoConsoleSnippetInStringTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method()
    {
        var str = ""$$"";
    }
}";

            await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
        }

        [WpfFact]
        public async Task NoConsoleSnippetInObjectInitializerTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method()
    {
        var str = new Test($$);
    }
}

class Test
{
    private string val;

    public Test(string val)
    {
        this.val = val;
    }
}";

            await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
        }

        [WpfFact]
        public async Task NoConsoleSnippetInParameterListTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method(int x, $$)
    {
    }
}";

            await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
        }

        [WpfFact]
        public async Task NoConsoleSnippetInRecordDeclarationTest()
        {
            var markupBeforeCommit =
@"public record Person
{
    $$
    public string FirstName { get; init; } = default!;
    public string LastName { get; init; } = default!;
};";

            await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
        }

        [WpfFact]
        public async Task NoConsoleSnippetInVariableDeclarationTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method()
    {
        var x = $$
    }
}";

            await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
        }

        [WpfFact]
        public async Task InsertConsoleSnippetWithInvocationBeforeAndAfterCursorTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method()
    {
        Wr$$Blah
    }
}";

            var expectedCodeAfterCommit =
@"using System;

class Program
{
    public void Method()
    {
        Console.WriteLine($$);
    }
}";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }

        [WpfFact]
        public async Task InsertConsoleSnippetWithInvocationUnderscoreBeforeAndAfterCursorTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public void Method()
    {
        _Wr$$Blah_
    }
}";

            var expectedCodeAfterCommit =
@"using System;

class Program
{
    public void Method()
    {
        Console.WriteLine($$);
    }
}";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }

        /// <summary>
        /// We want to fix this case and insert the fully qualified namespace
        /// in a future fix.
        /// </summary>
        [WpfFact]
        public async Task InsertConsoleSnippetWithPropertyNamedConsoleTest()
        {
            var markupBeforeCommit =
@"class Program
{
    public int Console { get; set; }

    public void Method()
    {
        $$
    }
}";

            var expectedCodeAfterCommit =
@"using System;

class Program
{
    public int Console { get; set; }

    public void Method()
    {
        Console.WriteLine($$);
    }
}";
            await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
        }
    }
}
