using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace ASHermed.SinoInterface.Tools
{

    public class MemoryCacheHelper
    {
        private static object _lock = new object();
        private ILogger<MemoryCacheHelper> _logger;
        private IMemoryCache _cache;
        public MemoryCacheHelper(ILogger<MemoryCacheHelper> logger, IMemoryCache cache)
        {
            _logger = logger;
            _cache = cache;
        }
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object Get(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("key不能为空");
            }
            object result = _cache.Get(key);
            return result;
        }
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            var res = Get(key);
            if (res == null)
            {
                return default(T);
            }
            T result = JsonConvert.DeserializeObject<T>(res.ToString());
            return result;
        }
        public T GetOrSet<T>(string key, Func<T> getData, DateTime dtExpireTime, bool reload = false)
        {
            return GetOrSet(key, getData, dtExpireTime.Subtract(DateTime.Now).TotalMinutes, reload);
        }
        public T GetOrSet<T>(string key, Func<T> getData, double timeOut = 1, bool reload = false)
        {
            T tResult = default(T);
            Stopwatch sw = new Stopwatch();
            sw.Start();
            //_logger.LogWarning("读取缓存" + key);
            if (reload || !_cache.TryGetValue(key, out tResult))
            {
                MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
                options.AbsoluteExpiration = DateTime.Now.AddMinutes(timeOut);
                //options.SlidingExpiration = TimeSpan.FromMinutes(timeOut);
                //options.RegisterPostEvictionCallback(((string skey, object value, EvictionReason reason, object state) =>
                //{
                //    if (reason == EvictionReason.Expired)
                //    {
                //        GetOrSet<T>(skey, getData, 20);
                //    }

                //}), this);

                sw.Restart();
                tResult = getData();
                sw.Stop();
                //_logger.LogWarning("读取缓存完成（未命中）" + key + "----" + sw.ElapsedMilliseconds);
                _cache.Set(key, tResult, DateTime.Now.AddMinutes(timeOut));

            }
            else
            {
                sw.Stop();
                // _logger.LogWarning("读取缓存完成" + key + "----" + sw.ElapsedMilliseconds);
            }

            return tResult;
        }

        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Add(string key, object value, double timeOut)
        {
            _cache.Set(key, value, DateTime.Now.AddMinutes(timeOut));
            return true;
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public void Remove(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("key不能为空");
            }
            _cache.Remove(key);
        }

        /// <summary>
        /// 修改缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Set(string key, string value, double timeOut)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("key不能为空");
            }
            Remove(key);
            return Add(key, value.ToString(), timeOut);
        }
        public bool Set<T>(string key, T value, double timeOut)
        {
            return Set(key, JsonConvert.SerializeObject(value), timeOut);
        }
        public bool Set<T>(string key, T value, DateTime timeOut)
        {
            return Set(key, value, timeOut.Subtract(DateTime.Now).TotalMinutes);
        }

        /// <summary>
        /// 获取所有缓存键
        /// </summary>
        /// <returns></returns>
        public List<string> GetCacheKeys()
        {
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
            var entries = _cache.GetType().GetField("_entries", flags).GetValue(_cache);
            var cacheItems = entries as IDictionary;
            var keys = new List<string>();
            if (cacheItems == null) return keys;
            foreach (DictionaryEntry cacheItem in cacheItems)
            {
                keys.Add(cacheItem.Key.ToString());
            }
            return keys;
        }
    }
}