using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Sockets;
using System.Threading;

using Fort23.Core;
using Fort23.UTool;
using Task = System.Threading.Tasks.Task;

namespace Core.KCPTool
{
    public class TCPClient : IClientConnection
    {
        private byte[] buffData = new byte[6553];
        private Socket socket;

        public bool IsConnection { get; set; }
        public bool disconnect { get; set; }

        //记录半包数据
        private bool isBufferData;
        private byte[] lastBuffData;
        private int lastCount;

        private byte lastSendType;
        //数据结束

        //尾包
        private byte[] weiBaoBuffData;


        private Thread _udpClientThread;

        private IClient client;
        private long playerId;
        private bool isFinish;
        public bool isAwaitReConnect { get; set; }

        private bool isStartConnect;

        private CTask _cTask;
        public bool serveError;
       
        public TCPClient()
        {
        }

        public async Task Connect(IPEndPoint endPoint, long playerId, IClient client)
        {
            if (isStartConnect)
            {
                return;
            }

            serveError = false;
            _cTask = CTask.Create(false);
            isStartConnect = true;
            this.client = client;
            this.playerId = playerId;
            try
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                await socket.ConnectAsync(endPoint);
                isStartConnect = false;
            }
            catch (Exception e)
            {
                disconnect = true;
                LogTool.Exception(e);
                isStartConnect = false;
                serveError = true;
                return;
            }

            IsConnection = false;
            
            disconnect = false;
            _udpClientThread = new Thread(TheUpdate);
            _udpClientThread.Start();

            byte[] data = SocketTool.LongToByte(playerId);
            SendToServer(SendDataType.ShakeHands, data);
            await _cTask;
        }

        /// <summary>
        /// 重新链接
        /// </summary>
        public async void ReConnect(IPEndPoint endPoint, int gameFrame)
        {
            // if (isStartConnect)
            // {
            //     return;
            // }
            //
            // if (socket != null)
            // {
            //     socket.Dispose();
            //     socket = null;
            // }
            //
            // isStartConnect = true;
            // Thread.Sleep(10);
            // LogTool.Error("开始重新链接" + gameFrame);
            //
            // try
            // {
            //     socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //     await socket.ConnectAsync(endPoint);
            //     isStartConnect = false;
            // }
            // catch (Exception e)
            // {
            //     disconnect = true;
            //     LogTool.Exception(e);
            //     isStartConnect = false;
            //     return;
            // }
            //
            // disconnect = false;
            // _udpClientThread = new Thread(TheUpdate);
            // _udpClientThread.Start();
            // isAwaitReConnect = true;
            byte[] data = SocketTool.LongToByte(playerId);
            byte[] gameFrameByte = SocketTool.IntToByte(gameFrame);
            byte[] buffer = new byte[data.Length + gameFrameByte.Length];
            Array.Copy(data, 0, buffer, 0, data.Length);
            Array.Copy(gameFrameByte, 0, buffer, data.Length, gameFrameByte.Length);
            SendToServer(SendDataType.GetGameFrameByte, buffer);
        }


