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 NetManager : SingleInstance<NetManager>, 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;
        
        /// <summary>
        /// 启动网络
        /// </summary>
        public void Start(string webPath,int webPort)
        {
            if (!string.IsNullOrEmpty(webPath) && webPort > 0)
            {
                //webSocket 服务 启动
                WChannel.OnConnectedEvt += WConnected;
                WChannel.OnDisconnectedEvt += WDisconnected;
                WChannel.OnReceivedEvt += WReceived;
                WChannel.OnErrorEvt += WError;
                _webSocketServer = new WebSocketServer(webPort);
                _webSocketServer.AddWebSocketService<WChannel>(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(WChannel 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);
            }
        }

        private void WDisconnected(WChannel channel)
        {
            long sessionId = channel.SessionId;
            if (sessionDic.TryRemove(sessionId,out Session session))
            {
                session.OnDisConnected();
            }
            else
            {
                Debug.Error("webSocket断开连接，竟然未找到 session!");
            }
        }
        
        private void WReceived(WChannel 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(WChannel channel, Exception e)
        {
            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
            {
                //opcode
                int opcode = BitConverter.ToInt32(data, offset);
                offset += 4;
                //4个备份字节
                offset += 4;
                //后面是包内容
                //Debug.Info($"接收到数据{opcode},{data.Length}");
                Type messageType = MessageManager.GetType(opcode);
                MessageData messageData = (MessageData)MessagePackSerializer.Deserialize(messageType,
                    new ReadOnlyMemory<byte>(data, offset, data.Length - offset));
                MessageDispatcher.Instance.AddPack(GamePacket.Create(opcode, messageData, session));

                Interlocked.Exchange(ref session.ReadWriteTime, TimeInfo.Instance.FrameTime);
                Interlocked.Add(ref ReceiveCount, 1);
            }
            catch (Exception e)
            {
                Debug.Error($"收包解析报错:{e.Message}");
            }
        }

        public void Update()
        {
            // 清理超时，和失效的链接
            long timeNow = TimeInfo.Instance.FrameTime;
            const int MaxCheckNum = 10;
            int n = 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;
                }
            }
        }
    }
}