using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Threading;
using ActorCore;
using GameMessage;
using MessagePack.Formatters;
using NetWorkMessage;
using Server.Core.Extend;
using Debug = MrWu.Debug.Debug;

namespace Server.Net
{
    /// <summary>
    /// 这个是路由过来的用户Session用来做对象池
    /// </summary>
    public class UserSession : IUserSession
    {
        /// <summary>
        /// 实例Id
        /// </summary>
        public long Id { get; private set; }

        /// <summary>
        /// 实例ID 如果Id 改变就不能用了，不再是之前的用户
        /// </summary>
        public long InstanceId { get; private set; }
        
        /// <summary>
        /// 登录验证码
        /// </summary>
        public string VerificationCode { get; set; }

        public string RemoteIPAddress { get; set; }

        public bool IsDisConnected { get; set; }

        public SessionUserData UserData { get; private set; }

        /// <summary>
        /// UserData 设置的时候需要锁
        /// </summary>
        public readonly object DisConnectLock = new object();
        
        // 收到链接包  ->  State = Using
        // 收到断开包 然后就回复断开成功的包 Session设置为断开

        //UserSession 被 ProxySession 包装使用， 代理持有UserSession 那么RefCount + 1 当ProxySession 销毁那么RefCount - 1

        public UserSession(long id, long instanceId)
        {
            this.Id = id;
            this.InstanceId = instanceId;
        }

        public void BindUser(int userid, string uuid, int clientVer, int plat, string deviceInfo,bool isNewUser,string storeType, bool reset = false)
        {
            if (IsDisConnected)
            {
                return;
            }

            if (!reset && UserData != null)
            {
                Debug.Error("该会话已经绑定了用户数据!");
                return;
            }

            ClearUserData();

            UserData = SessionUserData.Create(userid, uuid, clientVer, plat, deviceInfo,isNewUser, storeType);
            SessionUUIDManager.Instance.AddSessionUUID(uuid, UserData);
            GameNetDispatcher.Instance.Dispatch(GameNetMsgId.SessionBindUser, this);
        }

        private const int WarningCnt = 30 * 8 * 1024;
        
        /// <summary>
        /// 发送数据给客户端
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="messageType"></param>
        public void Send(byte[] buffer, Type messageType)
        {
            if (buffer == null)
            {
                Debug.Error("不能发送空数据!");
                return;
            }

            if (IsDisConnected)
            {
                Debug.Info($"链接并未在使用，不能发送! {Id} {this.InstanceId}");
                return;
            }

            //发送给客户端
            Server2ClientMessage message = Server2ClientMessage.Create();
            int len = PacketUtility.MessageParseDataV1(buffer, messageType, message.MemoryStream);
            byte[] data = new byte[len];
            int count = message.MemoryStream.Read(data, 0, len);
            if (count != len)
            {
                Debug.Error($"怎么会读取的数据跟要读取的长度不一致! {len} {count}");
            }
            
            if (buffer.Length > WarningCnt)
            {
                Debug.ImportantLog($"还有包大于240K? {messageType}");
            }

            message.Data = data;
            Send2Router(message);
        }

        /// <summary>
        /// 这个只能用来发送给客户端
        /// </summary>
        /// <param name="messageData"></param>
        public void Send(MessageData messageData)
        {
            if (messageData == null)
            {
                Debug.Error("不能发送空数据!");
                return;
            }

            if (IsDisConnected)
            {
                Debug.Info($"链接并未在使用，不能发送! - {Id} {this.InstanceId}");
                return;
            }

            //发送给客户端
            Server2ClientMessage message = Server2ClientMessage.Create();
            int len = PacketUtility.MessageParseDataV1(messageData, message.MemoryStream, message.CompressStream);
            byte[] data = new byte[len];
            int count = message.MemoryStream.Read(data, 0, len);
            if (count != len)
            {
                Debug.Error($"怎么会读取的数据跟要读取的长度不一致! {len} {count}");
            }

            //Debug.Info($"压缩标记:{data[0]},opcode:{BitConverter.ToInt32(data,1)}");
            message.Data = data;
            Send2Router(message);
        }

        private IActor MainActor;
        
        private IActor UerNetActor;

        private void GetActor()
        {
            if (MainActor == null)
            {
                MainActor = ActorManager.Instance.Get(ActorTypeId.Main);
            }

            if (UerNetActor == null)
            {
                UerNetActor = ActorManager.Instance.Get(ActorTypeId.UserNet);
            }
        }

        private void Send2Router(MessageObject message)
        {
            GetActor();

            UserNetSendMessage userNetSendMessage = new UserNetSendMessage();
            userNetSendMessage.Id = Id;
            userNetSendMessage.InstanceId = InstanceId;
            userNetSendMessage.MessageObject = message;
            MainActor.Send(UerNetActor.ActorId,userNetSendMessage);
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void DisConnected()
        {
            GetActor();
            
            Debug.Info("UserSession 强制断开链接");
            UserNetForceFinMessage userNetForceFinMessage = new UserNetForceFinMessage();
            userNetForceFinMessage.Id = Id;
            userNetForceFinMessage.InstanceId = InstanceId;
            userNetForceFinMessage.FinCode = 0;
            MainActor.Send(UerNetActor.ActorId,userNetForceFinMessage);
            
            //提前处理用户断开
            UserSessionManager.Instance.UserFin(this);
        }

        public void ClearUserData()
        {
            if (UserData != null)
            {
                Debug.Info($"注销绑定用户数据 Session:{Id} {UserData.Userid}");
                GameNetDispatcher.Instance.Dispatch(GameNetMsgId.SessionUnBindUser, this);
                SessionUUIDManager.Instance.RemoveLocalUUID(UserData.Uuid, UserData);
                UserData = null;
            }
        }

        /// <summary>
        /// 强制下线，强制下线也要等待1帧，因为线程不一样
        /// </summary>
        /// <param name="finCode"></param>
        /// <param name="userId"></param>
        public void ForceDiscConnect(int finCode,int userId)
        {
            GetActor();
            
            UserNetForceFinMessage userNetForceFinMessage = new UserNetForceFinMessage();
            userNetForceFinMessage.Id = Id;
            userNetForceFinMessage.InstanceId = InstanceId;
            userNetForceFinMessage.FinCode = finCode;
            MainActor.Send(UerNetActor.ActorId,userNetForceFinMessage);
            
            //提前处理用户断开
            UserSessionManager.Instance.UserFin(this);
        }
    }
}