using System;
using System.Collections.Concurrent;
using System.Configuration;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using GameData;
using GameData;
using GameMessage;
using MessagePack;
using MrWu.Debug;
using MrWu.RabbitMQ;
using Newtonsoft.Json;
using Server.Core;
using Server.Data;
using Server.Data.Module;
using Server.MQ;
using Server.Net;
using Server.Pack;
using UnityGame;

namespace Server
{
    public class GameMessageManager : SingleInstance<GameMessageManager>, IDisposable
    {
        private bool isStart = false;

        /// <summary>
        /// 等待处理的消息
        /// </summary>
        private readonly ConcurrentQueue<PackGroup> waitHandleMsg = new ConcurrentQueue<PackGroup>();

        private readonly ConcurrentQueue<PackGroup> idlePackGroup = new ConcurrentQueue<PackGroup>();

        private ModuleType _moduleType;

        private int _moduleId;

        private int Port;
        
        public void Start(ModuleType moduleType,int port,int gameid)
        {
            if (isStart)
            {
                return;
            }

            this._moduleType = moduleType;
            this._moduleId = (int)moduleType;

            if (port > 0)
            {
                GameNetManager.Instance.ConnectedEvt += OnConnected;
                GameNetManager.Instance.DisConnectedEvt += OnDisconnected;
                GameNetManager.Instance.ReceiveEvt += OnReceived;
                GameNetManager.Instance.Start($"/serid{gameid}/", port);
                Port = port;
            }
            
            MessageDispatcher.Instance.AddListener(MessageCode.ClientPackRequest, OnClientPackRequest);
            Debug.Info($"启动监听:{port} {gameid}");
            isStart = true;
        }

