#if COMBAT_SERVER


using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO.Compression;
using System.Net;
using System.Net.Sockets;
using System.Net.Sockets.Kcp;
using System.Threading;
using Com.Fort23.Protocol.Protobuf;
using Fort23.UTool;
using Utility;

namespace Core.KCPTool
{
    public class KCPServer : IServer
    {
        private Socket socket;

        private Thread _udpClientThread;

        private byte[] buffer = new byte[2048];
        private ArraySegment<byte> ArraySegment;
        public Map<long, IServerConnection> KcpServerConnections = new Map<long, IServerConnection>();
        private List<CombatSynchronizeRequest> CombatSynchronizeRequests = new List<CombatSynchronizeRequest>();

        // private List<IServerConnection> awaitConnections = new List<IServerConnection>();

        private IServerManager iServerManager;


        private Queue<SendDataBuffer> _sendDataBuffers = new Queue<SendDataBuffer>();

        private long lasetSendTime = 0;

        public KCPServer(int port, IServerManager iServerManager)
        {
            this.iServerManager = iServerManager;
            LogTool.Log("创建UDP链接端口"+port+"__");
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            socket.Bind(new IPEndPoint(IPAddress.Any, port));
            ArraySegment = new ArraySegment<byte>(buffer);
            _udpClientThread = new Thread(BeginRecv);
            _udpClientThread.Start();
        }


        public void SocketSendTo(byte[] buffer, EndPoint endPoint)
        {
            // if (_sendDataBuffers.Count > 0)
            {
                // LogTool.Log("发送消息："+endPoint.GetHashCode());
                SendDataBuffer sendDataBuffer = new SendDataBuffer();
                sendDataBuffer.buffer = buffer;
                sendDataBuffer.endPoint = endPoint;
                _sendDataBuffers.Enqueue(sendDataBuffer);
            }
            // else
            // {
            // SocketSendToForBuffer(buffer, endPoint);

            // }
        }

        private void SocketSendToForBuffer(byte[] buffer, EndPoint endPoint)
        {
            socket.SendTo(buffer, endPoint);
        }
        private byte[] AssembleData(SendDataType sendDataType, byte[] buffer)
        {
            byte[] sendBuff = new byte[buffer.Length + 1];
            sendBuff[0] = (byte)sendDataType;
            Array.Copy(buffer, 0, sendBuff, 1, buffer.Length);
            return sendBuff;
        }
        public bool SendToPlayer(SendDataType sendDataType, CombatSynchronizeType combatSynchronizeType, byte[] buffer,
            long playerId)
        {
            if (KcpServerConnections.Count <= 0)
            {
                return true;
            }

            byte[] sendBuff = AssembleData(sendDataType, buffer);
            
            bool isOk = false;
            lock (KcpServerConnections)
            {
                for (KcpServerConnections.Begin(); KcpServerConnections.Next();)
                {
                    if (KcpServerConnections.Value.isConnected)
                    {
                        isOk = true;
                    }

                    if (playerId != -1 && KcpServerConnections.Value.playerId != playerId)
                    {
                        continue;
                    }


                    KcpServerConnections.Value.SendData(sendBuff, sendBuff.Length);
                }
            }

            return isOk;
        }


        public void AddCombatSynchronizeRequest(CombatSynchronizeRequest combatSynchronizeRequest)
        {
            lock (CombatSynchronizeRequests)
            {
                CombatSynchronizeRequests.Add(combatSynchronizeRequest);
            }
        }

        public CombatSynchronizeRequest[] GetCombatSynchronizeRequest(bool isClear)
        {
            if (CombatSynchronizeRequests.Count <= 0)
            {
                return null;
            }

            lock (CombatSynchronizeRequests)
            {
                CombatSynchronizeRequest[] allData = CombatSynchronizeRequests.ToArray();
                CombatSynchronizeRequests.Clear();
                return allData;
            }
        }

        public bool UpdateKCP()
        {
            bool isConnected = false;

            if (_sendDataBuffers.TryDequeue(out SendDataBuffer sendDataBuffer))
            {
                SocketSendToForBuffer(sendDataBuffer.buffer, sendDataBuffer.endPoint);
            }

            long currTime = DateTime.Now.Ticks;
            if (currTime - lasetSendTime > 50000000)
            {
                lasetSendTime = currTime;
                SendToPlayer(SendDataType.Heartbeat, CombatSynchronizeType.PrepareStart, new byte[1], -1);
            }

            lock (KcpServerConnections)
            {
                for (KcpServerConnections.Begin(); KcpServerConnections.Next();)
                {
                    if (KcpServerConnections.Value.isConnected)
                    {
                        isConnected = true;
                        KcpServerConnections.Value.Update();
                    }
                }
            }


            // lock (awaitConnections)
            // {
            //     for (int i = 0; i < awaitConnections.Count; i++)
            //     {
            //         awaitConnections[i].Update();
            //     }
            // }

            return isConnected;
        }

        public void RecvKCP()
        {
            lock (KcpServerConnections)
            {
                for (KcpServerConnections.Begin(); KcpServerConnections.Next();)
                {
                    if (KcpServerConnections.Value.isConnected)
                    {
                        KcpServerConnections.Value.ReceiveAsync();
                    }
                }
            }

            // lock (awaitConnections)
            // {
            //     for (int i = 0; i < awaitConnections.Count; i++)
            //     {
            //         awaitConnections[i].ReceiveAsync();
            //     }
            // }
        }

