using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using GameDAL.Game;
using GameMessage;
using MrWu;
using MrWu.Debug;
using ObjectMessage;
using Server.DB.Redis;
using StackExchange.Redis;
using Server.Core;

namespace Server.Net
{
    /// <summary>
    /// 会话UUID管理
    /// </summary>
    public class SessionUUIDManager : SingleInstance<SessionUUIDManager>, IDisposable
    {
        /// <summary>
        /// 会话 UUID 集合
        /// </summary>
        protected ConcurrentDictionary<string, SessionUserData> SessionUUIDs =
            new ConcurrentDictionary<string, SessionUserData>();

        public int SessionCnt
        {
            get { return SessionUUIDs.Count; }
        }

        private Timer _timer;

        public SessionUUIDManager()
        {
            MessageDispatcher.Instance.AddListener(MessageCode.RegisterSessionRequest, OnRegisterSession);
            MessageDispatcher.Instance.AddListener(MessageCode.UpdateSessionExpireTime, OnSessionExpireTime);
            
            MessageDispatcher.Instance.AddListener(MessageCode.GamePackTestRequest,OnGamePackTestRequest);
            

            _timer = new Timer(OnTimer, null, 3000, 10 * 1000);
        }

        public void Init()
        {
        }

        /// <summary>
        /// 更新过期时间
        /// </summary>
        public void UpdateExpiredTime(string sessionUUID, int userid)
        {
            if (SessionUUIDs.ContainsKey(sessionUUID))
            {
                SessionUUID.UpdateExpiredTime(sessionUUID);
                //redisManager.db.KeyExpire(GetSessionUUIDKey(sessionUUID), TimeSpan.FromMinutes(ExpireTime));
            }
        }

