using Microsoft.VisualBasic;
using PetroleumViscosityTest.Controls;
using PetroleumViscosityTest.Models;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace PetroleumViscosityTest
{
    public partial class MainWindow : Window
    {
        private ViscosityTestData currentData;
        private List<double> rawTimes = new List<double>();
        // --- 新增 Modbus 通信相关字段 ---
        private SerialPort serialPort;
        private System.Timers.Timer readTimer;
        private byte slaveId = 0x01;          // 从机地址，根据实际修改
        private readonly object portLock = new object();


        private System.Diagnostics.Stopwatch stopwatch1 = new System.Diagnostics.Stopwatch();
        private System.Diagnostics.Stopwatch stopwatch2 = new System.Diagnostics.Stopwatch();
        private System.Diagnostics.Stopwatch stopwatch3 = new System.Diagnostics.Stopwatch();
        private System.Diagnostics.Stopwatch stopwatch4 = new System.Diagnostics.Stopwatch();

        // 新增：四个 DispatcherTimer，用于实时更新
        private DispatcherTimer timer1 = new DispatcherTimer();
        private DispatcherTimer timer2 = new DispatcherTimer();
        private DispatcherTimer timer3 = new DispatcherTimer();
        private DispatcherTimer timer4 = new DispatcherTimer();
        // --------------------------------

        public MainWindow()
        {
            InitializeComponent();
            currentData = new ViscosityTestData();
            dpTestDate.SelectedDate = DateTime.Today;
            UpdateThermostatTime();

            // --- 新增：初始化串口通信 ---
            InitSerialPort();

            // 初始化 DispatcherTimer
            timer1.Interval = TimeSpan.FromMilliseconds(100);
            timer1.Tick += (s, e) => { txtTime1.Text = (stopwatch1.Elapsed.TotalSeconds).ToString("F3"); };

            timer2.Interval = TimeSpan.FromMilliseconds(100);
            timer2.Tick += (s, e) => { txtTime2.Text = (stopwatch2.Elapsed.TotalSeconds).ToString("F3"); };

            timer3.Interval = TimeSpan.FromMilliseconds(100);
            timer3.Tick += (s, e) => { txtTime3.Text = (stopwatch3.Elapsed.TotalSeconds).ToString("F3"); };

            timer4.Interval = TimeSpan.FromMilliseconds(100);
            timer4.Tick += (s, e) => { txtTime4.Text = (stopwatch4.Elapsed.TotalSeconds).ToString("F3"); };
            // --------------------------------
        }

        private void InitSerialPort()
        {
            try
            {
                serialPort = new SerialPort("COM7", 9600, Parity.None, 8, StopBits.One); // 请根据实际COM口修改
                serialPort.DataReceived += SerialPort_DataReceived;
                serialPort.Open();

                // 启动定时器，每隔 5 秒读取一次
                readTimer = new System.Timers.Timer(2000);
                readTimer.Elapsed += ReadTimer_Elapsed;
                readTimer.AutoReset = true;
                readTimer.Start();

                txtStatus.Text = "串口已打开，正在读取数据...";
            }
            catch (Exception ex)
            {
                MessageBox.Show($"串口打开失败: {ex.Message}\n请检查COM口号及连接。", "通信错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                txtStatus.Text = "串口打开失败";
            }
        }

        //private void ReadTimer_Elapsed(object sender, ElapsedEventArgs e)
        //{
        //    // 发送读保持寄存器指令：功能码 0x03，起始地址 0x0005，读取 2 个寄存器
        //    byte[] request = new byte[8];
        //    request[0] = slaveId;
        //    request[1] = 0x03;                     // 功能码
        //    request[2] = 0x00;                      // 起始地址高字节
        //    request[3] = 0x05;                      // 起始地址低字节 (0x0005)
        //    request[4] = 0x00;                      // 数量高字节
        //    request[5] = 0x02;                      // 数量低字节 (2 个寄存器)
        //    byte[] crc = CalculateCRC16(request, 6);
        //    request[6] = crc[0];
        //    request[7] = crc[1];

        //    lock (portLock)
        //    {
        //        if (serialPort != null && serialPort.IsOpen)
        //        {
        //            try
        //            {
        //                serialPort.Write(request, 0, request.Length);
        //            }
        //            catch (Exception ex)
        //            {
        //                Dispatcher.Invoke(() => txtStatus.Text = $"发送失败: {ex.Message}");
        //            }
        //        }
        //    }
        //}
        // 替换原有的 ReadTimer_Elapsed 方法
        private void ReadTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            lock (portLock)
            {
                if (serialPort == null || !serialPort.IsOpen) return;

                // 从 0x0000 开始读取 20 个寄存器
                byte[] request = new byte[8];
                request[0] = slaveId;
                request[1] = 0x03;
                request[2] = 0x00;
                request[3] = 0x00;      // 起始地址 0x0000
                request[4] = 0x00;
                request[5] = 0x14;      // 读取 20 个寄存器 (0x0000 ~ 0x0013)
                byte[] crc = CalculateCRC16(request, 6);
                request[6] = crc[0];
                request[7] = crc[1];

                try
                {
                    serialPort.Write(request, 0, request.Length);
                }
                catch { }
            }
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                System.Threading.Thread.Sleep(50);
                byte[] buffer = new byte[serialPort.BytesToRead];
                serialPort.Read(buffer, 0, buffer.Length);

                if (buffer.Length < 9 || buffer[0] != slaveId || buffer[1] != 0x03)
                    return;

                // 解析温度 (0x0005)
                int tempIndex = 3 + (0x0005 - 0x0000) * 2;
                ushort rawTemp = (ushort)((buffer[tempIndex] << 8) | buffer[tempIndex + 1]);
                double temp = rawTemp / 100.0;

                // 解析运行时间 (0x0007) - 这才是您要的恒温时间！
                int timeIndex = 3 + (0x0007 - 0x0000) * 2;
                ushort rawRunTime = (ushort)((buffer[timeIndex] << 8) | buffer[timeIndex + 1]);

                // 根据 0x000F 的值判断单位（0=分钟，1=小时）
                int unitIndex = 3 + (0x000F - 0x0000) * 2;
                ushort timeUnit = (ushort)((buffer[unitIndex] << 8) | buffer[unitIndex + 1]);

                int displayTime = rawRunTime;
                string unit = "分钟";
                if (timeUnit == 1)
                {
                    displayTime = rawRunTime; // 小时
                    unit = "小时";
                }

                Dispatcher.Invoke(() =>
                {
                    txtTestTemp.Text = temp.ToString("F2");

                    // 只有当运行时间 >0 时才显示，否则显示等待状态
                    if (rawRunTime > 0)
                    {
                        txtThermostatTime.Text = displayTime.ToString();
                        txtStatus.Text = $"温度: {temp:F2}℃  已运行: {displayTime} {unit}  时间单位寄存器: {timeUnit}";
                    }
                    else
                    {
                        txtThermostatTime.Text = "0";
                        txtStatus.Text = $"温度: {temp:F2}℃  等待启动... (运行时间=0)";
                    }
                });
            }
            catch (Exception ex)
            {
                Dispatcher.Invoke(() => txtStatus.Text = $"接收错误: {ex.Message}");
            }
        }

        //private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        //{
        //    try
        //    {
        //        System.Threading.Thread.Sleep(50); // 等待数据收完
        //        byte[] buffer = new byte[serialPort.BytesToRead];
        //        serialPort.Read(buffer, 0, buffer.Length);

        //        // 最小有效响应长度：地址(1) + 功能码(1) + 字节数(1) + 数据(2*2) + CRC(2) = 9
        //        if (buffer.Length < 9 || buffer[0] != slaveId || buffer[1] != 0x03)
        //            return;

        //        // 提取数据：温度寄存器 (0x0005) 和 运行时间寄存器 (0x0007)
        //        ushort rawTemp = (ushort)((buffer[3] << 8) | buffer[4]);
        //        ushort rawRunTime = (ushort)((buffer[5] << 8) | buffer[6]);

        //        double temp = rawTemp / 100.0;      // 协议规定小数点2位
        //        int runTimeMinutes = rawRunTime;    // 假设单位是分钟，直接显示

        //        // 更新 UI
        //        Dispatcher.Invoke(() =>
        //        {
        //            // 更新试验温度（如果希望保留手动输入能力，可添加判断条件，这里直接覆盖）
        //            txtTestTemp.Text = temp.ToString("F2");

        //            // 更新恒温时间
        //            txtThermostatTime.Text = runTimeMinutes.ToString();

        //            txtStatus.Text = $"实时温度: {temp:F2}℃  运行时间: {runTimeMinutes} min";
        //        });
        //    }
        //    catch (Exception ex)
        //    {
        //        Dispatcher.Invoke(() => txtStatus.Text = $"接收错误: {ex.Message}");
        //    }
        //}


        private byte[] CalculateCRC16(byte[] data, int length)
        {
            ushort crc = 0xFFFF;
            for (int pos = 0; pos < length; pos++)
            {
                crc ^= data[pos];
                for (int i = 8; i != 0; i--)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            return new byte[] { (byte)(crc & 0xFF), (byte)(crc >> 8) };
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            readTimer?.Stop();
            readTimer?.Dispose();
            if (serialPort != null && serialPort.IsOpen)
            {
                serialPort.Close();
                serialPort.Dispose();
            }
        }


        // 温度变化时自动更新恒温时间（表2）
        private void TxtTestTemp_TextChanged(object sender, TextChangedEventArgs e)
        {
            UpdateThermostatTime();
        }

        private void UpdateThermostatTime()
        {
            if (double.TryParse(txtTestTemp.Text, out double temp))
            {
                int time = Models.Constants.GetThermostatTime(temp);
                txtThermostatTime.Text = time.ToString();
            }
            else
            {
                txtThermostatTime.Text = "";
            }
        }

        // 加载示例数据
        private void BtnLoadExample_Click(object sender, RoutedEventArgs e)
        {
            txtSampleID.Text = "S2026-001";
            txtSampleName.Text = "润滑油";
            txtTestTemp.Text = "50";
            txtConstant.Text = "0.4780";
            txtDensity.Text = "0.85";
            txtOperator.Text = "张三";
            txtRemark.Text = "示例数据";

            txtTime1.Text = "322.4";
            txtTime2.Text = "322.6";
            txtTime3.Text = "321.0";
            txtTime4.Text = "";
            txtTime5.Text = "";
            txtTime6.Text = "";

            UpdateThermostatTime();
            txtStatus.Text = "示例数据已加载";
        }

        // 清空所有输入
        private void BtnClearAll_Click(object sender, RoutedEventArgs e)
        {
            txtSampleID.Clear();
            txtSampleName.Clear();
            txtTestTemp.Clear();
            txtConstant.Clear();
            txtDensity.Clear();
            txtOperator.Clear();
            txtRemark.Clear();
            txtTime1.Clear();
            txtTime2.Clear();
            txtTime3.Clear();
            txtTime4.Clear();
            txtTime5.Clear();
            txtTime6.Clear();
            txtAvgTime.Clear();
            txtViscosity.Clear();
            txtDynamicViscosity.Clear();
            txtValidCount.Clear();
            txtPrecisionJudge.Clear();
            txtRepeatability.Clear();
            txtReproducibility.Clear();
            txtMeasuredRepeatability.Clear();
            txtRepeatJudge.Clear();
            lstRawTimes.ItemsSource = null;
            rawTimes.Clear();

            // 停止并重置所有计时器
            timer1.Stop();
            timer2.Stop();
            timer3.Stop();
            timer4.Stop();
            stopwatch1.Reset();
            stopwatch2.Reset();
            stopwatch3.Reset();
            stopwatch4.Reset();





            txtStatus.Text = "已清空";
        }

        // 清空流动时间
        private void BtnClearTimes_Click(object sender, RoutedEventArgs e)
        {
            txtTime1.Clear();
            txtTime2.Clear();
            txtTime3.Clear();
            txtTime4.Clear();
            txtTime5.Clear();
            txtTime6.Clear();
            rawTimes.Clear();

            timer1.Stop();
            timer2.Stop();
            timer3.Stop();
            timer4.Stop();
            stopwatch1.Reset();
            stopwatch2.Reset();
            stopwatch3.Reset();
            stopwatch4.Reset();
            lstRawTimes.ItemsSource = null;
        }

        // 增加一次测量（在界面中添加更多输入框，为简化，我们已预留6个）
        private void BtnAddMeasurement_Click(object sender, RoutedEventArgs e)
        {
            // 本版本固定6个输入框，无需动态增加
            MessageBox.Show("已支持最多6次测量，请直接在对应框中输入。", "提示");
        }

        // 核心计算：运动粘度、动力粘度、精密度
        private void BtnCalcViscosity_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // 1. 读取流动时间
                rawTimes = GetTimeValues();
                if (rawTimes.Count < 4)
                {
                    MessageBox.Show("至少需要输入4次流动时间！", "数据不足", MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }

                // 2. 读取常数、密度、温度
                if (!double.TryParse(txtConstant.Text, out double constant))
                {
                    MessageBox.Show("请输入有效的粘度计常数 C", "参数错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }
                if (!double.TryParse(txtTestTemp.Text, out double temp))
                {
                    MessageBox.Show("请输入试验温度", "参数错误", MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }
                double density = 0;
                if (!string.IsNullOrWhiteSpace(txtDensity.Text))
                {
                    if (!double.TryParse(txtDensity.Text, out density))
                    {
                        MessageBox.Show("密度格式错误，将不计算动力粘度", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                    }
                }

                // 3. 根据温度获取允许偏差（%）
                double allowedDeviationPercent = Models.Constants.GetAllowedDeviation(temp);
                double allowedDeviation = 0;

                // 4. 计算平均值、筛选有效数据
                List<double> validTimes = new List<double>();
                double avg = rawTimes.Average();
                bool continueCalc = true;
                int maxIterations = 10; // 防止死循环
                while (continueCalc && maxIterations-- > 0)
                {
                    validTimes = rawTimes.Where(t => Math.Abs(t - avg) <= avg * allowedDeviationPercent / 100.0).ToList();
                    if (validTimes.Count >= 3)
                    {
                        double newAvg = validTimes.Average();
                        if (Math.Abs(newAvg - avg) < 0.0001)
                            continueCalc = false;
                        else
                            avg = newAvg;
                    }
                    else
                    {
                        break;
                    }
                }

                if (validTimes.Count < 3)
                {
                    MessageBox.Show("有效测量次数不足3次，无法计算！请检查数据是否离散过大。", "精密度超差", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                double finalAvg = validTimes.Average();

                // 5. 计算运动粘度
                double viscosity = constant * finalAvg;

                // 6. 计算动力粘度（如果有密度）
                double dynamicViscosity = 0;
                if (density > 0)
                {
                    dynamicViscosity = viscosity * density;
                }

                // 7. 计算本次测量的重复性（相对极差）
                double measuredRepeatability = 0;
                if (validTimes.Count > 1)
                {
                    measuredRepeatability = (validTimes.Max() - validTimes.Min()) / finalAvg * 100;
                }

                // 8. 获取标准重复性限
                double stdRepeatability = Models.Constants.GetRepeatabilityLimit(temp);

                // 9. 更新UI
                txtAvgTime.Text = finalAvg.ToString("F3");
                txtViscosity.Text = viscosity.ToString("F4"); // 四位有效数字
                if (density > 0)
                    txtDynamicViscosity.Text = dynamicViscosity.ToString("F4");
                else
                    txtDynamicViscosity.Text = "未计算";
                txtValidCount.Text = $"{validTimes.Count} / {rawTimes.Count}";
                txtMeasuredRepeatability.Text = measuredRepeatability.ToString("F2") + "%";
                txtRepeatability.Text = stdRepeatability.ToString("F1") + "%";
                txtReproducibility.Text = Models.Constants.GetReproducibilityLimit(temp).ToString("F1") + "%";

                bool repeatOK = measuredRepeatability <= stdRepeatability;
                txtRepeatJudge.Text = repeatOK ? "合格" : $"超差 (允许 ≤ {stdRepeatability:F1}%)";
                txtRepeatJudge.Foreground = repeatOK ? System.Windows.Media.Brushes.Green : System.Windows.Media.Brushes.Red;

                txtPrecisionJudge.Text = repeatOK ? "精密度符合要求" : "精密度不符合要求，建议重新测试";

                // 10. 显示原始数据
                lstRawTimes.ItemsSource = rawTimes.Select((t, i) => new { Display = $"第{i + 1}次: {t:F3}s" }).ToList();

                // 11. 保存当前数据到模型
                currentData.SampleID = txtSampleID.Text;
                currentData.SampleName = txtSampleName.Text;
                currentData.TestTemp = temp;
                currentData.Constant = constant;
                currentData.Density = density > 0 ? density : (double?)null;
                currentData.RawTimes = rawTimes;
                currentData.ValidTimes = validTimes;
                currentData.AvgTime = finalAvg;
                currentData.Viscosity = viscosity;
                currentData.DynamicViscosity = dynamicViscosity;
                currentData.Operator = txtOperator.Text;
                currentData.TestDate = dpTestDate.SelectedDate ?? DateTime.Now;
                currentData.Remark = txtRemark.Text;
                currentData.Repeatability = measuredRepeatability;
                currentData.IsRepeatabilityOK = repeatOK;

                txtStatus.Text = $"计算完成，有效次数 {validTimes.Count}，运动粘度 {viscosity:G4} mm²/s";
            }
            catch (Exception ex)
            {
                MessageBox.Show($"计算错误: {ex.Message}", "异常", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        // 从文本框获取流动时间列表
        private List<double> GetTimeValues()
        {
            var list = new List<double>();
            AddIfValid(txtTime1, list);
            AddIfValid(txtTime2, list);
            AddIfValid(txtTime3, list);
            AddIfValid(txtTime4, list);
            AddIfValid(txtTime5, list);
            AddIfValid(txtTime6, list);
            return list;
        }

        private void AddIfValid(TextBox tb, List<double> list)
        {
            if (!string.IsNullOrWhiteSpace(tb.Text) && double.TryParse(tb.Text, out double val))
            {
                list.Add(val);
            }
        }

        // 生成原始记录
        private void BtnGenRecord_Click(object sender, RoutedEventArgs e)
        {
            if (currentData.Viscosity <= 0)
            {
                MessageBox.Show("请先计算运动粘度！", "无数据", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            var record = new TestRecordControl();
            record.LoadData(currentData);
            ReportContent.Content = record;
        }

        // 生成测试报告
        private void BtnGenReport_Click(object sender, RoutedEventArgs e)
        {
            if (currentData.Viscosity <= 0)
            {
                MessageBox.Show("请先计算运动粘度！", "无数据", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            var report = new TestReportControl();
            report.LoadData(currentData);
            ReportContent.Content = report;
        }

        // 打印预览
        private void BtnPrintPreview_Click(object sender, RoutedEventArgs e)
        {
            if (ReportContent.Content == null)
            {
                MessageBox.Show("请先生成记录或报告", "无报表", MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }
            if (ReportContent.Content is FrameworkElement visual)
            {
                PrintDialog printDialog = new PrintDialog();
                if (printDialog.ShowDialog() == true)
                {
                    printDialog.PrintVisual(visual, "粘度测试报表");
                }
            }
        }

        // 第1次
        private void BtnStart1_Click(object sender, RoutedEventArgs e)
        {
            timer1.Stop();
            stopwatch1.Reset();
            stopwatch1.Start();
            timer1.Start();
        }

        private void BtnStop1_Click(object sender, RoutedEventArgs e)
        {
            timer1.Stop();
            stopwatch1.Stop();
            txtTime1.Text = (stopwatch1.Elapsed.TotalSeconds).ToString("F3");
        }

        // 第2次
        private void BtnStart2_Click(object sender, RoutedEventArgs e)
        {
            timer2.Stop();
            stopwatch2.Reset();
            stopwatch2.Start();
            timer2.Start();
        }

        private void BtnStop2_Click(object sender, RoutedEventArgs e)
        {
            timer2.Stop();
            stopwatch2.Stop();
            txtTime2.Text = (stopwatch2.Elapsed.TotalSeconds).ToString("F3");
        }

        // 第3次
        private void BtnStart3_Click(object sender, RoutedEventArgs e)
        {
            timer3.Stop();
            stopwatch3.Reset();
            stopwatch3.Start();
            timer3.Start();
        }

        private void BtnStop3_Click(object sender, RoutedEventArgs e)
        {
            timer3.Stop();
            stopwatch3.Stop();
            txtTime3.Text = (stopwatch3.Elapsed.TotalSeconds).ToString("F3");
        }

        // 第4次
        private void BtnStart4_Click(object sender, RoutedEventArgs e)
        {
            timer4.Stop();
            stopwatch4.Reset();
            stopwatch4.Start();
            timer4.Start();
        }

        private void BtnStop4_Click(object sender, RoutedEventArgs e)
        {
            timer4.Stop();
            stopwatch4.Stop();
            txtTime4.Text = (stopwatch4.Elapsed.TotalSeconds).ToString("F3");
        }
    }
}