using Common.Attributes;
using DeviceCommand.Base;
using Logger;
using System;
using System.IO.Ports;
using System.Net;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace DeviceCommand.Device
{
    [BOBCommand]
    public class LQ7500_D : ModbusRtu
    {
        public LQ7500_D(string 串口, int 波特率, int 数据位, StopBits 停止位, Parity 校验位, int 读取超时, int 接收超时)
        {
            ConfigureDevice(串口, 波特率, 数据位, 停止位, 校验位, 读取超时, 接收超时);
        }
        #region 心跳
        private CancellationTokenSource? _cancellationTokenSource;
        private Task? _heartbeatTask;
        private const int HeartbeatInterval = 3000;
        public bool IsActive = false;
        public int ReConnectionAttempts = 0;
        public const int MaxReconnectAttempts = 10;

        public override async Task<bool> ConnectAsync(CancellationToken ct = default)
        {
            try
            {
                if (SerialPort.IsOpen)
                    SerialPort.Close();

                SerialPort.PortName = PortName;
                SerialPort.BaudRate = BaudRate;
                SerialPort.DataBits = DataBits;
                SerialPort.StopBits = StopBits;
                SerialPort.Parity = Parity;
                SerialPort.ReadTimeout = ReadTimeout;
                SerialPort.WriteTimeout = WriteTimeout;
                if (SerialPort.IsOpen) return true;
                SerialPort.Open();
                IsActive = true;
                StartHeartbeat();

                return true;
            }
            finally
            {

            }
        }
        public override void Close()
        {
            StopHeartbeat();
            if (SerialPort.IsOpen) SerialPort.Close();
        }

        public void StartHeartbeat()
        {
            if (_heartbeatTask != null && !_heartbeatTask.IsCompleted)
                return;

            _cancellationTokenSource?.Cancel();
            _cancellationTokenSource?.Dispose();

            _cancellationTokenSource = new CancellationTokenSource();

            _heartbeatTask = Task.Run(() => HeartbeatLoop(_cancellationTokenSource.Token));
        }

        public void StopHeartbeat()
        {
            try
            {
                IsActive = false;
                _cancellationTokenSource.Cancel();
                _heartbeatTask = null;
            }
            catch { }

            _heartbeatTask = null;
        }

        private async Task HeartbeatLoop(CancellationToken ct)
        {
            while (!ct.IsCancellationRequested)
            {
                await Task.Delay(HeartbeatInterval, ct);

                try
                {
                    await WriteSingleRegisterAsync(1,0,1);
                }
                catch (Exception ex)
                {
                    IsActive = false;
                    ReConnectionAttempts++;

                    if (ReConnectionAttempts > MaxReconnectAttempts)
                    {
                        LoggerHelper.InfoWithNotify("IT6724C重连多次失败");
                        StopHeartbeat();
                        return;
                    }

                    await ReconnectDevice(ct);
                }
            }
        }

        private async Task ReconnectDevice(CancellationToken ct)
        {
            try
            {
                bool ok = await ConnectAsync(ct);
                if (ok)
                    ReConnectionAttempts = 0;
            }
            catch { }
        }
        #endregion

        public byte 从站地址 { get; set; } = 1; // 默认从站地址

        private static readonly int[] Pow10Table =
            { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };

        private async Task 确保连接()
        {
            if (SerialPort == null || !SerialPort.IsOpen)
                await ConnectAsync();
        }

        #region 读取方法

        public virtual async Task<ushort> 读取温度分辨率()
        {
            await 确保连接();
            return (await ReadHoldingRegistersAsync(从站地址, 35, 1))[0];
        }

        public virtual async Task<double> 读取内部传感器温度(ushort 分辨率 = 0)
        {
            await 确保连接();
            if (分辨率 == 0) 分辨率 = await 读取温度分辨率();
            var data = await ReadHoldingRegistersAsync(从站地址, 0, 1);
            return Math.Round(data[0] / (double)Pow10Table[分辨率], 分辨率 + 1);
        }

        public virtual async Task<double> 读取外部传感器温度(ushort 分辨率 = 0)
        {
            await 确保连接();
            if (分辨率 == 0) 分辨率 = await 读取温度分辨率();
            var data = await ReadHoldingRegistersAsync(从站地址, 1, 1);
            return data[0] / (double)Pow10Table[分辨率];
        }

        public virtual async Task<ushort> 读取故障代码()
        {
            await 确保连接();
            return (await ReadHoldingRegistersAsync(从站地址, 1, 1))[0];
        }

        public virtual async Task<ushort> 读取设备状态()
        {
            await 确保连接();
            return (await ReadHoldingRegistersAsync(从站地址, 3, 1))[0];
        }

        public virtual async Task<ushort> 读取泵状态()
        {
            await 确保连接();
            return (await ReadHoldingRegistersAsync(从站地址, 4, 1))[0];
        }

        public virtual async Task<double> 读取流量()
        {
            await 确保连接();
            var data = await ReadHoldingRegistersAsync(从站地址, 17, 1);
            return Math.Round(data[0] / 10.0, 1);
        }

        #endregion

        #region 写入方法

        public virtual async Task 写入流量设置(double 值)
        {
            await 确保连接();
            short temp = (short)(值 * 10);
            ushort result = Unsafe.As<short, ushort>(ref temp);
            await WriteSingleRegisterAsync(从站地址, 24, result);
        }

        public virtual async Task 写入设备状态(bool 开)
        {
            await 确保连接();
            await WriteSingleRegisterAsync(从站地址, 3, (ushort)(开 ? 1 : 0));
        }

        public virtual async Task 写入泵状态(bool 开)
        {
            await 确保连接();
            await WriteSingleRegisterAsync(从站地址, 4, (ushort)(开 ? 1 : 0));
        }

        public virtual async Task 设置温度(double 温度)
        {
            await 确保连接();
            short temp = (short)(温度 * 100);
            ushort result = Unsafe.As<short, ushort>(ref temp);
            await WriteSingleRegisterAsync(从站地址, 2, result);
        }

        public virtual async Task 设置温度上限(double 温度)
        {
            await 确保连接();
            short temp = (short)(温度 * 100);
            ushort result = Unsafe.As<short, ushort>(ref temp);
            await WriteSingleRegisterAsync(从站地址, 5, result);
        }

        public virtual async Task 设置温度下限(double 温度)
        {
            await 确保连接();
            short temp = (short)(温度 * 100);
            ushort result = Unsafe.As<short, ushort>(ref temp);
            await WriteSingleRegisterAsync(从站地址, 6, result);
        }

        public virtual async Task 设置软件超温(double 上限温度, double 下限温度)
        {
            await 确保连接();
            short v1 = (short)(上限温度 * 100);
            short v2 = (short)(下限温度 * 100);
            ushort[] data = MemoryMarshal.Cast<short, ushort>(new short[] { v1, v2 }).ToArray();
            await WriteSingleRegisterAsync(从站地址, 30, data[0]);
            await Task.Delay(5);
            await WriteSingleRegisterAsync(从站地址, 31, data[1]);
        }

        public virtual async Task 设置硬件超温(double 上限温度)
        {
            await 确保连接();
            short v1 = (short)(上限温度 * 100);
            ushort result = Unsafe.As<short, ushort>(ref v1);
            await WriteSingleRegisterAsync(从站地址, 32, result);
        }

        #endregion
    }
}
