using System;
using Newtonsoft.Json;
using StackExchange.Redis;
using CommonClass.Factory;
using Autofac;

namespace Cmdjy.Bll
{
    /// <summary>
    /// 缓冲提供器工厂
    /// </summary>
    public static class CacheFactory
    {
        /// <summary>
        /// 缓冲提供器
        /// </summary>
        public static ICache Cache {
            get => new RedisHelper() as ICache;
        }
    }

    public class CacheRegister:IRegister
    {
        public void Register(ContainerBuilder builder) {
            builder.Register<ICache>(c => new RedisHelper());
        }

    }

    public interface ICache
    {
        /// <summary>
        /// 是否可用
        /// </summary>
        bool Usable { get; }
        /// <summary>
        /// 获取数据
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">保存的key</param>
        /// <returns>缓存的数据</returns>
        T GetData<T>(string key) where T : class;
        /// <summary>
        /// 缓存数据,缓存时间默认
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">保存的key</param>
        /// <param name="obj">缓存的数据</param>
        void SetData<T>(string key,T obj);
        /// <summary>
        /// 缓存数据
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">保存的key</param>
        /// <param name="obj">缓存的数据</param>
        /// <param name="timeSpan">缓存时间</param>
        void SetData<T>(string key,T obj,TimeSpan timeSpan);
        /// <summary>
        /// 删除数据缓存
        /// </summary>
        /// <param name="key">数据的键</param>
        void RemoveData(string key);
    }
    /// <summary>
    /// 数据缓存实现类
    /// </summary>
    public class RedisHelper:ICache
    {
        public IDatabase Database { get; set; }
        public static ConnectionMultiplexer Connection { get; set; }

        public bool Usable {
            get {
                return Connection != null && Connection.IsConnected && Database != null;
            }
        }

        public RedisHelper() {
            if(Connection == null) {
                var connectionStr = WebSettings.RedisConnectionString;
                if(!string.IsNullOrEmpty(connectionStr)) Connection = ConnectionMultiplexer.Connect(connectionStr);
            }
            if(Connection != null && Connection.IsConnected) {
                this.Database = this.Database ?? Connection.GetDatabase(0);
            }
        }

        public virtual T GetData<T>(string key) where T : class {
            if(!Usable) return null;
            return fromJson<T>(Database.StringGet(key));
        }

        public virtual void SetData<T>(string key,T obj) {
            SetData(key,obj,WebSettings.DefaultCacheTimeSpan);
        }

        public virtual void SetData<T>(string key,T obj,TimeSpan timeSpan) {
            if(!Usable) return;
            if(timeSpan == null) {
                this.Database.StringSet(key,toJson(obj));
            }
            else {
                this.Database.StringSet(key,toJson(obj),timeSpan);
            }
        }

        private static string toJson(object value) {
            if(value == null) return null;
            return JsonConvert.SerializeObject(value);
        }

        private static T fromJson<T>(string value) where T : class {
            if(value == null) return null;
            return JsonConvert.DeserializeObject<T>(value);
        }

        public void RemoveData(string key) {
            if(!Usable) return;
            this.Database.KeyDelete(key);
        }
    }
}