using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Server.DB.Redis;
using System.Collections.Concurrent;
using MrWu.Debug;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using StackExchange.Redis;
using Server.Pack;
using Server.MQ;
using GameData;

namespace Server {
    /// <summary>
    /// 缓存管理
    /// </summary>
    public class CaCheManager {

        private CaCheManager() {
        }

        static CaCheManager() {
            instance = new CaCheManager();
        }

        /// <summary>
        /// 实例
        /// </summary>
        public static CaCheManager instance {
            get;
            private set;
        }

        private IDatabase DB {
            get {
                return redisManager.GetDataBase(DbStyle.main, RedisDictionary.cachedb);
            }
        }

        /// <summary>
        /// 缓 key 对应 缓存的key Tuple('版本','数据')
        /// </summary>
        ConcurrentDictionary<string, Tuple<long, string>> caches = new ConcurrentDictionary<string, Tuple<long, string>>();

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <returns></returns>
        public Tuple<long, string> GetCache(string key) {

            Tuple<long, string> result = null;

            if (!caches.TryGetValue(key, out result)) { //缓存没有值
                result = UpdateKey(key);
            }

            if (result == null && !caches.TryGetValue(key, out result)) {
                Debug.Warning("没这个缓存数据:" + key);
            }

            Debug.Log("获取到缓存!" + result);
            return result;
        }

        public Task<Tuple<long, string>> UpdateKeyAsync(string key)
        {
            return Task.Run(() => UpdateKey(key));
        }

        /// <summary>
        /// 更新缓存_也就是把Redis中的数据读取到内存中来
        /// </summary>
        /// <param name="key"></param>
        public Tuple<long, string> UpdateKey(string key) {

            Debug.Info("更新缓存" + key);
            var type = redisManager.Getdb(RedisDictionary.cachedb).KeyType(key);

            Tuple<long, string> result = null;
            Tuple<long, string> value = null;

            switch (type) {
                case StackExchange.Redis.RedisType.Hash:
                    value = GetHash(key);   //转换成 json ver,data={字典} 字典传输出去
                    break;
                case StackExchange.Redis.RedisType.String:
                    value = GetString(key);  //转换成 json ver,data={字符串}
                    break;
                case StackExchange.Redis.RedisType.List:
                    value = GetList(key);    //转换成 json ver,data={数组}
                    break;
            }
            if (!string.IsNullOrEmpty(key)) {
                result = caches.AddOrUpdate(key, value, (k, v) => value);
            }
            
            //Debug.Info($"得到缓存:{value}");
            
            return result;
        }

        /// <summary>
        /// 获取hash
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        Tuple<long, string> GetHash(string key) {
            var tran = DB.CreateTransaction();
            var keyvaluestask = tran.HashGetAllAsync(key); //拿数据
            var valuestask = tran.StringGetAsync(key + ":ver");  //拿版本
            if (tran.Execute()) {
                if (keyvaluestask.Result == null || keyvaluestask.Result.Length == 0)
                    return null;

                var keyvalues = keyvaluestask.Result;
                long value = -1;
                string verResult = valuestask.Result;
                if (verResult != null && !long.TryParse(verResult, out value)) {
                    Debug.Warning("未获取到版本号!" + key);
                    value = -1;
                }

                JObject obj = new JObject();
                int len = keyvalues.Length;
                for (int i = 0; i < len; i++) {
                    obj[keyvalues[i].Name] = JsonPack.GetData<JObject>(keyvalues[i].Value);
                }
                //Debug.Info("获取到缓存:" + key + ":" + verResult);
                JObject baseobj = new JObject();
                baseobj["ver"] = verResult;
                baseobj["data"] = obj;
                return new Tuple<long, string>(value, JsonPack.GetJson(baseobj));
            } else
                return null;
        }

