// 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;
using Cake.Common.Tools.DotNet.MSBuild;
using Cake.Core;
using Cake.Core.Diagnostics;
using Cake.Core.IO;
using Cake.Core.Tooling;

namespace Cake.Common.Tools.DotNet.Restore
{
    /// <summary>
    /// .NET project restorer.
    /// </summary>
    public sealed class DotNetRestorer : DotNetTool<DotNetRestoreSettings>
    {
        private readonly ICakeEnvironment _environment;

        /// <summary>
        /// Initializes a new instance of the <see cref="DotNetRestorer" /> class.
        /// </summary>
        /// <param name="fileSystem">The file system.</param>
        /// <param name="environment">The environment.</param>
        /// <param name="processRunner">The process runner.</param>
        /// <param name="tools">The tool locator.</param>
        /// <param name="log">The cake log.</param>
        public DotNetRestorer(
            IFileSystem fileSystem,
            ICakeEnvironment environment,
            IProcessRunner processRunner,
            IToolLocator tools,
            ICakeLog log) : base(fileSystem, environment, processRunner, tools)
        {
            _environment = environment;
        }

        /// <summary>
        /// Restore the project using the specified path and settings.
        /// </summary>
        /// <param name="root">List of projects and project folders to restore. Each value can be: a path to a project.json or global.json file, or a folder to recursively search for project.json files.</param>
        /// <param name="settings">The settings.</param>
        public void Restore(string root, DotNetRestoreSettings settings)
        {
            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings));
            }

            RunCommand(settings, GetArguments(root, settings));
        }

        private ProcessArgumentBuilder GetArguments(string root, DotNetRestoreSettings settings)
        {
            var builder = CreateArgumentBuilder(settings);

            builder.Append("restore");

            // Specific root?
            if (root != null)
            {
                builder.AppendQuoted(root);
            }

            // Runtime
            if (!string.IsNullOrEmpty(settings.Runtime))
            {
                builder.Append("--runtime");
                builder.Append(settings.Runtime);
            }

            // Output directory
            if (settings.PackagesDirectory != null)
            {
                builder.Append("--packages");
                builder.AppendQuoted(settings.PackagesDirectory.MakeAbsolute(_environment).FullPath);
            }

            // Sources
            if (settings.Sources != null)
            {
                foreach (var source in settings.Sources)
                {
                    builder.Append("--source");
                    builder.AppendQuoted(source);
                }
            }

            // Config file
            if (settings.ConfigFile != null)
            {
                builder.Append("--configfile");
                builder.AppendQuoted(settings.ConfigFile.MakeAbsolute(_environment).FullPath);
            }

            // Ignore failed sources
            if (settings.NoCache)
            {
                builder.Append("--no-cache");
            }

            // Disable parallel
            if (settings.DisableParallel)
            {
                builder.Append("--disable-parallel");
            }

            // Ignore failed sources
            if (settings.IgnoreFailedSources)
            {
                builder.Append("--ignore-failed-sources");
            }

            // Ignore project to project references
            if (settings.NoDependencies)
            {
                builder.Append("--no-dependencies");
            }

            // Force restore
            if (settings.Force)
            {
                builder.Append("--force");
            }

            // Interactive
            if (settings.Interactive)
            {
                builder.Append("--interactive");
            }

            // Use lock file
            if (settings.UseLockFile)
            {
                builder.Append("--use-lock-file");
            }

            // Locked mode
            if (settings.LockedMode)
            {
                builder.Append("--locked-mode");
            }

            // Lock file path
            if (settings.LockFilePath != null)
            {
                builder.AppendSwitchQuoted("--lock-file-path", " ", settings.LockFilePath.MakeAbsolute(_environment).FullPath);
            }

            // Force Evaluate
            if (settings.ForceEvaluate)
            {
                builder.Append("--force-evaluate");
            }

            // Publish ReadyToRun
            if (settings.PublishReadyToRun.HasValue)
            {
                if (settings.PublishReadyToRun.Value)
                {
                    builder.Append("-p:PublishReadyToRun=true");
                }
                else
                {
                    builder.Append("-p:PublishReadyToRun=false");
                }
            }

            if (settings.MSBuildSettings != null)
            {
                builder.AppendMSBuildSettings(settings.MSBuildSettings, _environment);
            }

            return builder;
        }
    }
}