        private async void BeginRecv()
        {
            while (_udpClientThread != null)
            {
                EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0);
                try
                {
                    SocketReceiveFromResult receiveFromResult =
                        await socket.ReceiveFromAsync(ArraySegment, SocketFlags.None, newClientEP);

                    if (receiveFromResult.ReceivedBytes <= 0)
                    {
                        Thread.Sleep(10);
                        continue;
                    }


                    newClientEP = receiveFromResult.RemoteEndPoint;
                    byte[] data = new byte[receiveFromResult.ReceivedBytes];
                    Array.Copy(buffer, 0, data, 0, data.Length);
                    if (receiveFromResult.ReceivedBytes == 8) //链接到了
                    {
                        long playerId = SocketTool.ByteToLong(data);
                        CreateNewConnections(newClientEP, playerId);
                        continue;
                    }
                    else
                    {
                        IServerConnection kcpServerConnection = GetConnection(newClientEP.GetHashCode());
                        if (kcpServerConnection == null)
                        {
                            LogTool.Error("没有找到对应的客户端链接");
                        }
                        else
                        {
                            int ok = kcpServerConnection.Input(data);
                        }
                    }
                }
                catch (Exception e)
                {
                    // SocketException socketException = e as SocketException;
                    // if (socketException.ErrorCode == 10054)
                    // {
                    //     IServerConnection kcpServerConnection = GetConnection(newClientEP.GetHashCode());
                    //     if (kcpServerConnection != null) //链接已经断开
                    //     {
                    //         kcpServerConnection.isConnected = false;
                    //     }
                    // }
                    LogTool.Error(e);
                    Thread.Sleep(10);
                    // socket.Disconnect();
                }
            }
        }

        public void RemovePlayer(long playerId)
        {
            lock (KcpServerConnections)
            {
                KcpServerConnections.Remove(playerId);
            }
        }

        public IServerConnection GetConnection(long playerId)
        {
            lock (KcpServerConnections)
            {
                for (KcpServerConnections.Begin(); KcpServerConnections.Next();)
                {
                    if (playerId != -1 && KcpServerConnections.Value.playerId != playerId)
                    {
                        continue;
                    }

                    return KcpServerConnections.Value;
                }
            }

            return null;
        }

        public IServerConnection GetConnection(int connectionId)
        {
            lock (KcpServerConnections)
            {
                for (KcpServerConnections.Begin(); KcpServerConnections.Next();)
                {
                    if (connectionId != -1 && KcpServerConnections.Value.connectionID != connectionId)
                    {
                        continue;
                    }

                    return KcpServerConnections.Value;
                }
            }

            return null;
        }

        public void RemoveServerConnection(long playerId)
        {
            lock (KcpServerConnections)
            {
                if (KcpServerConnections.TryGetValue(playerId, out IServerConnection serverConnection))
                {
                    LogTool.Log("移除成功UDP" + playerId);
                    serverConnection.Dispose();
                    KcpServerConnections.Remove(playerId);
                }
            }
        }

        public void ConnectionUpdate()
        {
            if (socket != null)
            {
                try
                {
                    UpdateKCP();
                    RecvKCP();
                }
                catch (Exception e)
                {
                    LogTool.Exception(e);
                }
            }
        }  
        public async void SendGameFrame(int gameFrame, IServerConnection kcpServerConnection)
        {
            // if (gameFrame > 0)
            {
                LogTool.Log("重传数据开始" + gameFrame);
                int maxCount = iServerManager.GetSendBufferSize();
                for (int i = gameFrame; i < maxCount; i++)
                {
                    byte[] _sendBufferdata = iServerManager.GetSendBuffer(i);
                    if (_sendBufferdata != null)
                    {
                        _sendBufferdata = AssembleData(SendDataType.Data, _sendBufferdata);
                        kcpServerConnection.SendData(_sendBufferdata, _sendBufferdata.Length);
                        await System.Threading.Tasks.Task.Delay(1);
                    }
                }
            }
        }


        public void AddServerConnection(long playerId, int gameFrame, IServerConnection kcpServerConnection)
        {
            lock (KcpServerConnections)
            {
                RemoveServerConnection(playerId);
                iServerManager.AddServerConnection(this, kcpServerConnection);
                KcpServerConnections.Add(playerId, kcpServerConnection);
                LogTool.Log("握手成功UDP" + playerId);
                iServerManager.AddServerConnection(this, kcpServerConnection);
                byte[] data = SocketTool.LongToByte(playerId);
                SendToPlayer(SendDataType.ShakeHands, CombatSynchronizeType.PrepareStart, data, playerId);
            }

            // lock (awaitConnections)
            // {
            //     awaitConnections.Remove(kcpServerConnection);
            // }
        }

        public IServerConnection CreateNewConnections(EndPoint newClientEP, long playerId)
        {
            // int code = newClientEP.GetHashCode();

            KCPServerConnection kcpServerConnection = new KCPServerConnection(this, (IPEndPoint)newClientEP);
            kcpServerConnection.playerId = playerId;
            kcpServerConnection.connectionID = newClientEP.GetHashCode();
            LogTool.Log("创建新的链接UDP" + newClientEP);

            AddServerConnection(playerId, 0, kcpServerConnection);

            return kcpServerConnection;
        }

        public void Dispose()
        {
            _udpClientThread = null;
            socket?.Dispose();
            socket = null;
        }
    }
}
#endif