using Common.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using static Common.Attributes.ATSCommandAttribute;

namespace DeviceCommand.Base
{
    [ATSCommand]
    [DeviceCategory("全部驱动")] // 添加分类属性
    public class Udp
    {
        public string RemoteIpAddress { get; set; } = "127.0.0.1";
        public int RemotePort { get; set; } = 8080;
        public int LocalPort { get; set; } = 0; // 0 表示系统自动分配
        public int SendTimeout { get; set; } = 3000;
        public int ReceiveTimeout { get; set; } = 3000;

        public UdpClient UdpClient { get; set; } = new UdpClient();

        /// <summary>
        /// 创建UDP设备对象
        /// </summary>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        /// <param name="sendTimeout">发送超时时间</param>
        /// <param name="receiveTimeout">接收超时时间</param>
        public Udp CreateDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
        {
            RemoteIpAddress = ipAddress;
            RemotePort = port;
            SendTimeout = sendTimeout;
            ReceiveTimeout = receiveTimeout;
            if (LocalPort > 0)
            {
                UdpClient = new UdpClient(LocalPort);
            }
            else
            {
                UdpClient = new UdpClient();
            }
            UdpClient.Client.SendTimeout = SendTimeout;
            UdpClient.Client.ReceiveTimeout = ReceiveTimeout;
            return this;
        }

