using ExtensiblePortfolioSite.SDK;
using ExtensiblePortfolioSite.SDK.Caching;
using ExtensiblePortfolioSite.SDK.Git;

using System.Text.Json.Serialization;

namespace ExtensiblePortfolioSite
{
    public static class Config
    {
        [Serializable]
        public class ConfigObject : IJsonOnDeserialized
        {
            [Serializable]
            public class Profile : IJsonOnDeserialized
            {
                [Serializable]
                public class LanguageObject : IJsonOnDeserialized
                {
                    [JsonPropertyName("Name")]
                    [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                    [JsonInclude]
                    public String Name = null!;
                    [JsonPropertyName("Icon")]
                    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
                    public Uri? Icon = null;

                    public void OnDeserialized()
                    {
                        if (Name == null) throw new Exception("Language Name can't be null!");
                    }
                }

                [Serializable]
                public class LinkObject : IJsonOnDeserialized
                {
                    [JsonPropertyName("Name")]
                    [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                    public string Name { get; set; } = null!;

                    [JsonPropertyName("Link")]
                    [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                    public Uri Link { get; set; } = null!;

                    [JsonPropertyName("Icon")]
                    [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                    public Uri? Icon { get; set; } = null!;

                    public void OnDeserialized()
                    {
                        if (Name == null) throw new Exception("Link Name can't be null!");
                        if (Link == null) throw new Exception("Link Link can't be null!");
                    }
                }

                [JsonPropertyName("Name")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public string Name { get; set; } = null!;

                [JsonPropertyName("Phone")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public string? Phone { get; set; } = null!;

                [JsonPropertyName("Email")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public string? Email { get; set; } = null!;

                [JsonPropertyName("Description")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public string[] Description { get; set; } = Array.Empty<String>();

                [JsonPropertyName("Biography")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public string[] Biography { get; set; } = Array.Empty<String>();

                [JsonPropertyName("Languages")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public LanguageObject[] Languages { get; set; } = Array.Empty<LanguageObject>();

                [JsonPropertyName("Links")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public LinkObject[] Links { get; set; } = Array.Empty<LinkObject>();

                public void OnDeserialized()
                {
                    if (Name == null) throw new Exception("Profile Name can't be null");

                    if (Description == null) throw new Exception("Profile Description missing!");
                    if (Languages == null) throw new Exception("Profile Languages missing!");
                    if (Links == null) throw new Exception("Profile Links missing!");
                }
            }

            [Serializable]
            public class GitRepoObject : IJsonOnDeserialized
            {
                [JsonPropertyName("ServiceProvider")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public String ServiceProvider { get; set; } = null!;

                [JsonPropertyName("Repository")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public Uri Repository { get; set; } = null!;

                [JsonPropertyName("Description")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public String[] Description { get; set; } = Array.Empty<String>();

                public void OnDeserialized()
                {
                    if (ServiceProvider == null) throw new Exception("GitRepo ServiceProvider missing!");
                    if (Repository == null) throw new Exception("GitRepo Repository missing!");
                    if (Description == null) throw new Exception("GitRepo Description missing!");
                }

                public IRepository Resolve() => GitManager.GetService(this.ServiceProvider).GetRepository(this.Repository);
            }

            [Serializable]
            public class Logging : IJsonOnDeserialized
            {
                [JsonPropertyName("ConsoleLogging")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public Boolean ConsoleLogging { get; set; } = true;

                [JsonPropertyName("FileLogging")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public Boolean FileLogging { get; set; } = true;

                [JsonPropertyName("FileLogPath")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public String? FileLogPath { get; set; } = null!;

                public void OnDeserialized()
                {
                    if (FileLogging && FileLogPath == null)
                        throw new Exception("FileLogPath null with FileLogging Enabled!");
                }
            }

            [Serializable]
            public class Cache
            {
                [JsonPropertyName("GitRepo")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public Int32 GitRepo = 120;

                [JsonPropertyName("GitUser")]
                [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
                public Int32 GitUser = 1440;
            }

            [JsonPropertyName("Profile")]
            [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
            public Profile ProfileSection { get; set; } = null!;

            [JsonPropertyName("GitRepos")]
            [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
            public GitRepoObject[] GitRepos { get; set; } = Array.Empty<GitRepoObject>();

            [JsonPropertyName("Logging")]
            [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
            public Logging LoggingSection { get; set; } = null!;

            [JsonPropertyName("Cache")]
            [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
            public Cache CacheSection { get; set; } = null!;

            public void OnDeserialized()
            {
                if (ProfileSection == null) throw new Exception("Config Missing ProfileSection!");
                if (GitRepos == null) throw new Exception("Config Missing GitRepos!");
                if (LoggingSection == null) throw new Exception("Config Missing LoggingSection!");
                if (CacheSection == null) throw new Exception("Config Missing CacheSection!");
            }
        }

        private static String ConfigFile = "eps_host_config.json";

        public static void SetConfigFile(String File)
        {
            ConfigFile = File;
        }

        private static ConfigObject? Conf;
        public static ConfigObject GetConfig()
        {
            if (Conf == null)
                ReloadConfig();
            return Conf!;
        }

        public static void ReloadConfig()
        {
            Conf = Json.Deserialize<ConfigObject>(File.ReadAllText(ConfigFile));
            if (Conf == null)
                throw new Exception("Failed to Load Config!");

            // Load Config
            Cache.GitUserLifetime = TimeSpan.FromMinutes(Conf.CacheSection.GitUser);
            Cache.GitRepositoryLifetime = TimeSpan.FromMinutes(Conf.CacheSection.GitRepo);
        }
    }
}