        /// <summary>
        /// 添加一个会话 UUID
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        public string CreateSessionUUID(int userid)
        {
            return SessionUUID.CreateSessionUUID(userid);

            // string sessionUUID = Guid.NewGuid().ToString().Replace("-", "");
            // redisManager.db.StringSet(GetSessionUUIDKey(sessionUUID), userid, TimeSpan.FromMinutes(ExpireTime));
            // return sessionUUID;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sessionUUID"></param>
        /// <param name="userData"></param>
        public void AddSessionUUID(string sessionUUID, SessionUserData userData)
        {
            if (sessionUUID == null)
            {
                Debug.Error("不能添加空SeesionId!");
                return;
            }

            SessionUUIDs.AddOrUpdate(sessionUUID, (k) => userData, (k, oldValue) => userData);
        }

        /// <summary>
        /// 移除本地会话UUID 断开连接时移除本地会话
        /// </summary>
        /// <param name="sessionUUID"></param>
        /// <param name="userData"></param>
        public void RemoveLocalUUID(string sessionUUID, SessionUserData userData)
        {
            //null 会报错并闪退
            if (sessionUUID == null)
            {
                Debug.Error("不能移除空SeesionId!");
                return;
            }

            if (SessionUUIDs.TryGetValue(sessionUUID, out SessionUserData data) && data == userData)
            {
                if (SessionUUIDs.TryRemove(sessionUUID, out data))
                {
                    if (data == userData)
                        Debug.Info($"移除本地会话UUID:{data.Userid}");
                    else
                        Debug.Error($"删错了!");
                }
            }
        }

        /// <summary>
        /// 检测一个 UUID 是否存在
        /// </summary>
        /// <returns></returns>
        public int CheckSessionUUID(string sessionUUID)
        {
            if (string.IsNullOrEmpty(sessionUUID))
            {
                Debug.Error("sessionUUID is null!");
                return -1;
            }

            if (SessionUUIDs.TryGetValue(sessionUUID, out SessionUserData data))
            {
                if (data == null)
                {
                    Debug.Info("data is null");
                }

                return data.Userid;
            }

            return SessionUUID.GetUserIdBySessionUUID(sessionUUID);
            // RedisValue value = redisManager.db.StringGet(GetSessionUUIDKey(sessionUUID));
            // if (value.HasValue && int.TryParse(value, out userid) && userid > 0)
            // {
            //     return userid;
            // }
            //
            // return -1;
        }

        public void Dispose()
        {
            MessageDispatcher.Instance.RemoveListener(MessageCode.RegisterSessionRequest, OnRegisterSession);
            MessageDispatcher.Instance.RemoveListener(MessageCode.UpdateSessionExpireTime, OnSessionExpireTime);
            MessageDispatcher.Instance.RemoveListener(MessageCode.GamePackTestRequest,OnGamePackTestRequest);
            if (_timer != null)
            {
                _timer.Dispose();
                _timer = null;
            }
        }

        /// <summary>
        /// 注册会话绑定的数量
        /// </summary>
        private readonly ConcurrentDictionary<string, int> SessionUUidBindCnt = new ConcurrentDictionary<string, int>();

        /// <summary>
        /// 会话的黑名单
        /// </summary>
        private readonly ConcurrentDictionary<string, long> SessionUUidBlackList =
            new ConcurrentDictionary<string, long>();

        /// <summary>
        /// 黑名单队列
        /// </summary>
        private readonly ConcurrentQueue<string> SessionUUidBlackListQueue = new ConcurrentQueue<string>();

        /// <summary>
        /// 10 秒钟最多绑定的次数
        /// </summary>
        private const int BindMaxCnt = 10;

        private const int CheckCnt = 10;

        /// <summary>
        /// 黑名单一个小时过期时间 , 测试就用一分钟
        /// </summary>
        private const int BlackListExpireTime = 60 * 60 * 1000;

        private void OnTimer(object state)
        {
            SessionUUidBindCnt.Clear();

            int cnt = SessionUUidBlackListQueue.Count;
            if (cnt > CheckCnt)
            {
                cnt = CheckCnt;
            }

            for (int i = 0; i < cnt; i++)
            {
                if (SessionUUidBlackListQueue.TryDequeue(out string uuid))
                {
                    if (SessionUUidBlackList.TryGetValue(uuid, out long time))
                    {
                        if (TimeInfo.Instance.FrameTime >= time)
                        {
                            SessionUUidBlackList.TryRemove(uuid, out time);
                            //Debug.Info($"移除黑名单:{uuid}");
                        }
                        else
                        {
                            SessionUUidBlackListQueue.Enqueue(uuid);
                        }
                    }
                }
            }
        }

        private async Task OnRegisterSession(GamePacket packet)
        {
            if (packet.MessageData is RegisterSessionRequest request)
            {
                if (!packet.Session.IsDisConnected)
                {
                    //黑名单用户
                    if (SessionUUidBlackList.ContainsKey(request.SessionUUID))
                    {
                        packet.Session.DisConnected();
                        return;
                    }

                    int cnt = SessionUUidBindCnt.AddOrUpdate(request.SessionUUID, (k) => 1,
                        (k, oldValue) => oldValue + 1);

                    if (cnt >= BindMaxCnt) //添加到黑名单
                    {
                        //Debug.Info($"添加到黑名单:{request.SessionUUID}");
                        SessionUUidBlackList.TryAdd(request.SessionUUID,
                            TimeInfo.Instance.FrameTime + BlackListExpireTime);
                        SessionUUidBlackListQueue.Enqueue(request.SessionUUID);
                        packet.Session.DisConnected();
                        return;
                    }

                    //已经绑定过了，来重复绑定
                    if (packet.Session.UserData != null)
                    {
                        //Debug.Info("绑定过了，断开链接!");
                        packet.Session.DisConnected();
                        return;
                    }

                    RegisterSessionResponse response = new RegisterSessionResponse();
                    response.SeqId = request.SeqId;
                    int userid = CheckSessionUUID(request.SessionUUID);
                    if (userid < 0)
                    {
                        response.ResultCode = MessageErrCode.SessionUuidExpired;
                    }
                    else if (userid != request.Userid)
                    {
                        response.ResultCode = MessageErrCode.UseridFail;
                    }
                    else
                    {
                        response.ResultCode = MessageErrCode.Success;
                    }

                    // if (userid == 15497437)
                    // {
                    //     NetManager.BlackList.Enqueue(packet.Data);
                    // }

                    Debug.Info($"注册SessionUUID:{request.SessionUUID}");
                    packet.Session.Send(response);

                    //绑定成功才添加绑定
                    if (response.ResultCode == MessageErrCode.Success)
                    {
                        packet.Session.BindUser(userid, request.SessionUUID, request.ClientVer, request.Plat,
                            request.DeviceInfo, false, request.StoreType);
                        UpdateExpiredTime(request.SessionUUID, userid);
                    }
                }
            }
        }

        private Task OnSessionExpireTime(GamePacket packet)
        {
            if (packet.MessageData is SessionUpdateExpireTime request)
            {
                if (packet.Session.UserData != null)
                {
                    UpdateExpiredTime(packet.Session.UserData.Uuid, packet.Session.UserData.Userid);
                }
            }
            
            return Task.CompletedTask;
        }

        private Task OnGamePackTestRequest(GamePacket packet)
        {
            if (packet.MessageData is GamePackTestRequest request)
            {
                GamePackTestResponse response = new GamePackTestResponse();
                response.Id = request.Id;
                packet.Session.Send(response);
            }

            return Task.CompletedTask;
        }
    }
}