using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.NET.Build.Tasks; // LockFileCache
using NuGet.Frameworks; // NuGetFramework.Parse(targetframework)
using NuGet.ProjectModel; // LockFileTargetLibrary
namespace ILLink.Tasks
{
	public class GetRuntimeLibraries : Task
	{
		/// 
		///   Path to the assets file.
		/// 
		[Required]
		public ITaskItem AssetsFilePath { get; set; }
		/// 
		///   Target framework for which to get the platform
		///   libraries.
		/// 
		[Required]
		public string TargetFramework { get; set; }
		/// 
		///   Runtime identifier for which to get the platform
		///   libraries.
		/// 
		[Required]
		public string RuntimeIdentifier { get; set; }
		/// 
		///   Name of the library to consider the "platform"
		///   library.
		/// 
		[Required]
		public string[] PackageNames { get; set; }
		[Output]
		public ITaskItem[] RuntimeLibraries { get; private set; }
		public override bool Execute()
		{
			var lockFile = new LockFileCache(BuildEngine4).GetLockFile(AssetsFilePath.ItemSpec);
			var lockFileTarget = lockFile.GetTarget(NuGetFramework.Parse(TargetFramework), RuntimeIdentifier);
			if (lockFileTarget == null) {
				var targetString = string.IsNullOrEmpty(RuntimeIdentifier) ? TargetFramework : $"{TargetFramework}/{RuntimeIdentifier}";
				throw new Exception($"Missing target section {targetString} from assets file {AssetsFilePath}. Ensure you have restored this project previously.");
			}
			Dictionary packages = new Dictionary(lockFileTarget.Libraries.Count, StringComparer.OrdinalIgnoreCase);
			foreach (var lib in lockFileTarget.Libraries) {
				packages.Add(lib.Name, lib);
			}
			HashSet packageNames = new HashSet(PackageNames);
			var rootPackages = lockFileTarget.Libraries.Where(l => packageNames.Contains(l.Name));
			var packageQueue = new Queue(rootPackages);
			var libraries = new List();
			while (packageQueue.Count > 0) {
				var package = packageQueue.Dequeue();
				foreach (var lib in package.RuntimeAssemblies) {
					libraries.Add(lib.ToString());
				}
				foreach (var dep in package.Dependencies.Select(d => d.Id)) {
					packageQueue.Enqueue(packages[dep]);
				}
			}
			RuntimeLibraries = libraries.Select(l => new TaskItem(l)).ToArray();
			return true;
		}
	}
}