// 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.Runtime.Serialization;

namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api;

[DataContract]
internal sealed class UnitTestingSearchQuery
{
    /// <summary>
    /// Fully qualified metadata name for the type being searched for, or the containing type of the method being
    /// searched for (if <see cref="MethodName"/> is provided).  Should follow .Net metadata naming, e.g. <c>`</c>
    /// for arity and <c>+</c> for nested types.
    /// </summary>
    [DataMember(Order = 0)]
    public readonly string FullyQualifiedTypeName;

    /// <summary>
    /// Optional name of method within <see cref="FullyQualifiedTypeName"/> being searched for.  Should not include arity.
    /// </summary>
    [DataMember(Order = 1)]
    public readonly string? MethodName;

    /// <summary>
    /// Arity of the method being searched for.  Only valid if <see cref="MethodName"/> is non-null.
    /// </summary>
    [DataMember(Order = 2)]
    public readonly int MethodArity;

    /// <summary>
    /// Parameter count of the method being searched for.  Only valid if <see cref="MethodName"/> is non-null.
    /// </summary>
    [DataMember(Order = 3)]
    public readonly int MethodParameterCount;

    /// <summary>
    /// Whether or not this is a strict search or not.  Strict searches require matching arity and parameter counts,
    /// while non-strict searches do not.  Non-strict searches are useful in cases where the initial searching data
    /// may not be produced in a well formed fashion (for example, some legacy test providers that do not follow:
    /// https://github.com/microsoft/vstest-docs/blob/main/RFCs/0017-Managed-TestCase-Properties.md).
    /// </summary>
    [DataMember(Order = 4)]
    public readonly bool Strict;

    public static UnitTestingSearchQuery ForType(string fullyQualifiedTypeName, bool strict = true)
        => new(fullyQualifiedTypeName, methodName: null, methodArity: 0, methodParameterCount: 0, strict);

    public static UnitTestingSearchQuery ForMethod(string fullyQualifiedTypeName, string methodName, int methodArity, int methodParameterCount, bool strict = true)
        => new(fullyQualifiedTypeName, methodName, methodArity, methodParameterCount, strict);

    private UnitTestingSearchQuery(string fullyQualifiedTypeName, string? methodName, int methodArity, int methodParameterCount, bool strict)
    {
        FullyQualifiedTypeName = fullyQualifiedTypeName;
        MethodName = methodName;
        MethodArity = methodArity;
        MethodParameterCount = methodParameterCount;
        Strict = strict;
    }
}
