using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mono.Options;
using Newtonsoft.Json;

namespace isn
{
    public partial class Program
    {

        public static void LoadConfig()
        {
            FileInfo cfgSettingIf = new FileInfo(_configFileName);
            if (cfgSettingIf.Exists)
            {
                var json = File.ReadAllText(cfgSettingIf.FullName);
                settings = JsonConvert.DeserializeObject<Settings>(json);
                if (settings.DefaultSourceKey == null)
                {
                    Settings.DefaultSourceKey = settings.Sources.Keys.FirstOrDefault();
                }
                CurrentSource = settings.DefaultSourceKey;
            }
        }
        static readonly OptionSet storeoptions = new OptionSet {
            { "s|source=", "use source", val => CurrentSource = CurrentSource ?? val },
            { "h|help", "show this message and exit", h => shouldShowPushHelp = h != null },
        };

        private static readonly string _configFileName =
        Path.Combine(
        Path.Combine(Environment.GetFolderPath(
            Environment.SpecialFolder.UserProfile), ".isn"),
            "config.json")
            ;

        public const string push = "push";
        static readonly OptionSet options = new OptionSet {
                { "h|help", "show this message and exit", h => shouldShowHelp = h != null },
                { "v|version", "show soft version info and exit", h => shouldShowVersion = h != null }
            };

        static string apiKey;

        static readonly OptionSet pushoptions = new OptionSet {
                { "k|api-key=", "use api key", val => apiKey = apiKey ?? val },
                { "p|store-api-key", "store used api key", val => storApiKey = val != null },
                { "s|source=", "use source", val => CurrentSource = CurrentSource ?? val },
                { "h|help", "show this message and exit", h => shouldShowPushHelp = h != null },
            };
        static readonly OptionSet sourceoptions = new OptionSet {
                { "h|help", "show this message and exit", h => shouldShowSourceHelp = h != null },
            };

        static readonly OptionSet showOptions = new OptionSet {
                { "h|help", "show this message and exit", h => shouldShowSourceHelp = h != null },
            };

        private static bool shouldShowHelp;
        private static bool shouldShowVersion;
        private static bool shouldShowSourceHelp;
        private static bool shouldShowPushHelp;
        private static string currentSource = null;
        private static bool storApiKey = false;

        static Settings settings = null;

        public static Settings Settings
        {
            get
            {
                if (settings == null)
                    LoadConfig();
                if (settings == null)
                {
                    settings = new Settings
                    {
                        DataProtectionTitle = "isn",
                        Sources = new Dictionary<string, SourceSettings>()
                    };
                }
                return settings;
            }
        }

        public static string CurrentSource { get => currentSource; set => currentSource = value; }

        static int Main(string[] args)
        {
            var commandSet = new CommandSet("isn");
            var srclst = new Command("list")
            {
                Run = sargs => SourceList(sargs)
            };

            var showconfig = new Command("config")
            {
                Run = sargs => ShowConfig()
            };

            var srcadd = new Command("add")
            {
                Run = sargs => SourceAdd(sargs)
            };

            var srcsetdef = new Command("set-default")
            {
                Run = sargs => SetDefaultSource(sargs?.FirstOrDefault())
            };

            var showCommand = new Command("show")
            {
                Run = sargs =>
                {
                    var showCommandSet = new CommandSet("show")
                    {
                        showconfig
                    };
                    var pargs = showOptions.Parse(sargs);
                    if (shouldShowSourceHelp)
                    {
                        // output the options
                        Console.WriteLine("Sources Options:");
                        showOptions.WriteOptionDescriptions(Console.Out);
                        return;
                    }
                    showCommandSet.Run(pargs);
                }
            };

            var srcCmd = new Command("sources")
            {
                Run = sargs =>
                {

                    var sourcesCmdSet = new CommandSet("sources")
                    {
                        srclst,
                        srcadd,
                        srcsetdef
                    };


                    var pargs = sourceoptions.Parse(sargs);
                    if (shouldShowSourceHelp)
                    {
                        // output the options
                        Console.WriteLine("Sources Options:");
                        sourceoptions.WriteOptionDescriptions(Console.Out);
                        return;
                    }
                    sourcesCmdSet.Run(pargs);
                }
            };

            var add = new Command("add")
            {
                Run = sargs => Add(sargs)
            };

            commandSet.Add(add);

            var pushCmd = new Command(push)
            {
                Run = sargs =>
                {
                    var pargs = pushoptions.Parse(sargs);
                    if (args.Count()==0) shouldShowPushHelp=true;
                    if (shouldShowPushHelp)
                    {
                        // output the options
                        Console.Error.WriteLine("Push Options:");
                        pushoptions.WriteOptionDescriptions(Console.Out);
                        return;
                    }
                    List<PushReport> reports = PushPkg(pargs);
                }
            };

            var setapikey = new Command("set-api-key")
            {
                Run = sargs => StoreApiKey(sargs)
            };

            commandSet.Add(pushCmd);
            commandSet.Add(setapikey);
            commandSet.Add(srcCmd);
            commandSet.Add(showCommand);

            List<string> extra;
            try
            {
                // parse the command line
                extra = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Error.Write("isn: ");
                Console.Error.WriteLine(e.Message);
                Console.Error.WriteLine("Try `isn --help' for more information.");
                return 2;
            }


            if (shouldShowHelp)
            {
                // output the options
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return 1;
            }

             if (shouldShowVersion)
            {
                Console.WriteLine("isn version " + GitVersionInformation.AssemblySemFileVer);
            }

            return commandSet.Run(args);

        }
    }
}
