// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;

#nullable disable

namespace Microsoft.Build.Tasks
{
    /// <summary>
    /// There is no search path element because the only way to get this resolver is by having the SDKName metadata on the reference.
    /// </summary>
    internal class InstalledSDKResolver : Resolver
    {
        /// <summary>
        ///  Resolved SDKs
        /// </summary>
        private readonly Dictionary<string, ITaskItem> _resolvedSDKs;

        /// <summary>
        /// Construct.
        /// </summary>
        public InstalledSDKResolver(Dictionary<string, ITaskItem> resolvedSDKs, string searchPathElement, GetAssemblyName getAssemblyName, FileExists fileExists, GetAssemblyRuntimeVersion getRuntimeVersion, Version targetedRuntimeVesion)
            : base(searchPathElement, getAssemblyName, fileExists, getRuntimeVersion, targetedRuntimeVesion, System.Reflection.ProcessorArchitecture.None, false)
        {
            _resolvedSDKs = resolvedSDKs;
        }

        /// <inheritdoc/>
        public override bool Resolve(
            AssemblyNameExtension assemblyName,
            string sdkName,
            string rawFileNameCandidate,
            bool isPrimaryProjectReference,
            bool isImmutableFrameworkReference,
            bool wantSpecificVersion,
            string[] executableExtensions,
            string hintPath,
            string assemblyFolderKey,
            List<ResolutionSearchLocation> assembliesConsideredAndRejected,
            out string foundPath,
            out bool userRequestedSpecificFile)
        {
            foundPath = null;
            userRequestedSpecificFile = false;

            if (assemblyName != null)
            {
                // We have found a resolved SDK item that matches the one on the reference items.
                if (_resolvedSDKs.TryGetValue(sdkName, out ITaskItem resolvedSDK))
                {
                    string sdkDirectory = resolvedSDK.ItemSpec;
                    string configuration = resolvedSDK.GetMetadata("TargetedSDKConfiguration");
                    string architecture = resolvedSDK.GetMetadata("TargetedSDKArchitecture");

                    string referenceAssemblyFilePath = Path.Combine(sdkDirectory, "References", configuration, architecture);
                    string referenceAssemblyCommonArchFilePath = Path.Combine(sdkDirectory, "References", "CommonConfiguration", architecture);
                    string referenceAssemblyPathNeutral = Path.Combine(sdkDirectory, "References", configuration, "Neutral");
                    string referenceAssemblyArchFilePathNeutral = Path.Combine(sdkDirectory, "References", "CommonConfiguration", "Neutral");

                    string[] searchLocations =
                    [
                        referenceAssemblyFilePath, // Config-Arch
                        referenceAssemblyPathNeutral, // Config-Neutral
                        referenceAssemblyCommonArchFilePath, // CommonArch-Config
                        referenceAssemblyArchFilePathNeutral // CommonArch-Neutral
                    ];

                    // Lets try and resovle from the windowsmetadata directory first

                    // Go through the search locations and find the assembly
                    foreach (string searchLocation in searchLocations)
                    {
                        string resolvedPath = ResolveFromDirectory(assemblyName, isPrimaryProjectReference, wantSpecificVersion, executableExtensions, searchLocation, assembliesConsideredAndRejected);

                        if (resolvedPath != null)
                        {
                            foundPath = resolvedPath;
                            return true;
                        }
                    }
                }
            }

            return false;
        }
    }
}
