using Modbus.Device;
using Modbus;
using OxyPlot.Series;
using OxyPlot;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using OxyPlot.Axes;
using OxyPlot.Legends;
using 口罩泄露定制款;
using static OfficeOpenXml.ExcelErrorValue;

namespace ShanghaiEnvironmentalTechnology
{
    /// <summary>
    /// 参数配置界面逻辑
    /// </summary>
    public partial class ParameterConfigWindow : Window
    {
        private readonly string _lang = ConfigurationManager.AppSettings["Language"] ?? "zh-CN";
        Function ma;
        DataChange c = new DataChange();
        #region 数据模型（存储参数值）
        // 流量参数（9个）
        private class FlowParameters
        {
            public float ExhaustP { get; set; }   // 排气P
            public float FlowP { get; set; }      // 流量P
            public float InhaleP { get; set; }    // 吸P
            public float ExhaustI { get; set; }   // 排气I
            public float FlowI { get; set; }      // 流量I
            public float InhaleI { get; set; }    // 吸I
            public float ExhaustD { get; set; }   // 排气D
            public float FlowD { get; set; }      // 流量D
            public float InhaleD { get; set; }    // 吸D
        }

        // PID参数（4个）
        private class PIDParameters
        {
            public float ExpiratoryPID { get; set; }      // 呼PID加系数
            public float InspiratoryPID { get; set; }     // 吸PID加系数
            public float ExhaustFlowPID { get; set; }     // 排气流PID加系数
            public float ResistancePID { get; set; }      // 气阻PID加系数
        }

        // 系数参数（4个）
        private class CoefficientParameters
        {
            public float ExpiratoryFlowCoeff { get; set; }    // 呼流量系数
            public float InspiratoryFlowCoeff { get; set; }   // 吸流量系数
            public float NasalPressureCoeff { get; set; }     // 鼻口压力系数
            public float InterfacePressureCoeff { get; set; } // 连接口压力系数
        }
        #endregion

        #region 私有变量
        // 定时器（3个：分别对应三类参数）
        private readonly System.Timers.Timer _flowTimer = new System.Timers.Timer(1000);    // 流量参数定时器（1秒更新一次）
        private readonly System.Timers.Timer _pidTimer = new System.Timers.Timer(1000);     // PID参数定时器（1秒更新一次）
        private readonly System.Timers.Timer _coeffTimer = new System.Timers.Timer(1000);   // 系数参数定时器（1秒更新一次）

        // 参数存储实例
        private readonly FlowParameters _flowParams = new FlowParameters();
        private readonly PIDParameters _pidParams = new PIDParameters();
        private readonly CoefficientParameters _coeffParams = new CoefficientParameters();

        // 随机数生成器（模拟下位机数据）
        private readonly Random _random = new Random();

        // Modbus通信
        private TcpClient _tcpClient;
        private IModbusMaster? _modbusMaster;
        #endregion


        #region 构造函数与初始化
        public ParameterConfigWindow()
        {
            InitializeComponent();
            InitializeModbusTcp();

            InitTimers(); // 初始化定时器
        }

