using BDU.Models;
using BDU.Tools;
using BDU.Windows;
using DeviceCommand.Base;
using DocumentFormat.OpenXml.Drawing.Charts;
using Newtonsoft.Json;
using Org.BouncyCastle.Utilities;
using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using TSMasterCAN;

namespace BDU.Logic
{
    public static class DeviceConnect
    {
        private static ParameterModel devicePara = new();

        public static async Task InitAndConnectDevice(ProgramModel program, DeviceModel device, bool isDeviceAdd = false)
        {
            try
            {
                devicePara = new()
                {
                    Name = device.Name,
                    IsVisible = false
                };
                if (isDeviceAdd)
                {
                    device.ParameterID = devicePara.ID;
                    program.Devices.Add(device);
                }
                else
                {
                    devicePara.ID = device.ParameterID;
                }
                program.Parameters.Add(devicePara);
                switch (device.Type)
                {
                    case "Tcp":
                        program.Parameters.First(x => x.ID == device.ParameterID).Type = typeof(Tcp);
                        Tcp tcp = new();
                        var DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(device.ConnectString)!;
                        tcp.CreateDevice(DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value),
                            Convert.ToInt32(DeviceConnectSettings[2].Value), Convert.ToInt32(DeviceConnectSettings[3].Value));

                        device.CommunicationProtocol = tcp;
                        var tmpDevice = program.Devices.FirstOrDefault(x => x.ID == device.ID);
                        var tmpParameter = program.Parameters.FirstOrDefault(x => x.ID == device.ParameterID);
                        if (tmpDevice != null && tmpParameter != null)
                        {
                            tmpDevice.CommunicationProtocol = device.CommunicationProtocol;
                            tmpParameter.Value = tcp;
                            _ = DeviceConnectedStatusWatchTask(tmpDevice.ID);
                        }

                        break;

                    case "Udp":
                        program.Parameters.First(x => x.ID == device.ParameterID).Type = typeof(Udp);
                        Udp udp = new();
                        DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(device.ConnectString)!;
                        udp.CreateDevice(DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value),
                            Convert.ToInt32(DeviceConnectSettings[2].Value), Convert.ToInt32(DeviceConnectSettings[3].Value));
                        device.CommunicationProtocol = udp;
                        tmpDevice = program.Devices.FirstOrDefault(x => x.ID == device.ID);
                        tmpParameter = program.Parameters.FirstOrDefault(x => x.ID == device.ParameterID);
                        if (tmpDevice != null && tmpParameter != null)
                        {
                            tmpDevice.CommunicationProtocol = device.CommunicationProtocol;
                            tmpParameter.Value = udp;
                            _ = DeviceConnectedStatusWatchTask(tmpDevice.ID);
                        }
                        break;

                    case "ModbusTcp":
                        program.Parameters.First(x => x.ID == device.ParameterID).Type = typeof(ModbusTcp);
                        ModbusTcp modbusTcp = new();
                        DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(device.ConnectString)!;
                        modbusTcp.CreateDevice(DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value),
                            Convert.ToInt32(DeviceConnectSettings[2].Value), Convert.ToInt32(DeviceConnectSettings[3].Value));

                        device.CommunicationProtocol = modbusTcp;
                        tmpDevice = program.Devices.FirstOrDefault(x => x.ID == device.ID);
                        tmpParameter = program.Parameters.FirstOrDefault(x => x.ID == device.ParameterID);
                        if (tmpDevice != null && tmpParameter != null)
                        {
                            tmpDevice.CommunicationProtocol = device.CommunicationProtocol;
                            tmpParameter.Value = modbusTcp;
                            _ = DeviceConnectedStatusWatchTask(tmpDevice.ID);
                        }

                        break;

                    case "CAN":
                        program.Parameters.First(x => x.ID == device.ParameterID).Type = typeof(CAN);
                        tmpDevice = program.Devices.FirstOrDefault(x => x.ID == device.ID);
                        if (tmpDevice != null)
                        {
                            tmpDevice.CommunicationProtocol = device.CommunicationProtocol;
                            CAN.DisConnect();
                            var re1 = CAN.Init("ATS测试系统");
                            var re2 = CAN.LoadDBC(SystemConfig.Instance.DBCFilePath, [0, 1, 2, 3], out _);
                            var re3 = CAN.Connect();
                            if (re1 == 0 && re2 == 0 && re3 == 0)
                            {
                                tmpDevice.Connected = true;
                            }
                            else
                            {
                                tmpDevice.Connected = false;
                            }
                            _ = DeviceConnectedStatusWatchTask(tmpDevice.ID);
                        }
                        break;