        public void Update()
        {
            if (isStart)
            {
                if (Port > 0)
                {
                    GameNetManager.Instance.Update();
                }

                while (true)
                {
                    if (waitHandleMsg.TryDequeue(out PackGroup packGroup))
                    {
                        OnReceived(packGroup.Session,packGroup.HeadWrapper);
                        packGroup.HeadWrapper.Dispose();
                        ReleasePackGroup(packGroup);
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }

        public void Dispose()
        {
            if (isStart)
            {
                if (Port > 0)
                {
                    GameNetManager.Instance.ConnectedEvt -= OnConnected;
                    GameNetManager.Instance.DisConnectedEvt -= OnDisconnected;
                    GameNetManager.Instance.ReceiveEvt -= OnReceived;
                    GameNetManager.Instance.Dispose();
                }
               
                isStart = false;
            }
            
        }

        private void OnConnected(Session session)
        {
            PackHead head = PackHead.Create();
            head.packlx = ServerPackAgreement.connecOk;
            session.SendPack(head);
            head.Dispose();
        }

        private void OnDisconnected(Session session)
        {
            if (session.UserData == null)
            {
                return;
            }
            
            int userid = session.UserData.Userid;
            if (!GameSessionManager.Instance.RemovePlayerSession(userid, session)) {
                Debug.Error("玩家未移除链接!");
                return;
            }
            
            GameDispatcher.Instance.DispatchNextFrame(GameMsgId.DisConnected, userid);
        }

        private void OnReceived(IUserSession session, byte[] data)
        {
            int packlx = 0;
            try
            {
                string jsonData = Encoding.UTF8.GetString(data);
                HeadWrapper headWrapper = JsonPack.GetData<HeadWrapper>(jsonData);
                headWrapper.head.ip = session.RemoteIPAddress.ToString();
                headWrapper.IsText = true;

                if (headWrapper == null || headWrapper.head == null)
                {
                    Debug.Error($"解包失败,收到的消息:{jsonData}");
                    session.DisConnected();
                    return;
                }

                if (session.UserData != null)
                {
                    headWrapper.head.userid = session.UserData.Userid;
                }
                
                //输出毫秒值
                //Debug.Info($"收包线程:{Thread.CurrentThread.ManagedThreadId},{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
                waitHandleMsg.Enqueue(GetPackGroup(session, headWrapper));
            }
            catch (Exception e)
            {
                Debug.Error($"收包处理错误 packlx:{packlx} {e.Message}");
            }
        }

        private Task OnClientPackRequest(GamePacket gamePacket)
        {
            //Debug.Log("收到客户端来的包!");
            if (gamePacket.MessageData is ClientPackRequest request)
            {
                Debug.Log($"head:{request.Head.Length}");
                PackHead head = MessagePackSerializer.Deserialize<PackHead>(request.Head);
                
                head.ip = gamePacket.Session.RemoteIPAddress.ToString();
                if (gamePacket.Session.UserData != null)
                {
                    head.userid = gamePacket.Session.UserData.Userid;
                    Debug.Log($"取服务器中绑定的数据:{head.userid}");
                    head.plat = gamePacket.Session.UserData.Plat.ToString();
                    head.platValue = gamePacket.Session.UserData.Plat;
                    head.clientVer = gamePacket.Session.UserData.ClientVer;
                }
                else
                {
                    Debug.Log($"包内带的数据:{head.userid}");
                }

                HeadWrapper headWrapper = HeadWrapper.Create(head, request.Data);
                if (gamePacket.Session is ProxySession temp)
                {
                    waitHandleMsg.Enqueue(GetPackGroup(temp.SourceSession, headWrapper));
                }
            }

            return Task.CompletedTask;
        }
        
        private void OnReceived(IUserSession session, HeadWrapper headWrapper)
        {
            PackHead head = headWrapper.head;
            if (head.Util == null)
            {
                head.Util = GameBase.instance.myUtil;
            }

            switch (head.packlx)
            {
                case ServerPackAgreement.SocketPing: //测试用的
                    if (session.UserData != null)
                        Debug.Log("收到测试包了!");

                    session.SendPack(head,headWrapper.jsonMessage);
                    break;


                case ServerPackAgreement.GetPlayerGameInfo: //获取玩家所有的游戏信息
                    GetPlayerGameInfo(head, session);
                    break;

                case ServerPackAgreement.registeredSocket: //登录在本Socket中注册玩家
                    Debug.Log("来包绑定Socket!");
                    AddUser(head, (headWrapper.IsBinary ? headWrapper.Data2Text : headWrapper.jsonMessage), session);
                    break;

                case ServerPackAgreement.closeSocket: //连接断开
                    session.DisConnected();
                    break;

                case ServerPackAgreement.PushLogin: //强行登录
                    break;

                case ServerPackAgreement.Heartbeat: //处理心跳
                    // if (head.otherInt != null)
                    // {
                    //     Debug.Info($"处理心跳:{head.otherInt[0]} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");
                    // }
                    // else
                    // {
                    //     Debug.Info("心跳包??");
                    // }

                    DoHeart(head,session);
                    break;

                //					case GamePackAgreement.EveryGame://任意游戏模块处理
                //						deliveyGame_(head,messagedata);
                //						break;

                case GamePackAgreement.DoMessgae: //处理消息转发
                    break;

                case GamePackAgreement.UpdateSocketCryptKey: //应客户端要求更新加密密钥
                    
                    break;

                default: //发送给指定游戏模块
                    if (session.UserData == null)
                    {
                        Debug.ImportantLog($"收到未知来历的包裹:{head.packlx}");
                        return;
                    }
                    
                    Debug.Log("收到包裹:" + head.packlx);
                    //665000
                    if (head.packlx >= Game.Data.GameData.PackCardInt)
                    {
                        if ((head.packlx / Game.Data.GameData.PackCardInt) != _moduleId)
                        {
                            Debug.Warning("收到未解析的包裹!" + head.packlx);
                            return;
                        }
                        head.packlx = head.packlx % Game.Data.GameData.PackCardInt;
                    }
                    GamePack gamePack = null;
                    if (headWrapper.IsText)
                    {
                        gamePack = GamePack.Create(head, headWrapper.jsonMessage);
                    }
                    else
                    {
                        gamePack = GamePack.Create(head, headWrapper.Data);
                    }
                    GameManager.instance.DoPack(gamePack);
                    break;
            }
        }
        
        /// <summary>
        /// 处理心跳包
        /// </summary>
        private void DoHeart(PackHead head, IUserSession session) {
            if (session.UserData == null) {
                return;
            }
            
            session.SendPack(head);
        }
        
        private void AddUser(PackHead head, string jsonMessage, IUserSession session)
        {
            if (head.userid <= 0)
            {
                Debug.Log("userid is zero");
                return;
            }
            
            //有uuid 处理uuid 没有 uuid 创建 uuid
            BindSocket bindSocket = null;
            if (!string.IsNullOrEmpty(jsonMessage))
            {
                bindSocket = JsonPack.GetData<BindSocket>(jsonMessage);
            }
            else
            {
                // 先临时生成uuid，后续升级可以把这个删除,没有提供uuid的包，提示升级
                bindSocket = new BindSocket()
                {
                    SeesionUUID = SessionUUIDManager.Instance.CreateSessionUUID(head.userid)
                };
            }

            int userid = SessionUUIDManager.Instance.CheckSessionUUID(bindSocket.SeesionUUID);
        
            if (userid != head.userid)
            {
                //登录过期，请重新登录
                SendLoginResult(head, -1, session);
                session.DisConnected();
                return;
            }

            IUserSession beforeSession = GameSessionManager.Instance.FindSession(userid);

            if (beforeSession != null) { //这个玩家已经有链接了

                if (beforeSession == session)
                {
                    Debug.Warning($"同一个链接发送过来的注册,已经注册过了! {userid}");
                    return;
                }
                
                Debug.Warning("--已经有这个链接了!" + head.userid + "," + beforeSession.IsDisConnected);
                if (beforeSession.IsDisConnected)
                {
                    Debug.Error($"已经有这个连接了:{head.userid}");
                }
                else
                {
                    if(beforeSession.UserData != null)
                    {
                        Debug.Error($"--- ForceDisConnected UserId:{userid} beforeSession:{beforeSession.RemoteIPAddress} session:{session.RemoteIPAddress} {beforeSession.GetType().FullName} DeveiceInfoId:{beforeSession.UserData.DeviceInfo} {bindSocket.DeviceInfoId}");
                    }
                    else
                    {
                        Debug.Error($"beforeSession UserData is null userid:{userid}");
                    }
                }
                
                //断线，但是有可能还未发完包
                // 先把断线逻辑处理完
                if (beforeSession is Session)
                {
                    SendLoginResult(head, -4, beforeSession);
                    GameNetManager.Instance.ForceDisconnected(beforeSession.Id);
                }
                else if (beforeSession is UserSession userSession)
                {
                    userSession.ForceDiscConnect(ServerFin.FinCode_RemoteLogin,userid);
                    Debug.ImportantLog($"上一个强制下线:{userSession.Id} {ServerFin.FinCode_RemoteLogin}");
                    //要处理下线逻辑
                }
                
                SendLoginResult(head, -9, session);
                
            } else
            {
                BindUser(session, userid, bindSocket, head);
            }
        }

        private void BindUser(IUserSession session,int userid, BindSocket bindSocket,PackHead head)
        {
            object lockObj = null;
            if (session is Session userSession)
            {
                lockObj = userSession.DisConnectLock;
            }
            else if (session is UserSession _userSession)
            {
                lockObj = new object();
            }

            lock (lockObj)
            {
                if (session.IsDisConnected)
                {
                    Debug.Error("玩家链接已经断开，不处理!");
                    return;
                }
                    
                session.BindUser(userid, bindSocket.SeesionUUID, head.clientVer,head.platValue,bindSocket.DeviceInfoId,false,bindSocket.StoreType);
                //这个玩家正常
                if (GameSessionManager.Instance.AddPlayerSession(head.userid, session))
                {
                    Debug.Info("绑定完成!");
                    SendLoginResult(head, 1, session);
                }
                else
                {
                    Debug.Error("玩家没有添加成功!");
                }
            }
        }

        /// <summary>
        /// 发送登录结果包
        /// </summary>
        /// <param name="head"></param>
        /// <param name="style"></param>
        /// <param name="session"></param>
        private void SendLoginResult(PackHead head, int style, IUserSession session, playerData pl = null) {
            head.packlx = GamePackAgreement.registeredSocket;

            SocketRegResult result = SocketRegResult.GetSocketRegResult(style);
            result.pldata = pl;
            session.SendPack(head, result);
        }
        
        /// <summary>
        /// 获取玩家所在的游戏信息
        /// </summary>
        /// <param name="head">包头</param>
        /// <param name="session">链接</param>
        private async void GetPlayerGameInfo(PackHead head, IUserSession session) {
            if (session.UserData == null) {
                Debug.Error("897c570e-6571-4958-adaa-e8f2e48f2db1:用户未链接完成!" + head.userid);
                return;
            }

            int clickGame = 0;
            if (head.otherInt != null && head.otherInt.Length > 0) {
                clickGame = head.otherInt[0];
            }
            
            PlayerLockInfo pllockinfo = await PlayerFun.GetPlayerLockInfoAsync(head.userid);

            head = PackHead.Create(ServerPackAgreement.InGameInfo);
            PlayerGameInfo pgi = null;

            //这个包是给朋友房用的，朋友房先查询是不是在游戏中，如果在就提示玩家,不在才让进朋友房
            if (pllockinfo != null) {
                pgi = new PlayerGameInfo(pllockinfo.gameid, pllockinfo.isFriend ? 1 : 0,1, clickGame);
            } else {
                pgi = new PlayerGameInfo(0, 0, 2, clickGame);
            }

            session.SendPack(head,pgi);
            head.Dispose();
        }
        
        private PackGroup GetPackGroup(IUserSession session,HeadWrapper headWrapper)
        {
            if (!idlePackGroup.TryDequeue(out PackGroup packGroup))
            {
                packGroup = new PackGroup();
            }
            packGroup.Session = session;
            packGroup.HeadWrapper = headWrapper;
            return packGroup;
        }

        private void ReleasePackGroup(PackGroup packGroup)
        {
            packGroup.Clear();
            idlePackGroup.Enqueue(packGroup);
        }

        public bool ForceOffLine(int userid,bool isSendPack)
        {
            IUserSession session = GameSessionManager.Instance.FindSession(userid);
            if (session == null)
            {
                Debug.Info("没找到玩家!" + userid);
                return false;
            }
            else
            {
                if (isSendPack)
                {
                    PackHead head = PackHead.Create(ServerPackAgreement.registeredSocket);
                    SocketRegResult plr = SocketRegResult.GetSocketRegResult(-4);
                    session.SendPack(head,plr);
                    head.Dispose();
                }
                
                session.DisConnected();
                return true;
            }
        }

        private class PackGroup
        {
            public IUserSession Session;

            public HeadWrapper HeadWrapper;

            public void Clear()
            {
                Session = null;
                HeadWrapper = null;
            }
        }
        
    }

    public static class SessionExtend
    {
        public static void SendPack(this IUserSession session, PackHead head, byte[] data)
        {
            if (session == null)
            {
                return;
            }

            HeadWrapper headWrapper = HeadWrapper.Create(head, data);
            session.SendPack(headWrapper);
            headWrapper.Dispose();
        }
        
        public static void SendPack(this IUserSession session, PackHead head, object data) {

            if (session == null)
            {
                return;
            }
            
            session.SendPack(head, data == null ? null : JsonPack.GetJson(data));
        }
        
        public static void SendPack(this IUserSession session, PackHead head, string jsonMessage = null)
        {
            if (session == null)
            {
                return;
            }

            //todo 这里可以用引用池
            HeadWrapper headWrapper = HeadWrapper.Create(head, jsonMessage);
            session.SendPack(headWrapper);
            headWrapper.Dispose();
        }

        public static void SendPack(this IUserSession session, HeadWrapper value)
        {
            if (session == null)
            {
                return;
            }

            if (session.IsDisConnected)
            {
                return;
            }
            
            //Debug.Info($"发送包数据:{value.head.packlx}");
            //这里只能按字符串发送，TMD。之前的设计害死人
            if (session is Session oldSession)
            {
                string jsonValue = JsonPack.GetJson(value);
                oldSession.Send(jsonValue);
            }
            else
            {
                Debug.Log($"发包给客户端: 2122");
                byte[] data = value.Data;
                if (value.jsonMessage != null)
                {
                    data = Encoding.UTF8.GetBytes(value.jsonMessage);
                }

                if (data != null)
                {
                    Debug.Log($"发送的数据:{data.Length}");
                }
                
                ClientPackResponse response =
                    ClientPackResponse.Create(MessagePackSerializer.Serialize(value.head), data);
                session.Send(response);
                response.Dispose();
            }
        }
    }
}