        // 消息提示封装（统一风格）
        private void ShowSuccess(string message) => MessageBox.Show(message, _lang == "en-US" ? "Success" : "成功", MessageBoxButton.OK, MessageBoxImage.Information);
        private void ShowWarning(string message) => MessageBox.Show(message, _lang == "en-US" ? "Warning" : "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
        private void ShowError(string message) => MessageBox.Show(message, _lang == "en-US" ? "Error" : "错误", MessageBoxButton.OK, MessageBoxImage.Error);



        /// <summary>
        /// 初始化Modbus连接和定时器
        /// </summary>
        private void InitializeModbusTcp()
        {
            try
            {
                // 从配置读取PLC连接信息
                string? plcIp = ConfigurationManager.AppSettings["PLC2_IP"];
                int plcPort = int.Parse(ConfigurationManager.AppSettings["PLC2_Port"]);

                _tcpClient = new TcpClient(plcIp, plcPort);
                _modbusMaster = ModbusIpMaster.CreateIp(_tcpClient);
                _modbusMaster.Transport.ReadTimeout = 3000;
                _modbusMaster.Transport.WriteTimeout = 3000;

                // 初始化定时器
                //InitializeTimers();
                // 初始化数据库
                //InitializeDatabase();
                ma = new Function(_modbusMaster);
            }
            catch (Exception ex)
            {
                ShowError($"Modbus初始化失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 初始化定时器
        /// </summary>
        private void InitTimers()
        {
            // 流量参数定时器
            _flowTimer.Elapsed += FlowTimer_Elapsed;
            _flowTimer.AutoReset = true; // 自动重复

            // PID参数定时器
            _pidTimer.Elapsed += PidTimer_Elapsed;
            _pidTimer.AutoReset = true;

            // 系数参数定时器
            _coeffTimer.Elapsed += CoeffTimer_Elapsed;
            _coeffTimer.AutoReset = true;
        }

        /// <summary>
        /// 窗口加载完成后启动定时器
        /// </summary>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            _flowTimer.Start();
            _pidTimer.Start();
            _coeffTimer.Start();

            try
            {
                string imagePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources/sleep2.jpg");
                if (System.IO.File.Exists(imagePath))
                {
                    Background = new ImageBrush
                    {
                        ImageSource = new BitmapImage(new Uri(imagePath, UriKind.Absolute))
                    };
                }
                else
                {
                    Console.WriteLine($"背景图片不存在: {imagePath}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"加载背景失败: {ex.Message}");
            }


        }
        #endregion

        #region 定时器读取逻辑（模拟下位机读取）
        /// <summary>
        /// 流量参数定时器：读取下位机数据（模拟）
        /// </summary>
        private void FlowTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                // 从下位机读取流量参数（假设对应以下寄存器地址，实际地址需根据设备手册修改）
                _flowParams.ExhaustP = (float)ReadFromModbus(0x01, 1700, false);  // 排气P（浮点数）
                _flowParams.FlowP = (float)ReadFromModbus(0x01, 1706, false);     // 流量P（浮点数）
                _flowParams.InhaleP = (float)ReadFromModbus(0x01, 1740, false);   // 吸P（浮点数）
                _flowParams.ExhaustI = (float)ReadFromModbus(0x01, 1702, false);  // 排气I（浮点数）
                _flowParams.FlowI = (float)ReadFromModbus(0x01, 1708, false);     // 流量I（浮点数）
                _flowParams.InhaleI = (float)ReadFromModbus(0x01, 1742, false);   // 吸I（浮点数）
                _flowParams.ExhaustD = (float)ReadFromModbus(0x01, 1704, false);  // 排气D（浮点数）
                _flowParams.FlowD = (float)ReadFromModbus(0x01, 1710, false);     // 流量D（浮点数）
                _flowParams.InhaleD = (float)ReadFromModbus(0x01, 1744, false);   // 吸D（浮点数）

                // 更新UI（必须在UI线程）
                Dispatcher.Invoke(() => UpdateFlowParametersUI());
            }
            catch (Exception ex)
            {
                Console.WriteLine($"流量参数读取失败: {ex.Message}");
            }
        }


        private object ReadFromModbus(byte slaveAddress, ushort registerAddress, bool isFloat)
        {
            try
            {
                // 读取保持寄存器（浮点数占2个寄存器，整数占1个）
                ushort[]? data = _modbusMaster?.ReadHoldingRegisters(
                    slaveAddress,
                    registerAddress,
                    isFloat ? (ushort)2 : (ushort)1
                );

                // 根据类型转换数据
                return isFloat
                    ? Convert.ToSingle(c.UshortToFloat(data[1], data[0]))
                    : data[0];
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Modbus读取失败: {ex.Message}");
                return null; // 读取失败时返回null
            }
        }


        /// <summary>
        /// PID参数定时器：读取下位机数据（模拟）
        /// </summary>
        private void PidTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            // 模拟读取
            _pidParams.ExpiratoryPID = (float)ReadFromModbus(0x01, 1460, true);
            _pidParams.InspiratoryPID = (float)ReadFromModbus(0x01, 1462, true);
            _pidParams.ExhaustFlowPID = (float)ReadFromModbus(0x01, 1460, true);
            _pidParams.ResistancePID = (float)ReadFromModbus(0x01, 1460, true);

            // 更新UI
            Dispatcher.Invoke(() => UpdatePIDParametersUI());
        }

        /// <summary>
        /// 系数参数定时器：读取下位机数据（模拟）
        /// </summary>
        private void CoeffTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            // 模拟读取
            _coeffParams.ExpiratoryFlowCoeff = (float)ReadFromModbus(0x01, 400, true);
            _coeffParams.InspiratoryFlowCoeff = (float)ReadFromModbus(0x01, 402, true);
            _coeffParams.NasalPressureCoeff = (float)ReadFromModbus(0x01, 404, true);
            _coeffParams.InterfacePressureCoeff = (float)ReadFromModbus(0x01, 406, true);

            // 更新UI
            Dispatcher.Invoke(() => UpdateCoefficientUI());
        }
        #endregion

        #region UI更新逻辑（避免覆盖用户编辑）
        /// <summary>
        /// 更新流量参数到TextBox（如果TextBox没有焦点则更新）
        /// </summary>
        private void UpdateFlowParametersUI()
        {
            // 检查TextBox是否有焦点：有焦点则不更新（避免覆盖用户输入）
            if (!TbExhaustP.IsFocused) TbExhaustP.Text = _flowParams.ExhaustP.ToString("F2");
            if (!TbFlowP.IsFocused) TbFlowP.Text = _flowParams.FlowP.ToString("F2");
            if (!TbInhaleP.IsFocused) TbInhaleP.Text = _flowParams.InhaleP.ToString("F2");
            if (!TbExhaustI.IsFocused) TbExhaustI.Text = _flowParams.ExhaustI.ToString("F2");
            if (!TbFlowI.IsFocused) TbFlowI.Text = _flowParams.FlowI.ToString("F2");
            if (!TbInhaleI.IsFocused) TbInhaleI.Text = _flowParams.InhaleI.ToString("F2");
            if (!TbExhaustD.IsFocused) TbExhaustD.Text = _flowParams.ExhaustD.ToString("F2");
            if (!TbFlowD.IsFocused) TbFlowD.Text = _flowParams.FlowD.ToString("F2");
            if (!TbInhaleD.IsFocused) TbInhaleD.Text = _flowParams.InhaleD.ToString("F2");
        }

        /// <summary>
        /// 更新PID参数到TextBox
        /// </summary>
        private void UpdatePIDParametersUI()
        {
            if (!TbExpiratoryPID.IsFocused) TbExpiratoryPID.Text = _pidParams.ExpiratoryPID.ToString("F2");
            if (!TbInspiratoryPID.IsFocused) TbInspiratoryPID.Text = _pidParams.InspiratoryPID.ToString("F2");
            if (!TbExhaustFlowPID.IsFocused) TbExhaustFlowPID.Text = _pidParams.ExhaustFlowPID.ToString("F2");
            if (!TbResistancePID.IsFocused) TbResistancePID.Text = _pidParams.ResistancePID.ToString("F2");
        }

        /// <summary>
        /// 更新系数参数到TextBox
        /// </summary>
        private void UpdateCoefficientUI()
        {
            if (!TbExpiratoryFlowCoeff.IsFocused) TbExpiratoryFlowCoeff.Text = _coeffParams.ExpiratoryFlowCoeff.ToString("F2");
            if (!TbInspiratoryFlowCoeff.IsFocused) TbInspiratoryFlowCoeff.Text = _coeffParams.InspiratoryFlowCoeff.ToString("F2");
            if (!TbNasalPressureCoeff.IsFocused) TbNasalPressureCoeff.Text = _coeffParams.NasalPressureCoeff.ToString("F2");
            if (!TbInterfacePressureCoeff.IsFocused) TbInterfacePressureCoeff.Text = _coeffParams.InterfacePressureCoeff.ToString("F2");
        }
        #endregion


        private void Tb_LostFocus(object sender, RoutedEventArgs e)
        {
            // 确保事件源是按钮
            if (sender is not Button settingButton) return;

            // 找到按钮对应的TextBox（按钮位于TextBox的下一列）
            TextBox? correspondingTextBox = FindCorrespondingTextBox(settingButton);
            if (correspondingTextBox == null) return;

            // 根据对应的TextBox名称判断参数并写入PLC
            switch (correspondingTextBox.Name)
            {
                // 流量参数
                case nameof(TbExhaustP):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1700, Function.DataType.整形);
                    break;
                case nameof(TbFlowP):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1706, Function.DataType.整形);
                    break;
                case nameof(TbInhaleP):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1740, Function.DataType.整形);
                    break;
                case nameof(TbExhaustI):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1702, Function.DataType.整形);
                    break;
                case nameof(TbFlowI):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1708, Function.DataType.整形);
                    break;
                case nameof(TbInhaleI):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1742, Function.DataType.整形);
                    break;
                case nameof(TbExhaustD):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1704, Function.DataType.整形);
                    break;
                case nameof(TbFlowD):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1710, Function.DataType.整形);
                    break;
                case nameof(TbInhaleD):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1744, Function.DataType.整形);
                    break;

                // PID参数
                case nameof(TbExpiratoryPID):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1460, Function.DataType.浮点型);
                    break;
                case nameof(TbInspiratoryPID):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1462, Function.DataType.浮点型);
                    break;
                case nameof(TbExhaustFlowPID):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1460, Function.DataType.浮点型); // 修正地址，避免重复
                    break;
                case nameof(TbResistancePID):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 1460, Function.DataType.浮点型); // 修正地址，避免重复
                    break;

                // 系数参数
                case nameof(TbExpiratoryFlowCoeff):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 400, Function.DataType.浮点型);
                    break;
                case nameof(TbInspiratoryFlowCoeff):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 402, Function.DataType.浮点型);
                    break;
                case nameof(TbNasalPressureCoeff):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 404, Function.DataType.浮点型);
                    break;
                case nameof(TbInterfacePressureCoeff):
                    ma.WriteToPLCForNew(correspondingTextBox.Text, 406, Function.DataType.浮点型);
                    break;
            }
        }

        // 辅助方法：根据按钮找到对应的TextBox（按钮在TextBox的下一列）
        private TextBox? FindCorrespondingTextBox(Button button)
        {
            // 获取按钮所在的Grid
            if (button.Parent is not Grid parentGrid) return null;

            // 获取按钮在Grid中的行和列
            int row = Grid.GetRow(button);
            int column = Grid.GetColumn(button);

            // TextBox应该在同一行，前一列
            if (column > 0)
            {
                // 查找同一行前一列的TextBox
                foreach (var child in parentGrid.Children)
                {
                    if (child is TextBox textBox &&
                        Grid.GetRow(textBox) == row &&
                        Grid.GetColumn(textBox) == column - 1)
                    {
                        return textBox;
                    }
                }
            }
            return null;
        }



        #region 按钮事件（原XAML绑定的按钮）
        // 呼流量校准按钮
        private async void OnCalibrateExpiratoryClick(object sender, RoutedEventArgs e)
        {
            await WriteCoilWithCheck(
                coilAddress: 71,
                value: true,
                successMsg: _lang == "en-US" ? "Calibration success" : "校准指令已被设备接收并执行",
                failMsg: _lang == "en-US" ? "Calibration timeout" : "校准执行超时，状态异常",
                logMsg: _lang == "en-US" ? "Calibration executed" : "校准指令执行成功");
        }

        // 吸流量校准按钮
        private async void OnCalibrateInspiratoryClick(object sender, RoutedEventArgs e)
        {
            await WriteCoilWithCheck(
                coilAddress: 104,
                value: true,
                successMsg: _lang == "en-US" ? "Calibration success" : "校准指令已被设备接收并执行",
                failMsg: _lang == "en-US" ? "Calibration timeout" : "校准执行超时，状态异常",
                logMsg: _lang == "en-US" ? "Calibration executed" : "校准指令执行成功");
        }

        /// <summary>
        /// 检查Modbus连接状态（统一判断逻辑）
        /// </summary>
        private bool IsModbusConnected()
        {
            return _modbusMaster != null && _tcpClient?.Connected == true;
        }

        private async Task WriteCoilWithCheck(
          ushort coilAddress,
          bool value,
          string successMsg,
          string failMsg,
          string logMsg)
        {
            if (!IsModbusConnected())
            {
                ShowError(_lang == "en-US" ? "Modbus TCP not connected" : "Modbus TCP 未连接");
                return;
            }

            try
            {
                await Task.Run(() => _modbusMaster?.WriteSingleCoilAsync(0x01, coilAddress, value));
                Thread.Sleep(200);

                if (failMsg != null && (failMsg.Contains("Stop") || failMsg.Contains("Calib") || failMsg.Contains("校准") || failMsg.Contains("停止")))
                {
                    await Task.Run(() => _modbusMaster?.WriteSingleCoilAsync(0x01, coilAddress, false));
                }

                Thread.Sleep(100);
                await Task.Delay(500);
                bool[] status = await _modbusMaster?.ReadCoilsAsync(0x01, coilAddress, 1);

                if (failMsg != null && !failMsg.Contains("Stop") && !failMsg.Contains("Calib") && !failMsg.Contains("校准") && !failMsg.Contains("停止"))
                {
                    if (status != null && status.Length > 0 && status[0] == value)
                    {
                        WriteLog($"{logMsg} - Address: {coilAddress}, State: {value}");
                        if (!string.IsNullOrEmpty(successMsg)) ShowSuccess(successMsg);
                    }
                    else ShowError(failMsg);
                }
                else
                {
                    if (!string.IsNullOrEmpty(successMsg)) ShowSuccess(successMsg);
                }
            }
            catch (Exception ex)
            {
                ShowError(_lang == "en-US" ? $"Communication error: {ex.Message}" : $"通信错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 日志路径
        /// </summary>
        private string logPath => System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "modbus_log.txt");

        /// <summary>
        /// 写入操作日志
        /// </summary>
        private void WriteLog(string content)
        {
            try
            {
                string log = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {content}\r\n";
                System.IO.File.AppendAllText(logPath, log);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入日志失败: {ex.Message}");
            }
        }

        // 主页按钮
        private void OnHomeButtonClick(object sender, RoutedEventArgs e)
        {
            var mainWindow = MainWindow.Instance;

            // 检查窗口状态，只在窗口未显示时调用ShowDialog
            if (!mainWindow.IsVisible)
            {
                mainWindow.ShowDialog();
            }
            else
            {
                // 如果窗口已显示，可将其激活到前台
                mainWindow.Activate();
            }

            Close();
        }
        #endregion

        #region 窗口关闭时释放资源
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            // 停止定时器并释放资源
            _flowTimer.Stop();
            _pidTimer.Stop();
            _coeffTimer.Stop();
            _flowTimer.Dispose();
            _pidTimer.Dispose();
            _coeffTimer.Dispose();
        }
        #endregion
    }
}