using System;
using System.Collections.Generic;
using System.Linq;
using BO.Console.Commands.Base;
using BO.Console.Extensions;
using Quadarax.Foundation.Core.Logging;
using Quadarax.Foundation.Core.QConsole;
using Quadarax.Foundation.Core.QConsole.Argument;
using Quadarax.Foundation.Core.QConsole.Attributes;
using Quadarax.Foundation.Core.QConsole.Value;
using Quadarax.Foundation.Core.Value;
using Quadarax.Foundation.Core.Value.Extensions;

namespace BO.Console.Commands.Document
{
    [CommandDefinition]
    internal class DocumentGetCommand : AbstractWrkGetCommand
    {
        #region *** Constants ***
        private const string CS_CMD_DOCGET_NAME = "document_get";
        private const string CS_CMD_DOCGET_DESCR = "Get single document with artifacts by specification.";

        protected const string CS_ARG_NAME_NOCONTENT = "nocontent";
        private const string CS_ARG_HINT_NOCONTENT = "<no_content_saved>";
        private const string CS_ARG_DESC_NOCONTENT = "Flag if set skip content saving. Related to arguments '" + CS_ARG_NAME_OUTDIR + "' and '" + CS_ARG_NAME_FORCE + "'.";

        protected const string CS_ARG_NAME_OUTDIR = "outdir";
        private const string CS_ARG_HINT_OUTDIR = "<output_directory>";
        private const string CS_ARG_DESC_OUTDIR = "Alternative output directory to save content. If not exists attempts to create it. If not set use current directory.";
        #endregion

        #region *** Properties ***

        public override string Name => CS_CMD_DOCGET_NAME;
        public override string Description => CS_CMD_DOCGET_DESCR;

        protected bool IsNoContent { get; set; }
        protected string OutputDirectory { get; set; }
        #endregion

        #region *** Constructor ***
        public DocumentGetCommand(Engine engine) : base(engine)
        {
        }
        #endregion

        #region *** EXECUTE ***
        protected override Result OnExecute()
        {
            var document = Client.GetWorkspaceDocumentAsync(ApiKey, ApiKeyPassword,IdentificationType, IdentificationValue,UserName).Result;
            
            if (document == null)
                throw new Exception($"Document {IdentificationType}: '{IdentificationValue}' not found!");

            WriteDtoToConsole(document);

            if (!IsNoContent)
            {
                //var tasksDownload = new List<Task>();
                foreach (var art in document.Artifacts)
                {
                    //tasksDownload.Add(Task.Factory.StartNew(async () =>
                    //{
                        var bWrite = false;
                        var fullFileName = art.GetFullFileName(FileSystem, OutputDirectory);
                        if (FileSystem.File.Exists(fullFileName))
                        {
                            if (IsForce.GetValueOrDefault(false))
                            {
                                WriteDebugInfo($"Artifact file '{fullFileName}' already exists. Override.");
                                FileSystem.File.Delete(fullFileName);
                                WriteDebugInfo($"Artifact file '{fullFileName}' deleted.");
                                bWrite = true;
                            }
                        }
                        else
                        {
                            bWrite = true;
                        }

                        if (bWrite)
                        {
                            using (var fw = FileSystem.File.OpenWrite(fullFileName))
                            {
                                var content = Client.GetWorkspaceDocumentContentAsync(ApiKey, ApiKeyPassword,
                                    document.Id, art.Id, UserName).Result;
                                if (content != null)
                                {
                                    content.CopyTo(fw);
                                    fw.Flush();
                                    WriteCaption($"Artifact content file '{art.GetFileName(FileSystem)}' saved.");
                                }
                                else
                                {
                                    WriteError($"Artifact content file '{art.GetFileName(FileSystem)}' returns empty content! Skip.");
                                }
                            }
                        }
                        else
                        {
                            WriteError($"Artifact content file '{art.GetFileName(FileSystem)}' already exists! Skip.");
                        }
                    //}));
                }

                //Task.WaitAll(tasksDownload.ToArray());
            }
            else
            {
                WriteInfo("Artifacts content saving skip.");
            }
            return new Result();
        }
        #endregion

        #region *** Private operations ***

        protected override void OnValidateArguments()
        {
            base.OnValidateArguments();
            IsNoContent = GetArgumentValueOrDefault<bool>(CS_ARG_NAME_NOCONTENT);
            if (!IsNoContent)
            {
                OutputDirectory = GetArgumentValueOrDefault<string>(CS_ARG_NAME_OUTDIR).EnsurePathNonBackslash();
                if (!FileSystem.Directory.Exists(OutputDirectory))
                {
                    Log(LogSeverityEnum.Debug, $"Output directory '{OutputDirectory}' not exists. Creating...");
                    FileSystem.Directory.CreateDirectory(OutputDirectory);
                    Log(LogSeverityEnum.Info, $"Output directory '{OutputDirectory}' created.");
                }
            }
        }

        protected override IEnumerable<AbstractArgument> OnSetupArguments()
        {
            var result = base.OnSetupArguments().ToList();
            result.Add(new NamedArgument(CS_ARG_NAME_OUTDIR, CS_ARG_DESC_OUTDIR, CS_ARG_HINT_OUTDIR, TypeValuesEnum.String, FileSystem.Directory.GetCurrentDirectory(), false));
            result.Add(new FlagArgument(CS_ARG_NAME_NOCONTENT, CS_ARG_DESC_NOCONTENT, CS_ARG_HINT_NOCONTENT, false));
            AppendUserArgument(result);
            AppendForceArgument(result);
            return result;
        }
        #endregion
    }
}
