using HRD.AppLogger;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;

namespace HRD.WebApi
{
    public class MonitoringWebRequest
    {
        public string WebRequestMethod { get; set; }
        public string WebRequestPath { get; set; }
        public EN_LoggingLevel LoggingLevel { get; set; } = EN_LoggingLevel.Info;
    }

    //TODO: remove this. configure each with iconfiguretion using ioptions interface
    public static class WebApiConfig
    {
        private static string _dalConnectionstring;

        internal static EN_LoggingLevel GetMonitoringWebRequestLevel(string method, string path)
        {
            var entity = NlogMonitoringWebRequest.FirstOrDefault(
                x => x.WebRequestMethod.Equals(method, StringComparison.OrdinalIgnoreCase) &&
                    (x.WebRequestPath == "*" || path.StartsWith(x.WebRequestPath, StringComparison.OrdinalIgnoreCase))
                    );
            if (entity == default) { return EN_LoggingLevel.Off; }
            return entity.LoggingLevel;
        }

        private static Dictionary<string, string> _customConfig = new Dictionary<string, string>();

        public static int ConnectionstringTimeoutInMin { get; set; } = 5;
        public static bool RaiseRepositoryExceptions { get; set; } = false; //if true, all Repository-Exception are thrown

        public static void Init(dynamic appSettings, System.Reflection.AssemblyName assemblyName = null)
        {
            AssemblyName = assemblyName?.Name ?? string.Empty;
            AssemblyVersion = assemblyName?.Version.ToString() ?? string.Empty;

            Connectionstring = appSettings["ConnectionStrings:sqlConnection"];
            ClientVersion = appSettings["AppConfig:ClientVersion"];
            OfficeFileServerUrl = appSettings["AppConfig:OfficeFileServerUrl"];
            IsLive = bool.Parse(appSettings["AppConfig:LDAP_WebAppGroup_Is_Live"]);

            //LDAP
            //LDAPService.LdapGlobals.LDAP_WebAppGroup_Is_Live = IsLive;

            //Nlog
            NlogConnectionstring = appSettings["Nlog:NlogConnectionstring"];
            if (NlogConnectionstring.Equals("%sqlConnection%", StringComparison.OrdinalIgnoreCase))
            {
                NlogConnectionstring = appSettings["ConnectionStrings:sqlConnection"];
            }

            NlogDBLogLevel = ToEnumLoggingLevel(appSettings["Nlog:NlogDBLogLevel"]);
            NlogFileLogLevel = ToEnumLoggingLevel(appSettings["Nlog:NlogFileLogLevel"]);
            NlogLogDirectory = appSettings["Nlog:NlogLogDirectory"];
            NlogSentryDSN = appSettings["Nlog:NlogSentryDSN"];
            NlogSentryIsEnable = bool.Parse(appSettings["Nlog:NlogSentryIsEnable"]);

            for (int i = 1; i < 100; i++)
            {
                string configString = appSettings[$"Nlog:MonitoringWebRequest{i}"];
                if (!string.IsNullOrEmpty(configString))
                {
                    string[] configArr = configString.Split("|").Select(x => x.Trim()).ToArray();
                    NlogMonitoringWebRequest.Add(new MonitoringWebRequest { WebRequestMethod = configArr[0], WebRequestPath = configArr[1], LoggingLevel = ToEnumLoggingLevel(configArr[2]) });
                }
            }

            AppLoggerConfig.Init(
                WebApiConfig.AssemblyName, WebApiConfig.AssemblyVersion,
                WebApiConfig.NlogDBLogLevel,
                WebApiConfig.NlogFileLogLevel,
                WebApiConfig.NlogLogDirectory);
            AppLoggerConfig.NlogConnectionstring = NlogConnectionstring;
            AppLoggerConfig.NlogSentryConfig.Dsn = WebApiConfig.NlogSentryDSN;
            AppLoggerConfig.NlogSentryConfig.NlogSentryIsEnable = WebApiConfig.NlogSentryIsEnable;

            //custom
            var list = appSettings.GetSection("CustomConfig").GetChildren();
            foreach (var item in list)
            {
                _customConfig.Add(item.Key, item.Value);
            }
        }

        public static EN_LoggingLevel ToEnumLoggingLevel(string enumString)
        {
            if (string.IsNullOrEmpty(enumString))
            {
                return EN_LoggingLevel.Off;
            }

            return (EN_LoggingLevel)Enum.Parse(typeof(EN_LoggingLevel), enumString);
        }

        internal static void InitCustomSetting(Dictionary<string, string> customConfig)
        {
            _customConfig = customConfig;
        }

        public static string Connectionstring
        {
            get { return _dalConnectionstring; }
            set
            {
                _dalConnectionstring = value;
            }
        }

        public static string GetCustomconfig(string key)
        {
            _customConfig.TryGetValue(key, out string result);
            return result;
        }

        public static string AssemblyName { get; set; }
        public static string AssemblyVersion { get; set; }

        //OfficeFileServer
        public static string OfficeFileServerUrl { get; set; }

        //DAL

        public static string ClientVersion { get; set; }
        public static bool IsLive { get; set; }

        //Logger
        public static List<MonitoringWebRequest> NlogMonitoringWebRequest { get; set; } = new List<MonitoringWebRequest>();

        public static string NlogLogDirectory { get; set; } = string.Empty;

        public static string NlogSentryDSN { get; set; } = string.Empty;
        public static bool NlogSentryIsEnable { get; set; } = true;

        public static string NlogConnectionstring { get; set; }
        public static EN_LoggingLevel NlogFileLogLevel { get; set; } = EN_LoggingLevel.Error;
        public static EN_LoggingLevel NlogDBLogLevel { get; set; } = EN_LoggingLevel.Error;

        public static DbContextOptions<DbContext> SQLOptions()
        {
            if (string.IsNullOrEmpty(Connectionstring))
            {
                throw new NullReferenceException("Connectnion string is empty!");
            }
            var optionsBuilder = new DbContextOptionsBuilder<DbContext>();
            optionsBuilder
                .EnableDetailedErrors()
                .UseSqlServer(Connectionstring,
                                opts =>
                                {
                                    opts.CommandTimeout((int)TimeSpan.FromMinutes(ConnectionstringTimeoutInMin).TotalSeconds);
                                    opts.EnableRetryOnFailure(
                                        maxRetryCount: 5,
                                        maxRetryDelay: TimeSpan.FromSeconds(30),
                                        errorNumbersToAdd: null
                                        );
                                }
                            );

            return optionsBuilder.Options;
        }

        public static string ConnectionString(EN_ConnectionType connectionType = EN_ConnectionType.SQLServer)
        {
            switch (connectionType)
            {
                case EN_ConnectionType.SQLServer:
                    return Connectionstring;

                default:

                    return String.Empty;
            }
        }
    }
}