                    case "串口":
                        program.Parameters.First(x => x.ID == device.ParameterID).Type = typeof(Serial_Port);

                        // 串口设备初始化
                        Serial_Port serialPort = new ();
                        DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(device.ConnectString)!;

                        StopBits stopBitsEnum = GetstopBitsEnum(DeviceConnectSettings[3].Value);
                        Parity parityEnum = GetparityEnum(DeviceConnectSettings[4].Value);

                        serialPort.CreateDevice(DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value)
                            , Convert.ToInt32(DeviceConnectSettings[2].Value), stopBitsEnum, parityEnum
                            , Convert.ToInt32(DeviceConnectSettings[5].Value), Convert.ToInt32(DeviceConnectSettings[6].Value));

                        // 将串口通信协议赋值给设备
                        device.CommunicationProtocol = serialPort;

                        // 更新设备和参数
                        tmpDevice = program.Devices.FirstOrDefault(x => x.ID == device.ID);
                        tmpParameter = program.Parameters.FirstOrDefault(x => x.ID == device.ParameterID);
                        if (tmpDevice != null && tmpParameter != null)
                        {
                            tmpDevice.CommunicationProtocol = device.CommunicationProtocol;
                            tmpParameter.Value = serialPort;
                            _ = DeviceConnectedStatusWatchTask(tmpDevice.ID);
                        }

                        break;

                    case "ModbusRtu_Tcp":

                        program.Parameters.First(x => x.ID == device.ParameterID).Type = typeof(ModbusRtu_Tcp);
                        ModbusRtu_Tcp modbusRtu = new();
                        DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(device.ConnectString)!;

