using HslCommunication;
using HslCommunication.Core;
using HslCommunication.ModBus;
using HslCommunication.Profinet.Siemens;
using SWRIS.Enums;
using SWRIS.Models;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace SWRIS.Core
{
    public class CalibrationCore : IDisposable
    {
        private IReadWriteNet moduleDevice;
        private readonly CalibrationSettings config;
        private readonly ModuleStateModel moduleState;
        private readonly CancellationTokenSource ctsToken = new CancellationTokenSource();
        public bool IsConnected { get; set; }
        public event EventHandler<LimitData> LimitStateChanged;
        public event EventHandler<bool> ConnectionStateChanged;
        public CalibrationCore(CalibrationSettings config)
        {
            this.config = config;
            moduleState = new ModuleStateModel(false);
            InitializeModule();
            ConnectServer();
            ThreadPool.QueueUserWorkItem(o => ReadLimitData(ctsToken.Token));
        }
        private void InitializeModule()
        {
            // 根据模块类型创建相应的设备实例
            switch (config.ModuleType)
            {
                case ModuleType.S1200:
                    moduleDevice = new SiemensS7Net(SiemensPLCS.S1200)
                    {
                        IpAddress = config.Tcp.IpAddress,
                        Port = config.Tcp.Port,
                        ConnectTimeOut = 3000,
                        ReceiveTimeOut = 2000
                    };
                    break;

                case ModuleType.S1500:
                    moduleDevice = new SiemensS7Net(SiemensPLCS.S1500)
                    {
                        IpAddress = config.Tcp.IpAddress,
                        Port = config.Tcp.Port,
                        ConnectTimeOut = 3000,
                        ReceiveTimeOut = 2000
                    };
                    break;

                case ModuleType.S300:
                    moduleDevice = new SiemensS7Net(SiemensPLCS.S300)
                    {
                        IpAddress = config.Tcp.IpAddress,
                        Port = config.Tcp.Port,
                        ConnectTimeOut = 3000,
                        ReceiveTimeOut = 2000
                    };
                    break;

                case ModuleType.S400:
                    moduleDevice = new SiemensS7Net(SiemensPLCS.S400)
                    {
                        IpAddress = config.Tcp.IpAddress,
                        Port = config.Tcp.Port,
                        ConnectTimeOut = 3000,
                        ReceiveTimeOut = 2000
                    };
                    break;

                case ModuleType.S200:
                    moduleDevice = new SiemensS7Net(SiemensPLCS.S200)
                    {
                        IpAddress = config.Tcp.IpAddress,
                        Port = config.Tcp.Port,
                        ConnectTimeOut = 3000,
                        ReceiveTimeOut = 2000
                    };
                    break;

                case ModuleType.S200Smart:
                    moduleDevice = new SiemensS7Net(SiemensPLCS.S200Smart)
                    {
                        IpAddress = config.Tcp.IpAddress,
                        Port = config.Tcp.Port,
                        ConnectTimeOut = 3000,
                        ReceiveTimeOut = 2000
                    };
                    break;

                case ModuleType.ModbusTcp:
                    moduleDevice = new ModbusTcpNet(config.Tcp.IpAddress, config.Tcp.Port, config.Tcp.Station)
                    {
                        ConnectTimeOut = 3000,
                        ReceiveTimeOut = 2000
                    };
                    break;

                case ModuleType.ModbusRtu:
                    moduleDevice = new ModbusRtu(config.Serial.Station);
                    (moduleDevice as ModbusRtu).SerialPortInni(config.Serial.PortName,
                                                               config.Serial.BaudRate,
                                                               config.Serial.DataBits,
                                                               config.Serial.StopBits,
                                                               config.Serial.Parity);
                    break;

                default:
                    throw new NotSupportedException($"不支持的模块类型: {config.ModuleType}");
            }
        }
        private async void ReadLimitData(CancellationToken token)
        {
            OperateResult<bool> readLimitResult;
            while (!token.IsCancellationRequested)
            {
                try
                {
                    if (IsConnected)
                    {
                        foreach (var limit in config.Limits)
                        {
                            if (!limit.IsEnable)
                                continue;
                            readLimitResult = await moduleDevice.ReadBoolAsync(limit.Address);
                            if (StateMonitor(readLimitResult))
                            {
                                var limitState = (limit.IsReverse ? !readLimitResult.Content : readLimitResult.Content) ? LimitState.AtLimit : LimitState.NotInLimit;
                                if (limit.State != limitState)
                                {
                                    limit.State = limitState;
                                    LimitStateChanged?.Invoke(this, limit);
                                }
                            }
                            await Task.Delay(50);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error("读取限位信号时发生错误：" + ex.Message, ex);
                }
                finally
                {
                    Thread.Sleep(200);
                }
            }
        }
        private bool StateMonitor(OperateResult<bool> readLimitResult)
        {
            if (readLimitResult.IsSuccess)
            {
                moduleState.Depth = moduleState.Depth < 0 ? 1 : moduleState.Depth > 20 ? 20 : moduleState.Depth + 1;
                if (!moduleState.IsOnline && moduleState.Depth >= 3)
                {
                    ChangeModuleState(true);
                }
                return true;
            }
            else
            {
                moduleState.Depth = moduleState.Depth > 0 ? -1 : moduleState.Depth < -20 ? -20 : moduleState.Depth - 1;
                if (moduleState.IsOnline && moduleState.Depth <= -3)
                {
                    ChangeModuleState(false);
                }
                return false;
            }
        }
        private void ChangeModuleState(bool isOnline)
        {
            moduleState.IsOnline = isOnline;
            moduleState.Depth = 0;
            ConnectionStateChanged?.Invoke(this, isOnline);
        }
        private bool ConnectDevice()
        {
            try
            {
                if (moduleDevice is SiemensS7Net siemensDevice)
                {
                    return siemensDevice.ConnectServer().IsSuccess;
                }
                else if (moduleDevice is ModbusTcpNet modbusTcpDevice)
                {
                    return modbusTcpDevice.ConnectServer().IsSuccess;
                }
                else if (moduleDevice is ModbusRtu modbusRtuDevice)
                {
                    return modbusRtuDevice.Open().IsSuccess;
                }
                return false;
            }
            catch (Exception ex)
            {
                LogHelper.Error($"设备连接异常: {ex.Message}", ex);
                return false;
            }
        }
        private void CloseDeviceConnection()
        {
            try
            {
                if (moduleDevice is SiemensS7Net siemensDevice)
                {
                    siemensDevice.ConnectClose();
                }
                else if (moduleDevice is ModbusTcpNet modbusTcpDevice)
                {
                    modbusTcpDevice.ConnectClose();
                }
                else if (moduleDevice is ModbusRtu modbusRtuDevice)
                {
                    modbusRtuDevice.Close();
                }
                if (moduleDevice is IDisposable disposable)
                {
                    disposable.Dispose();
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error($"关闭设备连接异常: {ex.Message}", ex);
            }
            finally
            {
                moduleDevice = null;
                IsConnected = false;
            }
        }

        public void ConnectServer()
        {
            ThreadPool.QueueUserWorkItem(action =>
            {
                while (!ctsToken.IsCancellationRequested)
                {
                    if (!IsConnected)
                    {
                        try
                        {
                            if (ConnectDevice())
                            {
                                IsConnected = true;
                                LogHelper.Info($"连接成功: {config.ModuleType} - {config.Tcp.IpAddress}:{config.Tcp.Port}");
                            }
                        }
                        catch (Exception ex)
                        {
                            LogHelper.Error($"连接异常: {ex.Message}", ex);
                        }
                    }
                    Thread.Sleep(5000);
                }
            });
        }

        public void CloseServer()
        {
            CloseDeviceConnection();
        }
        public void Dispose()
        {
            ctsToken?.Cancel();
            ctsToken?.Dispose();
            CloseDeviceConnection();
        }
    }
}
