using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Aliyun.Api.LogService.Infrastructure.Serialization.Protobuf;
using MrWu.Debug;
using Server;
using Server.Core;
using Server.Net;

namespace Server
{
    /// <summary>
    /// 这个管理了新旧Session
    /// </summary>
    public class UserSessionsManager : Singleton<UserSessionsManager>
    {
        /// <summary>
        /// 锁对象
        /// </summary>
        private readonly object Hashlock = new object();

        /// <summary>
        /// 所有用户的Session
        /// </summary>
        private readonly Dictionary<long, IUserSession> AllUserSessions = new Dictionary<long, IUserSession>();
        
        /// <summary>
        /// 用户对应的Session
        /// </summary>
        private readonly Dictionary<int, HashSet<IUserSession>> UserSession =
            new Dictionary<int, HashSet<IUserSession>>();

        public int Count
        {
            get
            {
                return _Count;
            }
        }

        private int _Count;

        /// <summary>
        /// 闲置池
        /// </summary>
        private readonly ConcurrentQueue<HashSet<IUserSession>> IdlePools = new ConcurrentQueue<HashSet<IUserSession>>();

        protected override void Awake()
        {
            GameNetDispatcher.Instance.AddListener(GameNetMsgId.SessionBindUser, OnSessionBindUser);
            GameNetDispatcher.Instance.AddListener(GameNetMsgId.SessionUnBindUser, OnSessionUnBindUser);
        }

        protected override void Destroy()
        {
            GameNetDispatcher.Instance.RemoveListener(GameNetMsgId.SessionBindUser, OnSessionBindUser);
            GameNetDispatcher.Instance.RemoveListener(GameNetMsgId.SessionUnBindUser, OnSessionUnBindUser);
        }

        private HashSet<IUserSession> GetHash()
        {
            if (IdlePools.TryDequeue(out HashSet<IUserSession> sessions))
            {
                return sessions;
            }

            return new HashSet<IUserSession>();
        }

        private void Release(HashSet<IUserSession> sessions)
        {
            if (sessions.Count > 0)
            {
                Debug.Error("还有数据怎么释放!");
                return;
            }
            
            IdlePools.Enqueue(sessions);
        }

        private void OnSessionBindUser(object param)
        {
            if (param is IUserSession session)
            {
                Debug.Info($"绑定用户事件!!! {session.Id}");
                if (session.UserData == null)
                {
                    Debug.Error("已经绑定了，用户数据怎么会是空！");
                    return;
                }

                int userid = session.UserData.Userid;
                lock (Hashlock)
                {
                    if (!UserSession.TryGetValue(userid, out HashSet<IUserSession> sessions))
                    {
                        sessions = GetHash();
                        UserSession[userid] = sessions;
                    }

                    sessions.Add(session);
                    AllUserSessions.Add(session.Id, session);
                }

                Interlocked.Increment(ref _Count);
                GameDispatcher.Instance.DispatchNextFrame(GameMsgId.UserReportOnline,userid);
            }
            else
            {
                Debug.Info("Session 类型不对!");
            }
        }

        private void OnSessionUnBindUser(object param)
        {
            if (param is IUserSession session)
            {
                if (session.UserData == null)
                {
                    Debug.Error("解除绑定还未完成，怎么用户数据会是空的!");
                    return;
                }

                int userid = session.UserData.Userid;
                lock (Hashlock)
                {
                    if (!UserSession.TryGetValue(userid, out HashSet<IUserSession> sessions))
                    {
                        Debug.Error("未获取到用户的Session!");
                        return;
                    }

                    sessions.Remove(session);
                    if (!AllUserSessions.Remove(session.Id))
                    {
                        Debug.Error("怎么会未移除!!!!!");
                    }

                    if (sessions.Count == 0)
                    {
                        UserSession.Remove(userid);
                        Release(sessions);
                    }
                }
                
                Interlocked.Decrement(ref _Count);
                GameDispatcher.Instance.DispatchNextFrame(GameMsgId.UserReportOffline,userid);
            }
        }

        public HashSet<IUserSession> GetUserSession(int userid)
        {
            HashSet<IUserSession> result = null;
            lock (Hashlock)
            {
                if (UserSession.TryGetValue(userid, out HashSet<IUserSession> sessions))
                {
                    result = new HashSet<IUserSession>(sessions);
                }
            }
            
            return result;
        }

        public IUserSession[] GetSessions()
        {
            lock (Hashlock)
            {
                return AllUserSessions.Values.ToArray();
            }
        }
    }
}