namespace SimpleUdp
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Collections.Concurrent;


    internal class State
    {
        internal State(int bufferSize)
        {
            Buffer = new byte[bufferSize];
        }

        internal byte[] Buffer = null;
    }
    public class UdpEndpoint : IDisposable
    {
        private Socket _Socket = null;
        private int _MaxDatagramSize = 65507;
        private EndPoint _Endpoint = new IPEndPoint(IPAddress.Any, 0);
        private SemaphoreSlim _SendLock = new SemaphoreSlim(1, 1);

        public UdpEndpoint(string ip, int port)
        {
            var ipAddress = IPAddress.Parse(ip);

            _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            _Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            _Socket.Bind(new IPEndPoint(ipAddress, port));

            State state = new State(_MaxDatagramSize);

            _Socket.BeginReceiveFrom(state.Buffer, 0, _MaxDatagramSize, SocketFlags.None,
                ref _Endpoint, ReceiveCallback, state);
        }

        private void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                State so = (State)ar.AsyncState;
                int bytes = _Socket.EndReceiveFrom(ar, ref _Endpoint);

                if (bytes > 0 && bytes < so.Buffer.Length)
                {
                    byte[] buffer = new byte[bytes];
                    Buffer.BlockCopy(so.Buffer, 0, buffer, 0, bytes);

                    // 直接使用接收到的 EndPoint 进行回复
                    string senderIpPort = _Endpoint.ToString();
                    string[] parts = senderIpPort.Split(':');

                    if (parts.Length == 2)
                    {
                        SendInternal(parts[0], int.Parse(parts[1]), new byte[] { 0x01, 0x01 });
                    }
                }

                // 继续接收
                _Socket.BeginReceiveFrom(so.Buffer, 0, _MaxDatagramSize, SocketFlags.None,
                    ref _Endpoint, ReceiveCallback, so);
            }
            catch (Exception ex)
            {
                // 处理异常
            }
        }

        private void SendInternal(string ip, int port, byte[] data)
        {
            _SendLock.Wait();

            try
            {
                IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ip), port);
                // 使用同一个 Socket 发送回复
                _Socket.SendTo(data, remoteEP);
            }
            finally
            {
                _SendLock.Release();
            }
        }

        public void Dispose()
        {
            _Socket.Close();
            _Socket.Dispose();
        }
    }
}
