using System;
using MrWu.Debug;
using Server;
using WebSocketSharp.Server;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using GameMessage;
using MessagePack;
using MrWu;
using Server.Core;

namespace Server.Net
{
    public class GameNetManager : SingleInstance<GameNetManager>, IDisposable
    {
        public static bool IsStart
        {
            get;
            private set;
        }

        public bool IsDispose { get; private set; }

        private WebSocketServer _webSocketServer;

        /// <summary>
        /// 会话集合
        /// </summary>
        private ConcurrentDictionary<long, Session> sessionDic = new ConcurrentDictionary<long, Session>();

        /// <summary>
        /// SessionIds 队列
        /// </summary>
        private readonly ConcurrentQueue<long> sessionIds = new ConcurrentQueue<long>();

        /// <summary>
        /// 当前的链接数
        /// </summary>
        public int ConnectCount
        {
            get { return sessionDic.Count; }
        }

        /// <summary>
        /// 当前接收的数量
        /// </summary>
        public long ReceiveCount;

        public const int MaxMessageSize = 1024 * 1024;

        public event Action<Session> ConnectedEvt;

        public event Action<Session> DisConnectedEvt;

        public event Action<Session, byte[]> ReceiveEvt;

        /// <summary>
        /// 启动网络
        /// </summary>
        public void Start(string webPath, int webPort)
        {
            if (!string.IsNullOrEmpty(webPath) && webPort > 0)
            {
                //webSocket 服务 启动
                GameWChannel.OnConnectedEvt += WConnected;
                GameWChannel.OnDisconnectedEvt += WDisconnected;
                GameWChannel.OnReceivedEvt += WReceived;
                GameWChannel.OnErrorEvt += WError;
                _webSocketServer = new WebSocketServer(webPort);
                _webSocketServer.AddWebSocketService<GameWChannel>(webPath);
                _webSocketServer.Start();
                //webSocket 服务 结束

                IsStart = true;
                SessionUUIDManager.Instance.Init();
            }
        }

        public void Dispose()
        {
            IsDispose = true;
            WebSocketStop();
        }

        private void WebSocketStop()
        {
            Task.Factory.StartNew(() => { _webSocketServer?.Stop(); });
        }

        #region WebSocket 事件

        private void WConnected(GameWChannel channel)
        {
            Session session = new Session(channel);
            Interlocked.Exchange(ref session.ReadWriteTime, TimeInfo.Instance.FrameTime);
            long id = session.Id;
            channel.SessionId = id;
            if (!sessionDic.TryAdd(id, session))
            {
                Debug.Error("添加 webSocket 链接到 字典失败!!!");
            }
            else
            {
                sessionIds.Enqueue(id);
                try
                {
                    ConnectedEvt?.Invoke(session);
                }
                catch (Exception e)
                {
                    Debug.Error($"链接成功事件执行报错:{e.Message}");
                }
            }
        }

        private void WDisconnected(GameWChannel channel)
        {
            long sessionId = channel.SessionId;
            if (sessionDic.TryRemove(sessionId, out Session session))
            {
                lock (session.DisConnectLock)
                {
                    try
                    {
                        DisConnectedEvt?.Invoke(session);
                    }
                    catch (Exception e)
                    {
                        Debug.Error($"断开连接事件执行报错:{e.Message}");
                    }

                    session.OnDisConnected();
                }
            }
            else
            {
                if (!_forceDisConnectedSessionIds.TryRemove(sessionId, out Session _))
                {
                    Debug.Error("webSocket断开连接，竟然未找到 session");
                }
            }
        }

        private ConcurrentDictionary<long,Session> _forceDisConnectedSessionIds = new ConcurrentDictionary<long, Session>();
        
        public void ForceDisconnected(long sessionId)
        {
            if (sessionDic.TryRemove(sessionId, out Session session))
            {
                if (!_forceDisConnectedSessionIds.TryAdd(sessionId, session))
                {
                    Debug.Error("不存在说添加不进去吧？？？");
                }

                lock (session.DisConnectLock)
                {
                    try
                    {
                        DisConnectedEvt?.Invoke(session);
                    }
                    catch (Exception e)
                    {
                        Debug.Error($"断开连接事件执行报错:{e.Message}");
                    }

                    session.OnDisConnected();
                }
            }
            else
            {
                Debug.Error($"ForceDisconnected 断开连接，竟然未找到 session {sessionId}");
            }
        }
        
        private void WReceived(GameWChannel channel, byte[] data)
        {
            long sessionId = channel.SessionId;
            if (sessionDic.TryGetValue(sessionId, out Session session))
            {
                //因为没去掉头
                Received(session, data, 0);
            }
            else
            {
                Debug.Error("接收到webSocket包，未找到会话!");
            }
        }

        private void WError(GameWChannel channel, Exception e)
        {
            if (e == null)
            {
                Debug.Error($"Web Socket Error: e is null!");
            }else
                Debug.Error("Web Socket Error:" + e.Message);
        }

        #endregion

        /// <summary>
        /// 接受到数据
        /// </summary>
        /// <param name="session"></param>
        /// <param name="data"></param>
        /// <param name="offset"></param>
        private void Received(Session session, byte[] data, int offset)
        {
            try
            {
                ReceiveEvt?.Invoke(session, data);
            }
            catch (Exception e)
            {
                Debug.Error($"收包解析报错:{e.Message}");
            }
        }

        public void Update()
        {
            // 清理超时，和失效的链接
            long timeNow = TimeInfo.Instance.FrameTime;
            const int MaxCheckNum = 10;
            int n = this.sessionIds.Count;
            if (n > MaxCheckNum)
            {
                n = MaxCheckNum;
            }

            for (int i = 0; i < n; i++)
            {
                if (this.sessionIds.TryDequeue(out long sessionId))
                {
                    if (this.sessionDic.TryGetValue(sessionId, out Session session))
                    {
                        if (timeNow - session.ReadWriteTime > 20 * 1000)
                        {
                            Debug.Info($"超时断线! {session.IsDisConnected}");
                            //var key = Debug.StartTiming();
                            session.DisConnected();
                            // double runtime = Debug.GetRunTime(key);
                            // if (runtime > 20)
                            // {
                            //     Debug.Warning($"NetManager runtime:{runtime},n:{n}");
                            // }
                            //超时断线
                            continue;
                        }

                        this.sessionIds.Enqueue(sessionId);
                    }
                }
                else
                {
                    break;
                }
            }
        }
    }
}