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.Tasks;
using System.Windows;
using static Common.Attributes.ATSCommandAttribute;

namespace DeviceCommand.Base
{
    [ATSCommand]
    [DeviceCategory("全部驱动")] // 添加分类属性
    public class Tcp
    {
        public string IPAddress { get; set; } = "127.0.0.1";

        public int Port { get; set; } = 502;

        public int SendTimeout { get; set; } = 3000;

        public int ReceiveTimeout { get; set; } = 3000;

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

        public Tcp CreateDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
        {
            IPAddress = ipAddress;
            Port = port;
            SendTimeout = sendTimeout;
            ReceiveTimeout = receiveTimeout;
            return this;
        }

        /// <summary>
        /// 修改TCP连接参数
        /// </summary>
        /// <param name="tcp"></param>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        /// <param name="sendTimeout">发送超时时间</param>
        /// <param name="receiveTimeout">接收超时时间</param>
        public static void ChangeDeviceConfig(Tcp tcp, string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
        {
            tcp.IPAddress = ipAddress;
            tcp.Port = port;
            if (sendTimeout > 0)
            {
                tcp.SendTimeout = sendTimeout;
            }
            if (receiveTimeout > 0)
            {
                tcp.ReceiveTimeout = receiveTimeout;
            }
        }



        /// <summary>
        /// 连接TCP设备
        /// </summary>
        /// <param name="tcp">TCP设备对象</param>
        /// <param name="ct">取消令牌</param>
        /// <returns>连接结果</returns>
        public static async Task<bool> ConnectAsync(Tcp tcp, CancellationToken ct = default)
        {
            if (!tcp.TcpClient.Connected)
            {
                tcp.TcpClient.Close();
                tcp.TcpClient.Dispose();
                tcp.TcpClient = new TcpClient();
                await tcp.TcpClient.ConnectAsync(tcp.IPAddress, tcp.Port, ct);
            }
            else
            {
                // 获取当前连接的远程端点
                var remoteEndPoint = (IPEndPoint)tcp.TcpClient.Client.RemoteEndPoint!;

                // 比较IP地址和端口
                var ip = remoteEndPoint.Address.MapToIPv4().ToString();
                bool isSameAddress = ip.Equals(tcp.IPAddress);
                bool isSamePort = remoteEndPoint.Port == tcp.Port;

                // 如果端点不匹配则断开重连
                if (!isSameAddress || !isSamePort)
                {
                    tcp.TcpClient.Close();
                    tcp.TcpClient.Dispose();
                    tcp.TcpClient = new TcpClient();
                    await tcp.TcpClient.ConnectAsync(tcp.IPAddress, tcp.Port, ct);
                }
            }
            return true;
        }

        /// <summary>
        /// 关闭TCP连接
        /// </summary>
        /// <param name="tcp">TCP设备对象</param>
        public static void Close(Tcp tcp)
        {
            tcp.TcpClient.Close();
        }

        /// <summary>
        /// 发送字节数组到TCP设备
        /// </summary>
        /// <param name="tcp">TCP设备对象</param>
        /// <param name="bytes">要发送的字节数组</param>
        /// <param name="ct">取消令牌</param>
        public static async Task SendAsync(Tcp tcp, byte[] bytes, CancellationToken ct = default)
        {
            var timeoutMs = tcp.SendTimeout;
            if (timeoutMs <= 0)
            {
                await tcp.TcpClient.Client.SendAsync(bytes, ct);
                return;
            }

            var sendTask = tcp.TcpClient.Client.SendAsync(bytes, ct).AsTask();
            var timeoutTask = Task.Delay(timeoutMs, ct);

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

            await sendTask;
        }

        /// <summary>
        /// 发送字符串到TCP设备
        /// </summary>
        /// <param name="tcp">TCP设备对象</param>
        /// <param name="str">要发送的字符串</param>
        /// <param name="ct">取消令牌</param>
        public static async Task SendAsync(Tcp tcp, string str, CancellationToken ct = default)
        {
            await SendAsync(tcp, Encoding.UTF8.GetBytes(str), ct);
        }

        /// <summary>
        /// 接收指定长度的字节数组
        /// </summary>
        /// <param name="tcp">TCP设备对象</param>
        /// <param name="buffer">接收缓冲区</param>
        /// <param name="ct">取消令牌</param>
        /// <returns>接收到的字节数组</returns>
        public static async Task<byte[]> ReadAsync(Tcp tcp, byte[] buffer, CancellationToken ct = default)
        {
            if (!tcp.TcpClient.Connected) return null;

            var timeoutMs = tcp.ReceiveTimeout;
            if (timeoutMs <= 0)
            {
                return await ReadBytes(tcp, buffer, ct);
            }

            var readTask = ReadBytes(tcp, buffer, ct);
            var timeoutTask = Task.Delay(timeoutMs, ct);

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

            return await readTask;
        }

        private static async Task<byte[]> ReadBytes(Tcp tcp, byte[] buffer, CancellationToken ct)
        {
            NetworkStream stream = tcp.TcpClient.GetStream();
            int bytesRead = 0;
            while (bytesRead < buffer.Length)
            {
                int read = await stream.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead, ct);
                if (read == 0) return null;
                bytesRead += read;
            }
            return buffer;
        }

        /// <summary>
        /// 接收字符串直到遇到分隔符
        /// </summary>
        /// <param name="tcp">TCP设备对象</param>
        /// <param name="delimiter">分隔符</param>
        /// <param name="ct">取消令牌</param>
        /// <returns>接收到的字符串</returns>
        public static async Task<string> ReadAsync(Tcp tcp, string delimiter = "\n", CancellationToken ct = default)
        {
            delimiter ??= "\n";
            var timeoutMs = tcp.ReceiveTimeout;
            if (timeoutMs <= 0)
            {
                return await ReadString(tcp, delimiter, ct);
            }

            var readTask = ReadString(tcp, delimiter, ct);
            var timeoutTask = Task.Delay(timeoutMs, ct);

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

            return await readTask;
        }

        private static async Task<string> ReadString(Tcp tcp, string delimiter, CancellationToken ct)
        {
            NetworkStream stream = tcp.TcpClient.GetStream();
            MemoryStream memoryStream = new();
            byte[] buffer = new byte[2048];

            int bytesRead;
            while ((bytesRead = await stream.ReadAsync(buffer, ct)) > 0)
            {
                memoryStream.Write(buffer, 0, bytesRead);
                string data = Encoding.UTF8.GetString(memoryStream.ToArray());
                int lineEndIndex = data.IndexOf(delimiter);
                if (lineEndIndex >= 0)
                {
                    return data[..lineEndIndex].Trim();
                }
            }
            return null;
        }

        /// <summary>
        /// 发送并接收数据
        /// </summary>
        /// <param name="tcp">TCP设备对象</param>
        /// <param name="str">要发送的字符串</param>
        /// <param name="endstr">结束符</param>
        /// <param name="ct">取消令牌</param>
        /// <returns>接收到的响应</returns>
        public async Task<string> WriteRead(Tcp tcp, string str, string endstr, CancellationToken ct = default)
        {
            await SendAsync(tcp, str, ct);
            return await ReadAsync(tcp, endstr, ct);
        }

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

    }
}