// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using VerifyCS = MSTest.Analyzers.Test.CSharpCodeFixVerifier<
    MSTest.Analyzers.GlobalTestFixtureShouldBeValidAnalyzer,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;

namespace MSTest.Analyzers.Test;

[TestClass]
public sealed class GlobalTestFixtureShouldBeValidAnalyzerTests
{
    [TestMethod]
    public async Task WhenGlobalTestInitializeIsValid_NoDiagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestInitialize]
                public static void GlobalTestInitialize(TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestCleanupIsValid_NoDiagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestCleanup]
                public static void GlobalTestCleanup(TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestInitializeIsAsyncTask_NoDiagnostic()
    {
        string code = """
            using System.Threading.Tasks;
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestInitialize]
                public static async Task GlobalTestInitialize(TestContext testContext)
                {
                    await Task.Delay(100);
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestCleanupIsAsyncValueTask_NoDiagnostic()
    {
        string code = """
            using System.Threading.Tasks;
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestCleanup]
                public static async ValueTask GlobalTestCleanup(TestContext testContext)
                {
                    await Task.Delay(100);
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestInitializeIsNotStatic_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestInitialize]
                public void [|GlobalTestInitialize|](TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestCleanupIsNotPublic_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestCleanup]
                private static void [|GlobalTestCleanup|](TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestInitializeHasNoParameters_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestInitialize]
                public static void [|GlobalTestInitialize|]()
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestCleanupHasWrongParameterType_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestCleanup]
                public static void [|GlobalTestCleanup|](string param)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestInitializeHasTooManyParameters_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestInitialize]
                public static void [|GlobalTestInitialize|](TestContext testContext, string extraParam)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestCleanupIsGeneric_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestCleanup]
                public static void [|GlobalTestCleanup|]<T>(TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestInitializeIsAsyncVoid_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestInitialize]
                public static async void [|GlobalTestInitialize|](TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestCleanupReturnsInt_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass
            {
                [GlobalTestCleanup]
                public static int [|GlobalTestCleanup|](TestContext testContext)
                {
                    return 0;
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestCleanupInInternalClassWithoutDiscoverInternals_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            internal class MyTestClass
            {
                [GlobalTestCleanup]
                public static void [|GlobalTestCleanup|](TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestInitializeInStaticClass_NoDiagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public static class MyTestClass
            {
                [GlobalTestInitialize]
                public static void GlobalTestInitialize(TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestCleanupInClassWithoutTestClassAttribute_Diagnostic()
    {
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            public class MyTestClass
            {
                [GlobalTestCleanup]
                public static void [|GlobalTestCleanup|](TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestInitializeInGenericClass_Diagnostic()
    {
        // Generic containing type is rejected by `allowGenericType: false` in the analyzer.
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            [TestClass]
            public class MyTestClass<T>
            {
                [GlobalTestInitialize]
                public static void [|GlobalTestInitialize|](TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }

    [TestMethod]
    public async Task WhenGlobalTestCleanupWithDerivedTestClassAttribute_NoDiagnostic()
    {
        // A class marked with a TestClassAttribute-derived attribute satisfies the TestClass check
        // because the guard uses `Inherits(testClassAttributeSymbol)`.
        string code = """
            using Microsoft.VisualStudio.TestTools.UnitTesting;

            public class MyTestClassAttribute : TestClassAttribute
            {
            }

            [MyTestClass]
            public class MyTestClass
            {
                [GlobalTestCleanup]
                public static void GlobalTestCleanup(TestContext testContext)
                {
                }
            }
            """;

        await VerifyCS.VerifyCodeFixAsync(code, code);
    }
}
