using System;
using System.Net;
using System.IO;
using dotNetty_kcp;
using DotNetty.Buffers;
using UnityEngine;
using Guru;
using Dof;
namespace DofLibrary
{
    public class GameKcpClient : KcpListener
    {
        public Action OnConnected;
        public Action OnDisConnected;
        private KcpClient _kcpClient;
        public IMessageSender sender { get; private set; } = new MessageSender();
        private IMessageReceiver _receiver;
        private bool _running;
		private int? _timeoutMillis;
        public GameKcpClient(DotNetty.Unity.Level level = DotNetty.Unity.Level.ALL)
        {
            // 指定DotNetty日志的显示级别
            DotNetty.Unity.UnityLoggerFactory.Default.Level = level;
        }
        /// 
        /// 当前 Client 是否处于连接状态
        /// 
        public bool Running => _running;
        /// 
        /// 创建一个到 Dof GameServer 的连接
        /// 
        /// Dof GameServer 的地址,形如 xxx.xxx.xxx.xxx
        /// 房间ID
        /// 事件回调接口
        public async void Connect(string serverAddress, int port, IMessageReceiver receiver)
        {
            _receiver = receiver;
            _receiver.MessageSender = sender;
            _running = true;
            var channelConfig = new ChannelConfig();
            channelConfig.initNodelay(true, 40, 2, true);
            channelConfig.Sndwnd = 512;
            channelConfig.Rcvwnd = 512;
            channelConfig.Mtu = 512;
            channelConfig.FecDataShardCount = 10;
            channelConfig.FecParityShardCount = 3;
            channelConfig.AckNoDelay = true;
            channelConfig.Crc32Check = false;
            channelConfig.UseConvChannel = true;
            //channelConfig.Conv = UnityEngine.Random.Range(1, int.MaxValue);
			if(_timeoutMillis.HasValue)
            	channelConfig.TimeoutMillis = _timeoutMillis.Value;
            _kcpClient = new KcpClient();
            _kcpClient.init(channelConfig);
            var remoteAddress = new IPEndPoint(IPAddress.Parse(serverAddress), port);
            var task = _kcpClient.BindLocal();
            await task;
            var channel = task.Result;
            _kcpClient.connect(channel, remoteAddress, channelConfig, this);
        }
        private void ProcessMessage(ServerMessage serverMessage)
        {
            //Debug.Log("[ProcessMessage]");
            if (serverMessage.PlayerEntered != null)
            {
                //Debug.Log("[ProcessMessage]PlayerEntered");
                var cid = serverMessage.PlayerEntered.Cid;
                sender.Cid = cid;
                _receiver.OnPlayerEntered(cid);
            }
            else if (serverMessage.GameStart != null)
            {
                //Debug.Log("[ProcessMessage]GameStart");
                _receiver.OnGameStart(serverMessage.GameStart);
            }
            else if (serverMessage.LevelStart != null)
            {
                //Debug.Log("[ProcessMessage]LevelStart");
                _receiver.OnLevelStart(serverMessage.LevelStart);
            }
            else if (serverMessage.PointFound != null)
            {
                //Debug.Log("[ProcessMessage]PointFound");
                _receiver.OnPointFound(serverMessage.PointFound);
            }
            else if (serverMessage.GameFinish != null)
            {
                //Debug.Log("[ProcessMessage]GameFinish");
                _receiver.OnGameFinish(serverMessage.GameFinish);
            }
            else if (serverMessage.Heartbeat != null)
            {
                //Debug.Log("[ProcessMessage]Heartbeat");
                _receiver.OnHeartbeat(serverMessage.Heartbeat);
            }
        }
        /// 
        /// kcp 连接后的回调函数
        /// 
        /// kcp连接
        public void onConnected(Ukcp ukcp)
        {
            Debug.Log($"[GameKcpClient]onConnected: conv = {ukcp.getConv()}");
            sender.Client = ukcp;
            if (OnConnected != null)
            {
                LoomUtil.QueueOnMainThread(() =>
                {
                    OnConnected.Invoke();
                });
            }
        }
        /// 
        /// kcp 接收到消息的回调函数
        /// 
        /// 接收到的消息buffer
        /// kcp连接
        public void handleReceive(IByteBuffer byteBuf, Ukcp ukcp)
        {
            Debug.Log("[GameKcpClient]handleReceive");
            var ms = new MemoryStream(1024 * 1024 * 1);
            var data_len = byteBuf.ReadableBytes;
            byteBuf.ReadBytes(ms, data_len);
            var msg = ProtobufHelper.FromBytes(typeof(ServerMessage), ms.GetBuffer(), 0, data_len);
            if (msg is ServerMessage server_msg)
            {
                LoomUtil.QueueOnMainThread(() =>
                {
                    ProcessMessage(server_msg);
                });
            }
            else
            {
                Debug.LogError("[GameKcpClient]handleReceive: Fail to Deserialize ServerMessage");
            }
        }
        /// 
        /// kcp 连接或者接收消息出错的回调函数
        /// 
        /// 异常
        /// kcp连接
        public void handleException(Exception ex, Ukcp ukcp)
        {
            Debug.LogError($"[GameKcpClient]handleException: {ex}");
        }
        /// 
        /// kcp 连接关闭时的回调函数
        /// 
        /// kcp连接
        public void handleClose(Ukcp ukcp)
        {
            Debug.Log("[GameKcpClient]: Connection closed");
            if (OnDisConnected != null)
            {
                LoomUtil.QueueOnMainThread(() =>
                {
                    OnDisConnected.Invoke();
                });
            }
        }
		public void setTimeoutMillis(int timeoutMillis)
		{
			_timeoutMillis = timeoutMillis;
		}
        /// 
        /// 关闭 Client,应该在游戏结束时调用
        /// 
        public void Close()
        {
            _kcpClient?.stop();
            _running = false;
        }
    }
}