        private void TheUpdate()
        {
            while (socket != null)
            {
                try
                {
                    int count = socket.Receive(buffData);

                    if (count <= 0)
                    {
                        Thread.Sleep(1);
                        return;
                    }

                    // LogTool.Log("数据来了" + count);

                    try
                    {
                        int currCount = 0;
                        int startIndex = 0;

                        // bool isEnd = false;
                        while (currCount < count)
                        {
                            // isEnd = true;
                            byte[] data = null;
                            byte sendType = 0;
                            int cdShort = 0;

                            if (!isBufferData)
                            {
                                if (weiBaoBuffData != null)
                                {
                                    int maxCount = 6553500;
                                    if (count + weiBaoBuffData.Length > maxCount)
                                    {
                                        maxCount = count + weiBaoBuffData.Length;
                                    }

                                    // LogTool.Log("修复包太短__" + count + "___" + weiBaoBuffData.Length);
                                    byte[] newBuff = new byte[maxCount];
                                    Array.Copy(weiBaoBuffData, 0, newBuff, 0, weiBaoBuffData.Length);
                                    Array.Copy(buffData, 0, newBuff, weiBaoBuffData.Length, count);

                                    buffData = newBuff;
                                    count += weiBaoBuffData.Length;
                                    // LogTool.Log("修复包后太短__" + count);
                                    if (count < 6)
                                    {
                                        weiBaoBuffData = new byte[count];
                                        // LogTool.Log("包太短222__" + count);
                                        Array.Copy(buffData, currCount, weiBaoBuffData, 0, count);
                                        break;
                                    }
                                    else
                                    {
                                        weiBaoBuffData = null;
                                    }
                                }
                                else
                                {
                                    if (count - currCount < 5)
                                    {
                                        weiBaoBuffData = new byte[count];
                                        // LogTool.Log("包太短__" + count);
                                        Array.Copy(buffData, currCount, weiBaoBuffData, 0, count);
                                        break;
                                    }
                                }
                            }

                            if (!isBufferData)
                            {
                                sendType = buffData[currCount];
                                currCount++;
                                byte[] dataBuffLanl = new byte[4];
                                dataBuffLanl[0] = buffData[currCount];
                                currCount++;
                                dataBuffLanl[1] = buffData[currCount];
                                currCount++;
                                dataBuffLanl[2] = buffData[currCount];
                                currCount++;
                                dataBuffLanl[3] = buffData[currCount];
                                currCount++;
                                cdShort = (SocketTool.ByteToInt(dataBuffLanl));
                                // LogTool.Log("数据到来" + cdShort + "__" + count + "_" + sendType);
                                if ((currCount + cdShort) > count) //处理半包情况
                                {
                                    lastBuffData = new byte[count - currCount];
                                    lastCount = cdShort;
                                    lastSendType = sendType;
                                    Array.Copy(buffData, currCount, lastBuffData, 0, lastBuffData.Length);
                                    // LogTool.Log("数据只有一半" + count + "__" + currCount + "___" + cdShort);
                                    isBufferData = true;
                                    break;
                                }
                                else
                                {
                                    // LogTool.Log(currCount + "_收到长度：" + cdShort + "_Max" + count);
                                    data = new byte[cdShort];
                                    Array.Copy(buffData, currCount, data, 0, data.Length);
                                }
                            }
                            else if (lastCount - lastBuffData.Length > count)
                            {
                                // LogTool.Log("数据只有一半的一半" + count + "__" + lastCount + "___" + lastBuffData.Length);
                                byte[] newLastBuffData = new byte[lastBuffData.Length + count];
                                Array.Copy(lastBuffData, 0, newLastBuffData, 0, lastBuffData.Length);
                                Array.Copy(buffData, 0, newLastBuffData, lastBuffData.Length, count);
                                lastBuffData = newLastBuffData;
                                break;
                            }

                            else if (lastBuffData != null) //处理半包情况
                            {
                                isBufferData = false;
                                // LogTool.Log("修复半包" + lastCount + "__" + count + "___" +
                                //             (lastCount - lastBuffData.Length));
                                sendType = lastSendType;
                                data = new byte[lastCount];
                                cdShort = lastCount - lastBuffData.Length;
                                Array.Copy(lastBuffData, 0, data, 0, lastBuffData.Length);
                                Array.Copy(buffData, currCount, data, lastBuffData.Length, cdShort);
                            }
                            SendDataType sendDataType = (SendDataType)sendType;
                            if (sendDataType == SendDataType.Data)
                            {
                                using (MemoryStream compressedStream = new MemoryStream(data))
                                {
                                    using (MemoryStream decompressedStream = new MemoryStream())
                                    {
                                        using (GZipStream gzipStream =
                                               new GZipStream(compressedStream, CompressionMode.Decompress))
                                        {
                                            gzipStream.CopyTo(decompressedStream);
                                        }

                                        data = decompressedStream.ToArray();
                                    }
                                }
                            }
                            switch (sendDataType)
                            {
                                case SendDataType.ShakeHands:
                                    IsConnection = true;
                                    isAwaitReConnect = false;
                                    _cTask.SetResult();
                                    LogTool.Log("握手成功");
                                    break;
                                case SendDataType.Data:
                                    // CombatSynchronizeResponsePack combatSynchronizeResponse =
                                    //     CombatSynchronizeResponsePack.Parser.ParseFrom(data);
                                    // if (combatSynchronizeResponse == null)
                                    // {
                                    //     LogTool.Error("错误的实例化战斗" + data.Length);
                                    // }
                                    // else
                                    // {
                                    //     IsConnection = true;
                                    //     isAwaitReConnect = false;
                                    //     long t = System.DateTime.Now.Ticks;
                                    //     // LogTool.Log("收包延迟" + (t - combatSynchronizeResponse.Time) / 10000);
                                    //     // LogTool.Error("收到客户端消息" + combatSynchronizeRequest.CombatSynchronizeType);
                                    //     client.AddCombatSynchronizeResponse(combatSynchronizeResponse);
                                    // }

                                    break;
                            }


                            currCount += cdShort;
                            startIndex = currCount;
                        }
                    }
                    catch (Exception e)
                    {
                        LogTool.Exception(e);


                        // LogTool.Log("");
                    }
                }
                catch (Exception e)
                {
                    // LogTool.Log(e);
                    break;
                }

                Thread.Sleep(1);
            }

            IsConnection = false;
            disconnect = true;
            LogTool.Log("服务器执行完毕");
        }


        public void SendToServer(SendDataType sendDataType, byte[] buffer)
        {
            byte[] mdata = null;
            // LogTool.Log("回复消息" + buffer.Length);
            mdata = new byte[buffer.Length + 5];
            mdata[0] = (byte)sendDataType;
            byte[] zcd = SocketTool.IntToByte(buffer.Length);
            mdata[1] = zcd[0];
            mdata[2] = zcd[1];
            mdata[3] = zcd[2];
            mdata[4] = zcd[3];
            Array.Copy(buffer, 0, mdata, 5, buffer.Length);
            try
            {
                socket.Send(mdata);
            }
            catch (Exception e)
            {
                LogTool.Exception(e);
            }
        }

        public void Finish()
        {
            isFinish = true;
        }

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