using System;
using System.Collections.Generic;
using System.IO.Abstractions;
using System.Linq;
using System.Text.Json;
using BO.Console.Options;
using Quadarax.Foundation.Core.Console;
using Quadarax.Foundation.Core.Data.Interface.Entity;
using Quadarax.Foundation.Core.Logging;
using Quadarax.Foundation.Core.Object.Extensions;
using Quadarax.Foundation.Core.QConsole;
using Quadarax.Foundation.Core.QConsole.Argument;
using Quadarax.Foundation.Core.QConsole.Command.Base;

namespace BO.Console.Commands.Base
{
    internal abstract class BaseLocalCommand : AbstractCommand, ILogHandler
    {
        #region *** Constants ***

        protected const string CS_ARG_NAME_DUMP = "dump";
        private const string CS_ARG_HINT_DUMP = "<is_dump_reponses>";
        private const string CS_ARG_DESC_DUMP = "Flag if set dumps incomming json messages.";

        protected const string CS_ARG_NAME_DEBUG = "dbg";
        private const string CS_ARG_HINT_DEBUG = "<is_debug_mode>";
        private const string CS_ARG_DESC_DEBUG = "Flag if set writes debug messages.";

        protected const string CS_ARG_NAME_FORCE = "force";
        private const string CS_ARG_HINT_FORCE = "<is_force>";
        private const string CS_ARG_DESC_FORCE = "Flag if set, then overrite existing entity, otherwise cancel operation.";


        #endregion

        protected Configuration Configuration { get; private set; }

        protected bool? IsForce { get; private set; }

        protected bool IsDebug { get; private set; }

        protected IFileSystem FileSystem { get; private set; }

        protected BaseLocalCommand(Engine engine) : base(engine)
        {

        }

        protected override void OnInitialize()
        {
            base.OnInitialize();
            Configuration = JsonSerializer.Deserialize<Configuration>(FileSystem.File.ReadAllText(Constants.CS_CONFIGURATION_FILE));
        }

        protected override void OnValidateArguments()
        {
            base.OnValidateArguments();
            
            if (ContainsArgument(CS_ARG_NAME_FORCE))
            {
                IsForce = WasArgumentSpecified(CS_ARG_NAME_FORCE);
                if (IsForce.GetValueOrDefault(false))
                    WriteWarning("Force flag is set!");
            }

            IsDebug = WasArgumentSpecified(CS_ARG_NAME_DEBUG);

            if (IsDebug)
                DebugConsoleWriter.IsWriteDebugEnabled = true;
        }

        protected override IEnumerable<AbstractArgument> OnSetupArguments()
        {
            FileSystem = new FileSystem();
            var args = base.OnSetupArguments().ToList();
            args.Add(new FlagArgument(CS_ARG_NAME_DUMP, CS_ARG_DESC_DUMP, CS_ARG_HINT_DUMP, false));
            args.Add(new FlagArgument(CS_ARG_NAME_DEBUG, CS_ARG_DESC_DEBUG, CS_ARG_HINT_DEBUG, false));
            return args;
        }


        protected void AppendForceArgument(IList<AbstractArgument> args, string alternativeUserDescription = null)
        {
            args.Add(new FlagArgument(CS_ARG_NAME_FORCE, string.IsNullOrEmpty(alternativeUserDescription) ? CS_ARG_DESC_FORCE : alternativeUserDescription, CS_ARG_HINT_FORCE, false));
        }

        public void Log(LogSeverityEnum type, string message, Exception e = null)
        {
            if ((type == LogSeverityEnum.Trace || type == LogSeverityEnum.Debug) && !IsDebug)
                return;
            WriteInfo($"{type}: {message}" + (e == null ? "" : e.Message));
        }

        protected void WriteDtoToConsole(IDto dto)
        {
            var props = dto.GetAllPropertyValues();
            using (var wName = new ConsoleWriter(ConsoleColor.White))
            {
                using (var wValue = new ConsoleWriter(ConsoleColor.Yellow))
                {
                    var maxKeyLength = props.Keys.Max(x => x.Length);
                    foreach (var prop in props)
                    {
                        wName.Write(prop.Key);
                        wName.Write(new string(' ', maxKeyLength - prop.Key.Length) + " :\t");
                        wValue.WriteLine(prop.Value?.ToString());
                    }
                }
            }
        }
    }
}
