using Timer = System.Timers.Timer;

namespace CacheModule{

    public class CacheService
    {
        private readonly Dictionary<string, Dictionary<string, CachedObject>> _cache = new Dictionary<string, Dictionary<string, CachedObject>>();

        private static object _lock = new object();

        private readonly Timer _timer = new Timer();

        private static CacheService? _instance;

        private CacheService(){
            _timer.Interval = 3600 * 1000;
            _timer.Elapsed += (sender, e) => ClearExpired();
            _timer.Start();
        }
        public static CacheService Instance
        {
            get
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new CacheService();
                    }
                    return _instance;
                }
            }
        }

        public void Add(string functionName, string functionParams, object value, Duration duration)
        {
            Add(functionName, functionParams, value, (int)duration);
        }

        public void Add(string functionName, string functionParams, object value, int duration)
        {
            if (!_cache.ContainsKey(functionName))
            {
                _cache[functionName] = new Dictionary<string, CachedObject>();
            }

            _cache[functionName][functionParams] = new CachedObject(){
                Value = value,
                Timestamp = DateTime.Now,
                Duration = duration
            };
        }

        public object? Get(string functionName, string functionParams)
        {
            if (!_cache.ContainsKey(functionName))
            {
                return null;
            }

            if (!_cache[functionName].ContainsKey(functionParams))
            {
                return null;
            }
            var cachedObject = _cache[functionName][functionParams];
            if (cachedObject.IsExpired())
            {
                _cache[functionName].Remove(functionParams);
                return null;
            }
            return cachedObject.Value;
        }

        public void Clear()
        {
            _cache.Clear();
        }

        public void Clear(string functionName)
        {
            if (_cache.ContainsKey(functionName))
            {
                _cache.Remove(functionName);
            }
        }

        public void Clear(string functionName, string functionParams)
        {
            if (_cache.ContainsKey(functionName))
            {
                if (_cache[functionName].ContainsKey(functionParams))
                {
                    _cache[functionName].Remove(functionParams);
                    if (_cache[functionName].Count == 0)
                    {
                        _cache.Remove(functionName);
                    }
                }
            }
        }

        public void ClearExpired()
        {
            foreach (var functionName in _cache.Keys)
            {
                foreach (var functionParams in _cache[functionName].Keys)
                {
                    if (_cache[functionName][functionParams].IsExpired())
                    {
                        _cache[functionName].Remove(functionParams);
                        if (_cache[functionName].Count == 0)
                        {
                            _cache.Remove(functionName);
                        }
                    }
                }
            }
        }


    }
}