                        modbusRtu.CreateDevice(DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value),
                            Convert.ToInt32(DeviceConnectSettings[2].Value), Convert.ToInt32(DeviceConnectSettings[3].Value));

                        device.CommunicationProtocol = modbusRtu;
                        tmpDevice = program.Devices.FirstOrDefault(x => x.ID == device.ID);
                        tmpParameter = program.Parameters.FirstOrDefault(x => x.ID == device.ParameterID);
                        if (tmpDevice != null && tmpParameter != null)
                        {
                            tmpDevice.CommunicationProtocol = device.CommunicationProtocol;
                            tmpParameter.Value = modbusRtu;
                            _ = DeviceConnectedStatusWatchTask(tmpDevice.ID);
                        }

                        break;

                    case "ModbusRtu_Udp":
                        program.Parameters.First(x => x.ID == device.ParameterID).Type = typeof(ModbusRtu_Udp);
                        ModbusRtu_Udp modbusRtuUdp = new();
                        DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(device.ConnectString)!;
       
                        modbusRtuUdp.CreateDevice(DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value),
                            Convert.ToInt32(DeviceConnectSettings[2].Value));
                        device.CommunicationProtocol = modbusRtuUdp;
                        tmpDevice = program.Devices.FirstOrDefault(x => x.ID == device.ID);
                        tmpParameter = program.Parameters.FirstOrDefault(x => x.ID == device.ParameterID);
                        if (tmpDevice != null && tmpParameter != null)
                        {
                            tmpDevice.CommunicationProtocol = device.CommunicationProtocol;
                            tmpParameter.Value = modbusRtuUdp;
                            _ = DeviceConnectedStatusWatchTask(tmpDevice.ID);
                        }
                        break;

                    case "ModbusRtu_Serial":
                        program.Parameters.First(x => x.ID == device.ParameterID).Type = typeof(ModbusRtu_Udp);
                        ModbusRtu_Serial modbusRtu_Serial = new();
                        DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(device.ConnectString)!;
                        stopBitsEnum = GetstopBitsEnum(DeviceConnectSettings[3].Value);
                        parityEnum = GetparityEnum(DeviceConnectSettings[4].Value);

                        modbusRtu_Serial.CreateDevice(DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value)
                            , Convert.ToInt32(DeviceConnectSettings[2].Value), stopBitsEnum, parityEnum
                            , Convert.ToInt32(DeviceConnectSettings[5].Value), Convert.ToInt32(DeviceConnectSettings[6].Value));
                        device.CommunicationProtocol = modbusRtu_Serial;
                        tmpDevice = program.Devices.FirstOrDefault(x => x.ID == device.ID);
                        tmpParameter = program.Parameters.FirstOrDefault(x => x.ID == device.ParameterID);
                        if (tmpDevice != null && tmpParameter != null)
                        {
                            tmpDevice.CommunicationProtocol = device.CommunicationProtocol;
                            tmpParameter.Value = modbusRtu_Serial;
                            _ = DeviceConnectedStatusWatchTask(tmpDevice.ID);
                        }
                        break;





                }
            }
            catch (Exception ex)
            {
                Log.Error($"设备 [ {device.Name} ] 初始化连接失败：{ex.Message}");
            }
        }

        private static async Task DeviceConnectedStatusWatchTask(Guid deviceID)
        {
            DeviceModel? watchedDevice = MainWindow.Instance.Program.Devices.FirstOrDefault(x => x.ID == deviceID);
            while (watchedDevice != null)
            {
                try
                {
                    switch (watchedDevice.Type)
                    {
                        case "Tcp":
                            Tcp tcp = (Tcp)watchedDevice.CommunicationProtocol!;
                            var DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(watchedDevice.ConnectString)!;
                            Tcp.ChangeDeviceConfig(tcp, DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value),
                                Convert.ToInt32(DeviceConnectSettings[2].Value), Convert.ToInt32(DeviceConnectSettings[3].Value));
                            var re = await Tcp.ConnectAsync(tcp);
                            await Tcp.SendAsync(tcp, "");
                            if (re && tcp.TcpClient.Connected)
                            {
                                watchedDevice.Connected = true;
                            }
                            else
                            {
                                watchedDevice.Connected = false;
                            }
                            break;

                        case "Udp":
                            Udp udp = (Udp)watchedDevice.CommunicationProtocol!;
                            DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(watchedDevice.ConnectString)!;
                            Udp.ChangeDeviceConfig(udp, DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value),
                                Convert.ToInt32(DeviceConnectSettings[2].Value), Convert.ToInt32(DeviceConnectSettings[3].Value));
                            re = await Udp.ConnectAsync(udp);
                            await Udp.SendAsync(udp, Encoding.UTF8.GetBytes(""));
                            if (re && udp.UdpClient.Client.Connected)
                            {
                                watchedDevice.Connected = true;
                            }
                            else
                            {
                                watchedDevice.Connected = false;
                            }
                            break;

                        case "ModbusTcp":
                            ModbusTcp modbusTcp = (ModbusTcp)watchedDevice.CommunicationProtocol!;
                            DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(watchedDevice.ConnectString)!;
                            ModbusTcp.ChangeDeviceConfig(modbusTcp, DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value),
                                Convert.ToInt32(DeviceConnectSettings[2].Value), Convert.ToInt32(DeviceConnectSettings[3].Value));
                            re = await ModbusTcp.ConnectAsync(modbusTcp);
                            await modbusTcp.TcpClient.Client.SendAsync(Encoding.UTF8.GetBytes(""));
                            if (re && modbusTcp.TcpClient.Connected)
                            {
                                watchedDevice.Connected = true;
                            }
                            else
                            {
                                watchedDevice.Connected = false;
                            }
                            break;

                        case "CAN":
                            var re1 = CAN.Init("ATS测试系统");
                            //var re2 = CAN.LoadDBC(SystemConfig.Instance.DBCFilePath, [0, 1, 2, 3], out _);
                            //var re3 = CAN.Connect();
                            if (re1 == 0 && CAN.ConnectFlag)
                            {
                                watchedDevice.Connected = true;
                            }
                            else
                            {
                                watchedDevice.Connected = false;
                            }
                            break;

                        case "串口":
                            Serial_Port serialPort = (Serial_Port)watchedDevice.CommunicationProtocol!;
                            DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(watchedDevice.ConnectString)!;
                            
                            StopBits stopBitsEnum = GetstopBitsEnum(DeviceConnectSettings[3].Value);
                            Parity parityEnum = GetparityEnum(DeviceConnectSettings[4].Value);

                            Serial_Port.ChangeDeviceConfig(serialPort, DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value)
                                , Convert.ToInt32(DeviceConnectSettings[2].Value), stopBitsEnum, parityEnum
                                , Convert.ToInt32(DeviceConnectSettings[5].Value), Convert.ToInt32(DeviceConnectSettings[6].Value));

                            re = await Serial_Port.ConnectAsync(serialPort);
                            await Serial_Port.SendAsync(serialPort, "");

                            if (re)
                            {
                                watchedDevice.Connected = true;
                            }
                            else
                            {
                                watchedDevice.Connected = false;
                            }
                            break;

                        case "ModbusRtu_Tcp":
                            ModbusRtu_Tcp modbusRtu = (ModbusRtu_Tcp)watchedDevice.CommunicationProtocol!;
                            DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(watchedDevice.ConnectString)!;
                            stopBitsEnum = GetstopBitsEnum(DeviceConnectSettings[3].Value);
                            //parityEnum = GetparityEnum(DeviceConnectSettings[4].Value);
                            ModbusRtu_Tcp.ChangeDeviceConfig(modbusRtu, DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value),
                                Convert.ToInt32(DeviceConnectSettings[2].Value), Convert.ToInt32(DeviceConnectSettings[3].Value));
                            re = await ModbusRtu_Tcp.ConnectAsync(modbusRtu);
                            await modbusRtu.TcpClient.Client.SendAsync(Encoding.UTF8.GetBytes(""));
                            if (re && modbusRtu.TcpClient.Connected)
                            {
                                watchedDevice.Connected = true;
                            }
                            else
                            {
                                watchedDevice.Connected = false;
                            }
                            break;

                        case "ModbusRtu_Udp":
                            ModbusRtu_Udp modbusRtuUdp = (ModbusRtu_Udp)watchedDevice.CommunicationProtocol!;
                            DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(watchedDevice.ConnectString)!;
                            //stopBitsEnum = GetstopBitsEnum(DeviceConnectSettings[3].Value);
                            //parityEnum = GetparityEnum(DeviceConnectSettings[4].Value);
                            ModbusRtu_Udp.ChangeDeviceConfig(modbusRtuUdp, DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value)
                                , Convert.ToInt32(DeviceConnectSettings[2].Value));
                            CancellationToken ct = default;
                            re = await modbusRtuUdp.ConnectAsync(ct);
                            if (re)                      
                            {
                                await modbusRtuUdp.SendRequestAndReceiveAsync(Encoding.UTF8.GetBytes(""), CancellationToken.None);
                                watchedDevice.Connected = true;
                            }
                            else
                            {
                                watchedDevice.Connected = false;
                            }
                            break;

                        case "ModbusRtu_Serial":
                            ModbusRtu_Serial modbusRtu_Serial = (ModbusRtu_Serial)watchedDevice.CommunicationProtocol!;
                            DeviceConnectSettings = JsonConvert.DeserializeObject<ObservableCollection<DeviceConnectSettingModel>>(watchedDevice.ConnectString)!;

                            stopBitsEnum = GetstopBitsEnum(DeviceConnectSettings[3].Value);
                            parityEnum = GetparityEnum(DeviceConnectSettings[4].Value);

                            ModbusRtu_Serial.ChangeDeviceConfig(modbusRtu_Serial, DeviceConnectSettings[0].Value, Convert.ToInt32(DeviceConnectSettings[1].Value)
                                , Convert.ToInt32(DeviceConnectSettings[2].Value), stopBitsEnum, parityEnum
                                , Convert.ToInt32(DeviceConnectSettings[5].Value), Convert.ToInt32(DeviceConnectSettings[6].Value));

                            CancellationToken ctSerial = default;
                            re = await ModbusRtu_Serial.ConnectAsync(modbusRtu_Serial, ctSerial);
                            if (re)
                            {
                                watchedDevice.Connected = true;
                            }
                            else
                            {
                                watchedDevice.Connected = false;
                            }
                            break;
                    }

                }
                catch (Exception ex)
                {
                    watchedDevice.Connected = false;
                    watchedDevice.ErrorMessage = ex.Message;
                }
                finally
                {
                    await Task.Delay(1000);
                    if (watchedDevice.Connected && !string.IsNullOrEmpty(watchedDevice.ErrorMessage))
                    {
                        watchedDevice.ErrorMessage = "";
                    }
                    watchedDevice = MainWindow.Instance.Program.Devices.FirstOrDefault(x => x.ID == deviceID);
                }
            }
        }

        private static StopBits GetstopBitsEnum(string Value)
        {
            StopBits stopBitsEnum;
            // 使用 Enum.TryParse 转换字符串到 StopBits 枚举
            if (!Enum.TryParse(Value, true, out stopBitsEnum))
            {
                throw new TimeoutException($"转换失败！无效的停止位字符串");
            }
            return stopBitsEnum;
        }
        private static Parity GetparityEnum(string Value)
        {
            string ParityEnumValue = GetParityEnumValue(Value);
            Parity parityEnum;
            // 使用 Enum.TryParse 转换字符串到 Parity 枚举
            if (!Enum.TryParse(ParityEnumValue, true, out parityEnum))
            {
                throw new TimeoutException($"转换失败！无效的校验位字符串");
            }
            return parityEnum;
        }

        private static string GetParityEnumValue(string Value)
        {
            return Value switch
            {
                "无" => "None",
                "奇" => "Odd",
                "偶" => "Even",
                _ => "",
            };
        }
    }
}
