// 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.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.Shell.Interop;

namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser;

internal abstract partial class AbstractObjectBrowserLibraryManager
{
    private static string GetSearchText(VSOBSEARCHCRITERIA2[] pobSrch)
    {
        if (pobSrch.Length == 0 ||
            pobSrch[0].szName == null)
        {
            return null;
        }

        var searchText = pobSrch[0].szName;

        var openParenIndex = searchText.IndexOf('(');
        if (openParenIndex != -1)
        {
            searchText = searchText[openParenIndex..];
        }

        return searchText;
    }

    public async Task<IVsSimpleObjectList2> GetSearchListAsync(
        ObjectListKind listKind,
        uint flags,
        VSOBSEARCHCRITERIA2[] pobSrch,
        ImmutableHashSet<(ProjectId, IAssemblySymbol)> projectAndAssemblySet,
        CancellationToken cancellationToken)
    {
        var searchText = GetSearchText(pobSrch);
        if (searchText == null)
            return null;

        // TODO: Support wildcards (e.g. *xyz, *xyz* and xyz*) like the old language service did.

        switch (listKind)
        {
            case ObjectListKind.Namespaces:
                {
                    var builder = ImmutableArray.CreateBuilder<ObjectListItem>();

                    foreach (var projectIdAndAssembly in projectAndAssemblySet)
                    {
                        var projectId = projectIdAndAssembly.Item1;
                        var assemblySymbol = projectIdAndAssembly.Item2;

                        CollectNamespaceListItems(assemblySymbol, projectId, builder, searchText);
                    }

                    return new ObjectList(ObjectListKind.Namespaces, flags, this, builder.ToImmutable());
                }

            case ObjectListKind.Types:
                {
                    var builder = ImmutableArray.CreateBuilder<ObjectListItem>();

                    foreach (var projectIdAndAssembly in projectAndAssemblySet)
                    {
                        var projectId = projectIdAndAssembly.Item1;
                        var assemblySymbol = projectIdAndAssembly.Item2;

                        var compilation = await this.GetCompilationAsync(projectId, cancellationToken).ConfigureAwait(true);
                        if (compilation == null)
                            return null;

                        CollectTypeListItems(assemblySymbol, compilation, projectId, builder, searchText);
                    }

                    return new ObjectList(ObjectListKind.Types, flags, this, builder.ToImmutable());
                }

            case ObjectListKind.Members:
                {
                    var builder = ImmutableArray.CreateBuilder<ObjectListItem>();

                    foreach (var projectIdAndAssembly in projectAndAssemblySet)
                    {
                        var projectId = projectIdAndAssembly.Item1;
                        var assemblySymbol = projectIdAndAssembly.Item2;

                        var compilation = await this.GetCompilationAsync(projectId, cancellationToken).ConfigureAwait(true);
                        if (compilation == null)
                            return null;

                        CollectMemberListItems(assemblySymbol, compilation, projectId, builder, searchText);
                    }

                    return new ObjectList(ObjectListKind.Types, flags, this, builder.ToImmutable());
                }

            default:
                return null;
        }
    }
}