        /// <summary>
        /// 修改UDP连接参数
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        /// <param name="sendTimeout">发送超时时间</param>
        /// <param name="receiveTimeout">接收超时时间</param>
        public static void ChangeDeviceConfig(Udp udp, string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
        {
            udp.RemoteIpAddress = ipAddress;
            udp.RemotePort = port;
            if (sendTimeout > 0)
            {
                udp.SendTimeout = sendTimeout;
            }
            if (receiveTimeout > 0)
            {
                udp.ReceiveTimeout = receiveTimeout;
            }
            if (udp.UdpClient != null)
            {
                udp.UdpClient.Client.SendTimeout = udp.SendTimeout;
                udp.UdpClient.Client.ReceiveTimeout = udp.ReceiveTimeout;
            }
        }

        // ————————————————————————
        // 功能 78
        // ————————————————————————

        /// <summary>
        /// UDP连接（功能78）
        /// UDP是无连接的，此处主要进行初始化和设置默认远程端点
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        /// <param name="ct">取消令牌</param>
        /// <returns>连接结果</returns>
        public static async Task<bool> ConnectAsync(Udp udp, CancellationToken ct = default)
        {
            if (udp.UdpClient == null)
            {
                if (udp.LocalPort > 0)
                {
                    udp.UdpClient = new UdpClient(udp.LocalPort);
                }
                else
                {
                    udp.UdpClient = new UdpClient();
                }
            }

            udp.UdpClient.Client.SendTimeout = udp.SendTimeout;
            udp.UdpClient.Client.ReceiveTimeout = udp.ReceiveTimeout;

            var remoteEndpoint = new IPEndPoint(IPAddress.Parse(udp.RemoteIpAddress), udp.RemotePort);
            //await udp.UdpClient.ConnectAsync(remoteEndpoint, ct);

            return true;
        }

        /// <summary>
        /// 紧急停止（功能78）
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        public static void EmergencyStop(Udp udp)
        {
            Close(udp); // 复用 Close 逻辑
        }

        // ————————————————————————
        // 功能 79
        // ————————————————————————

        /// <summary>
        /// 设备初始化（功能79）
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        public static void InitializeDevice(Udp udp)
        {
            if (udp.UdpClient == null)
            {
                if (udp.LocalPort > 0)
                {
                    udp.UdpClient = new UdpClient(udp.LocalPort);
                }
                else
                {
                    udp.UdpClient = new UdpClient();
                }
            }
            udp.UdpClient.Client.SendTimeout = udp.SendTimeout;
            udp.UdpClient.Client.ReceiveTimeout = udp.ReceiveTimeout;
        }

        /// <summary>
        /// 断开（功能79）
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        public static void Disconnect(Udp udp)
        {
            Close(udp); // 复用 Close 逻辑
        }

        /// <summary>
        /// 连接（功能79）
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        /// <param name="ct">取消令牌</param>
        /// <returns>连接结果</returns>
        public static async Task<bool> Connect(Udp udp, CancellationToken ct = default)
        {
            // 与 ConnectAsync 功能相同，可以复用
            return await ConnectAsync(udp, ct);
        }

        // ————————————————————————
        // 功能 80
        // ————————————————————————

        /// <summary>
        /// 发送字符串（功能80）
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        /// <param name="str">要发送的字符串</param>
        /// <param name="ct">取消令牌</param>
        public static async Task SendString(Udp udp, string str, CancellationToken ct = default)
        {
            await SendAsync(udp, str, ct); // 复用 SendAsync 逻辑
        }

        /// <summary>
        /// 发送字节（功能80）
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        /// <param name="bytes">要发送的字节数组</param>
        /// <param name="ct">取消令牌</param>
        public static async Task SendByte(Udp udp, byte[] bytes, CancellationToken ct = default)
        {
            await SendAsync(udp, bytes, ct); // 复用 SendAsync 逻辑
        }

        /// <summary>
        /// 接收字节（功能80）
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        /// <param name="ct">取消令牌</param>
        /// <returns>接收到的字节数组</returns>
        public static async Task<byte[]> ReceiveByte(Udp udp, CancellationToken ct = default)
        {
            // UDP 接收通常不需要预先分配固定大小的 buffer，直接返回整个数据报
            if (udp.UdpClient == null) throw new InvalidOperationException("UDP Client 未初始化。");

            var timeoutMs = udp.ReceiveTimeout;
            if (timeoutMs <= 0)
            {
                var res = await udp.UdpClient.ReceiveAsync();
                return res.Buffer;
            }

            var readTask = udp.UdpClient.ReceiveAsync();
            var timeoutTask = Task.Delay(timeoutMs, ct);

            var completedTask = await Task.WhenAny(readTask, timeoutTask);
            if (completedTask == timeoutTask)
            {
                throw new TimeoutException($"UDP通讯异常：读取操作在 {timeoutMs} ms内未完成");
            }

            var result = await readTask;
            return result.Buffer;
        }

        /// <summary>
        /// 接收字符串（功能80）
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        /// <param name="ct">取消令牌</param>
        /// <returns>接收到的字符串</returns>
        public static async Task<string> ReceiveString(Udp udp, CancellationToken ct = default)
        {
            var bytes = await ReceiveByte(udp, ct);
            return Encoding.UTF8.GetString(bytes);
        }

        // ————————————————————————
        // 内部辅助方法 (与 Tcp 风格一致)
        // ————————————————————————

        /// <summary>
        /// 关闭UDP连接
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        private static void Close(Udp udp)
        {
            udp.UdpClient?.Close();
            // udp.UdpClient?.Dispose(); // 通常 Close 就足够了
        }

        /// <summary>
        /// 发送字节数组到UDP设备 (内部核心方法)
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        /// <param name="bytes">要发送的字节数组</param>
        /// <param name="ct">取消令牌</param>
        public static async Task SendAsync(Udp udp, byte[] bytes, CancellationToken ct = default)
        {
            if (udp.UdpClient == null) throw new InvalidOperationException("UDP Client 未初始化。");

            var timeoutMs = udp.SendTimeout;
            if (timeoutMs <= 0)
            {
                await udp.UdpClient.SendAsync(bytes, bytes.Length);
                return;
            }

            var sendTask = udp.UdpClient.SendAsync(bytes, bytes.Length);
            var timeoutTask = Task.Delay(timeoutMs, ct);

            var completedTask = await Task.WhenAny(sendTask, timeoutTask);
            if (completedTask == timeoutTask)
            {
                throw new TimeoutException($"UDP通讯异常：写入操作在 {timeoutMs} ms内未完成");
            }

            await sendTask;
        }

        /// <summary>
        /// 发送字符串到UDP设备 (内部核心方法)
        /// </summary>
        /// <param name="udp">UDP设备对象</param>
        /// <param name="str">要发送的字符串</param>
        /// <param name="ct">取消令牌</param>
        private static async Task SendAsync(Udp udp, string str, CancellationToken ct = default)
        {
            await SendAsync(udp, Encoding.UTF8.GetBytes(str), ct);
        }

        // ————————————————————————
        // 实例方法 (可选，便于链式调用)
        // ————————————————————————

        /// <summary>
        /// 连接UDP设备（实例方法）
        /// </summary>
        /// <param name="ct">取消令牌</param>
        /// <returns>连接结果</returns>
        public async Task<bool> ConnectAsync(CancellationToken ct = default)
        {
            return await ConnectAsync(this, ct);
        }
    }
}