using System;
using System.Buffers;
using System.Net;
using System.Net.Sockets;
using System.Net.Sockets.Kcp;
using System.Threading;
using System.Threading.Tasks;
using Fort23.UTool;


public class UDPForKCP : IKcpCallback, IDisposable
{
    private UdpClient client;

    private Thread _udpClientThread;

    public int myPort;
    public int ycPort;
    public bool isLockSend;
    public object LockObject;

    public bool isConnect;
    // public int PiPeiPort;

    public UDPForKCP()
    {
    }

    public UDPForKCP(int port, uint conv) : this(port, null, conv)
    {
    }

    public UDPForKCP(int port, IPEndPoint endPoint, uint conv)
    {
        myPort = port;
        // LogTool.Log("链接端口"+port+"__"+endPoint.Address);
        client = new UdpClient(port);
        if (endPoint != null)
        {
            client.Connect(endPoint);
            isConnect = true;
        }


        _kcp = new SimpleSegManager.Kcp(conv, this);
        kcp.NoDelay(1, 40, 2, 0);
        this.EndPoint = endPoint;


        _udpClientThread = new Thread(BeginRecv);
        _udpClientThread.Start();
    }



    public SimpleSegManager.Kcp kcp
    {
        get { return _kcp; }
    }

    public IPEndPoint EndPoint { get; set; }

    private SimpleSegManager.Kcp _kcp;

    public void Output(IMemoryOwner<byte> buffer, int avalidLength)
    {
        if (EndPoint == null)
        {
            return;
        }


        var s = buffer.Memory.Span.Slice(0, avalidLength).ToArray();
        if (isLockSend)
        {
            lock (LockObject)
            {
                client.Send(s, s.Length, EndPoint);
                // Debug.Log("发送"+client.Client.RemoteEndPoint);
                buffer.Dispose();
            }
        }
        else
        {
            // Debug.Log("发送"+client.Client.RemoteEndPoint!=null);
            if (isConnect)
            {
                client.Send(s, s.Length);
            }
            else
            {
                client.Send(s, s.Length, EndPoint);
            }


            buffer.Dispose();
        }
    }

    public async void SendAsync(byte[] datagram, int bytes)
    {
        int c = kcp.Send(datagram.AsSpan().Slice(0, bytes));
        // LogTool.Error("发送错误" + c);
    }

    public byte[] ReceiveAsync()
    {
        var (buffer, avalidLength) = kcp.TryRecv();
        while (buffer == null)
        {
            Thread.Sleep(5);
            if (_udpClientThread == null)
            {
                return null;
            }

            (buffer, avalidLength) = kcp.TryRecv();
        }

        var s = buffer.Memory.Span.Slice(0, avalidLength).ToArray();
        return s;
    }

    private async void BeginRecv()
    {
        while (_udpClientThread != null)
        {
            try
            {
                var res = await client.ReceiveAsync();
                int ok = kcp.Input(res.Buffer);
                if (ok >= 0)
                {
                    EndPoint = res.RemoteEndPoint;
                    ycPort = EndPoint.Port;
                }
                else
                {
                    LogTool.Error("kcp.Receive 返回错误" + ok+"___"+res.RemoteEndPoint);
                }
               
            }
            catch (Exception e)
            {
                SocketException socketException = e as SocketException;
                if (socketException.ErrorCode == 10054)
                {
                }

                LogTool.Error(e);
            }
            Thread.Sleep(1);
        }
    }

    public void Dispose()
    {
        _udpClientThread = null;
        client?.Dispose();
        kcp?.Dispose();
        client = null;
        _kcp = null;
    }
}