        /// <summary>
        /// 获取字符串
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        Tuple<long, string> GetString(string key) {
            var tran = DB.CreateTransaction();
            var valuetask = tran.StringGetAsync(key);
            var vertask = tran.StringGetAsync(key + ":ver");

            if (tran.Execute()) {
                long ver = -1;
                string verResult = vertask.Result;
                if (verResult != null && !long.TryParse(verResult, out ver)) {
                    Debug.Warning("未获取到版本号!" + key);
                    ver = -1;
                }
                JObject baseobj = new JObject();
                baseobj["ver"] = ver;
                baseobj["data"] = (string)valuetask.Result;
                return new Tuple<long, string>(ver, JsonPack.GetJson(baseobj));
            } else
                return null;
        }

        /// <summary>
        /// 获取列表
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        Tuple<long, string> GetList(string key) {
            var tran = DB.CreateTransaction();
            var valuestask = tran.ListRangeAsync(key);
            var vertask = tran.StringGetAsync(key + ":ver");

            if (tran.Execute()) {
                var values = valuestask.Result;
                if (values == null || values.Length == 0)
                    return null;

                long ver = -1;
                string verResult = vertask.Result;
                if (verResult != null && !long.TryParse(verResult, out ver)) {
                    Debug.Warning("未获取到版本号!" + key);
                    ver = -1;
                }

                JArray jar = new JArray();

                int len = values.Length;
                for (int i = 0; i < len; i++) {
                    jar.Add(JsonPack.GetData<JObject>(values[i]));
                }

                JObject baseobj = new JObject();
                baseobj["ver"] = ver;
                baseobj["data"] = jar;

                return new Tuple<long, string>(ver, JsonPack.GetJson(baseobj));
            } else {
                return null;
            }
        }

        /// <summary>
        /// 检查版本是否达到了最大
        /// </summary>
        /// <param name="verKey">版本key</param>
        /// <param name="task">增加版本的任务</param>
        private void CheckVerMax(string verKey, Task<long> task) {
            if (task.Result > 9999999999) {
                DB.StringSet(verKey, 1);
            }
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key"></param>
        public bool DelCache(string key) {
            var tran = DB.CreateTransaction();
            tran.KeyDeleteAsync(key);
            tran.KeyDeleteAsync(key + ":ver");
            return tran.Execute();
        }

        /// <summary>
        /// 设Hash缓存数据
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="value"></param>
        public void SetHash(string key, string field, string value) {
            var tran = DB.CreateTransaction();
            tran.HashSetAsync(key, field, value);
            string verKey = key + ":ver";
            var taskVer = tran.StringIncrementAsync(verKey);

            Debug.Info($"保存缓存数据:{field} {value}");
            if (tran.Execute()) {
                Debug.Log("保存Hash缓存成功!" + value);
                CheckVerMax(verKey, taskVer);
            } else {
                Debug.Error("保存配置失败!");
            }
        }

        /// <summary>
        /// 删除缓存的Hash字段
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        public void DelHashField(string key, string field) {
            var tran = DB.CreateTransaction();
            tran.HashDeleteAsync(key, field);
            string verKey = key + ":ver";
            var taskVer = tran.StringIncrementAsync(verKey);

            if (tran.Execute()) {
                Debug.Log("删除Hash子段成功!");
                CheckVerMax(verKey, taskVer);
            } else {
                Debug.Error("删除配置失败!");
            }


        }

        /// <summary>
        /// 设置字符串类型的缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void SetString(string key, string value) {
            var tran = DB.CreateTransaction();
            tran.StringSetAsync(key, value);
            string verKey = key + ":ver";
            var taskVer = tran.StringIncrementAsync(verKey);

            if (tran.Execute()) {
                Debug.Log("设置string缓存成功!" + value);
                CheckVerMax(verKey, taskVer);
            } else {
                Debug.Error("保存配置失败!");
            }
        }

        /*
         * 列表形式的缓存  下次再拓展
         * 
         * 
         * */

        /// <summary>
        /// 发送缓存变化包
        /// </summary>
        /// <param name="key"></param>
        public static void SendCacheChange(string key) {
            PackHead head = PackHead.Create(ServerPackAgreement.CacheChange);
            head.otherString = new string[] { key };

            Debug.Log("发送更新缓存包:");
            GlobalMQ.instance.DeliveryAll(GlobalMQ.CreateMessage(head, null), true);
            head.Dispose();
        }


    }
}
