using System;
using System.Collections.Generic;
using InABox.Core;

namespace InABox.Configuration
{
    public enum ConfigurationCacheType
    {
        Local,
        Global,
        User
    }

    public static class ConfigurationCache
    {
        private static readonly Dictionary<Type, Dictionary<string, string>> _localcache = new Dictionary<Type, Dictionary<string, string>>();
        private static readonly Dictionary<Type, Dictionary<string, string>> _globalcache = new Dictionary<Type, Dictionary<string, string>>();
        private static readonly Dictionary<Type, Dictionary<string, string>> _usercache = new Dictionary<Type, Dictionary<string, string>>();

        private static readonly bool _shouldLog = false;

        private static Dictionary<Type, Dictionary<string, string>> GetCache(ConfigurationCacheType type)
        {
            return type == ConfigurationCacheType.Local
                ? _localcache
                : type == ConfigurationCacheType.Global
                    ? _globalcache
                    : _usercache;
        }

        private static void Log(LogType type, string message)
        {
            if (_shouldLog)
            {
                Logger.Send(type, "", message);
            }
        }

        public static T Check<T>(ConfigurationCacheType type, string section)
        {
            Log(LogType.Information, $"- Checking {typeof(T)}({type},{section})");
            var _cache = GetCache(type);
            if (_cache.ContainsKey(typeof(T)))
            {
                var subcache = _cache[typeof(T)];
                if (subcache.ContainsKey(section))
                {
                    var data = subcache[section];
                    if (!string.IsNullOrWhiteSpace(data))
                    {
                        Log(LogType.Information, $"- Checking: Found {typeof(T)}({type},{section}) -> {subcache[section]}");
                        var result = Serialization.Deserialize<T>(subcache[section]);
                        if(result is BaseObject obj)
                        {
                            obj.CommitChanges();
                        }
                        return result;
                    }
                }
            }

            return default;
        }

        public static void Add<T>(ConfigurationCacheType type, string section, T config)
        {
            Log(LogType.Information, $"- Adding {typeof(T)}({type},{section})");
            var _cache = GetCache(type);
            if (!_cache.ContainsKey(typeof(T)))
                _cache[typeof(T)] = new Dictionary<string, string>();
            var subcache = _cache[typeof(T)];
            subcache[section] = Serialization.Serialize(config);
        }

        public static void Clear<T>(ConfigurationCacheType type, string section)
        {
            Log(LogType.Information, $"- Clearing {typeof(T)}({type},{section})");
            var _cache = GetCache(type);
            if (_cache.ContainsKey(typeof(T)))
            {
                var subcache = _cache[typeof(T)];
                if (subcache.ContainsKey(section))
                {
                    Log(LogType.Information, $"- Clearing: Removing {typeof(T)}({type},{section})");
                    subcache[section] = "";
                }
            }
        }

        /// <summary>
        ///     Clear the entire cache for a given cache type <see cref="ConfigurationCacheType" />. Intended for use when the
        ///     database server has changed and therefore the entire cache needs to be reset.
        /// </summary>
        /// <param name="type">The type of cache to clear. </param>
        public static void ClearAll(ConfigurationCacheType type)
        {
            var _cache = GetCache(type);
            _cache.Clear();
        }
    }
}