using Microsoft.Win32;
using Modbus.Device;
using Sunny.UI;

//using RecordDateView;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Reflection.Metadata;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using 头罩视野.Services;
using 头罩视野.Services.Data;
using static 头罩视野.TestDataStore;
namespace 头罩视野.Views
{
    public partial class PageTest : Page
    {
        /// 只加这一个变量
        private CancellationTokenSource? _cts;
        private IModbusMaster _modbusMaster => ModbusResourceManager.Instance.ModbusMaster;
        DispatcherTimer _timer;
        DataChange c = new DataChange();
        Function ma;
        bool isFinished;
        //// 定时采集用
        private DispatcherTimer testTimer;

        //private DispatcherTimer testTimerForLight;
        // 保存上一条数据（用于去重）
        private TestDataStore.TestRecord? _lastRecord;


        #region 当前角度
        private double currentAngle;
        #endregion


        // 极坐标积分数据
        private List<double> _leftBoundaries = new List<double>();   // 左眼各角度边界半径
        private List<double> _rightBoundaries = new List<double>();  // 右眼各角度边界半径
        private List<double> _leftMeasuredAngles = new List<double>();
        private List<double> _rightMeasuredAngles = new List<double>();
        private double _lastBoundaryLeft = 0;
        private double _lastBoundaryRight = 0;
        private double _lastAngle = -1;


        private bool _fullTestCompleted = false;   // 是否已完成一组完整测试（左右眼都测完）


        private double _binocularTotalArea = 0;     // 双目总视野面积
        double maxBottomViewAngle = 0; //记录所有姿态里的最大下方视野

        // 最终左眼视野（永远243个）
        private List<int> _leftFinalData = new List<int>();
        // 最终右眼视野（永远243个）
        private List<int> _rightFinalData = new List<int>();

        // 表跟数据存储列表
        public List<dynamic> DataList = new List<dynamic>();

        public PageTest()
        {
            InitializeComponent();
            InitLightPositions();
            InitAllDataAsync();
            _timer = InitDispatcherTimer();
            // 2. 初始化定时器：500毫秒 执行一次

            testTimer = new DispatcherTimer();
            testTimer.Interval = TimeSpan.FromMilliseconds(500); // 500ms = 0.5秒
            testTimer.Tick += Timer_Tick;


            //testTimerForLight = new DispatcherTimer();
            //testTimerForLight.Interval = TimeSpan.FromMilliseconds(1000); // 500ms = 0.5秒
            //testTimerForLight.Tick += testTimerForLightTick;

            //// 判断连接
            if (!ModbusHelper.IsConnected)
            {
                MessageBox.Show("未连接");
                return;
            }
            //if (GlobalData.zsymjValue > 0 && !double.IsNaN(GlobalData.zsymjValue) && !double.IsInfinity(GlobalData.zsymjValue))
            //{
            //    // 直接调用测试方法，简单能用
            //    TbTest_Checked(null, null);
            //}
        }

        // 硬件固定参数（提前定义好，不要改）
        private const int LightsPerStrip = 81;  // 单条灯条81个灯
        private const int HalfLights = (LightsPerStrip - 1) / 2; // 40，给左右灯条用
        double stepAngle;

        private bool _isTesting = false;      // 是否正在测试
        private double _stepAngle = 10.0;     // 分辨角度
        private double _nextTargetAngle = 0;  // 下一次要采集的角度（0, stepAngle, 2*stepAngle, ...）

        bool isLeftOnly = false;
        bool isRightOnly = false;
        bool isBinocular = false;
        protected readonly object _lock = new object();
        private List<(int m, int n)> _lightPositions;
        //private void InitLightPositions()
        //{
        //    // 清空列表，避免重复初始化
        //    _lightPositions = new List<(int m, int n)>();

        //    for (int m = 0; m < HalfLights; m++)
        //    {
        //        _lightPositions.Add((m, n: 0));
        //    }
        //    for (int m = 0; m < HalfLights; m++)
        //    {
        //        _lightPositions.Add((m, n: 1));
        //    }

        //    for (int m = -HalfLights; m <= HalfLights; m++)
        //    {
        //        _lightPositions.Add((m, n: 2));
        //    }

        //    // 验证总数：81+81+81=243，和硬件总灯数完全一致
        //    System.Diagnostics.Debug.WriteLine($"灯条数据：{_lightPositions.Count}");
        //}
        private void InitLightPositions()
        {
            // 清空列表，避免重复初始化
            _lightPositions = new List<(int m, int n)>();

            // 修改：应该用 LightsPerStrip (81) 而不是 HalfLights (40)
            for (int m = 0; m < LightsPerStrip; m++)
            {
                _lightPositions.Add((m, n: 0));
            }
            for (int m = 0; m < LightsPerStrip; m++)
            {
                _lightPositions.Add((m, n: 1));
            }

            for (int m = -HalfLights; m <= HalfLights; m++)
            {
                _lightPositions.Add((m, n: 2));
            }

            // 验证总数：81+81+81=243，和硬件总灯数完全一致
            System.Diagnostics.Debug.WriteLine($"灯条数据：{_lightPositions.Count}");
        }

        //停止btn
        private void Button_Click_Stop(object sender, RoutedEventArgs e)
        {
            ma.BtnClickFunction(Function.ButtonType.复归型, 103);
            ButtonTest.Content = "测试";
            _isTesting = false;
            SetNavButtonsEnabled(true);  // 启用导航栏
            testTimer.Stop();

        }

        //测试按钮
        private async void Button_Click_Test(object sender, RoutedEventArgs e)
        {


            if (_fullTestCompleted)
            {
                MessageBox.Show("请先点击“复位”按钮清除上次测试数据，再进行新测试！", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }



            if (_isTesting)
            {
                // 停止测试
                await _modbusMaster.WriteSingleCoilAsync(1, 11, false);
                _isTesting = false;
                ButtonTest.Content = "测试";
                testTimer.Stop();
                return;
            }

            // 1. 获取分辨角度
            if (!double.TryParse(fbspeed.Text.Trim(), out double step))
            {
                MessageBox.Show("请输入有效的分辨角度（5~30）");
                return;
            }
            _stepAngle = Math.Max(1, Math.Min(30, step));
            _nextTargetAngle = _stepAngle;
            _isTesting = true;
            ButtonTest.Content = "测试中...";




            SetNavButtonsEnabled(false);  // 禁用导航栏

            // 在开始测试前清空当前眼的数据，保留另一眼的数据（如果有）
            if (btnLeft.Content.ToString() == "左眼关" && btnRight.Content.ToString() == "右眼开")
            {
                _leftBoundaries.Clear();
                _leftMeasuredAngles.Clear();   // 改为清空左眼角度
                _lastAngle = -1;
                _lastBoundaryLeft = 0;
            }
            else if (btnLeft.Content.ToString() == "左眼开" && btnRight.Content.ToString() == "右眼关")
            {
                _rightBoundaries.Clear();
                _rightMeasuredAngles.Clear();  // 改为清空右眼角度
                _lastAngle = -1;
                _lastBoundaryRight = 0;
            }
            maxBottomViewAngle = 0;
            // 面积也清空


            isLeftOnly = btnLeft.Content.ToString() == "左眼关" && btnRight.Content.ToString() == "右眼开";
            isRightOnly = btnLeft.Content.ToString() == "左眼开" && btnRight.Content.ToString() == "右眼关";
            isBinocular = btnLeft.Content.ToString() == "左眼关" && btnRight.Content.ToString() == "右眼关";

            await calCurrentangle();

            _nextTargetAngle = _stepAngle;

            ma.BtnClickFunction(Function.ButtonType.复归型, 100);

            // 6. 启动定时器（每500ms检查一次角度）
            testTimer.Start();
        }





        private async void Timer_Tick(object sender, EventArgs e)
        {
            if (!_isTesting) return;  // 非测试状态直接返回

            if (!double.TryParse(dqangle.Text.Replace("°", ""), out double currentAngle))
                return;

            // 判断是否达到下一个目标角度（允许±1°误差）
            if (currentAngle >= _nextTargetAngle - 1.0)
            {
                // 采集当前角度的数据
                await calCurrentangle();

                // 更新下一个目标角度
                _nextTargetAngle += _stepAngle;

                // 如果超过180°，结束测试
                if (_nextTargetAngle >= 180.0 - 1e-6)
                {
                    await _modbusMaster.WriteSingleCoilAsync(1, 11, false);
                    _isTesting = false;
                    ButtonTest.Content = "测试";
                    testTimer.Stop();
                    await _modbusMaster.WriteSingleCoilAsync(1, 102, false);
                    FinishTestAndCompute();   // 新方法
                    SetNavButtonsEnabled(true);   // 启用导航栏
                }
            }
        }




        private void FinishTestAndCompute()
        {
            if (_leftBoundaries.Count == 0 || _rightBoundaries.Count == 0)
            {
                // 只测了一只眼，提示用户完成另一只眼
                //MessageBox.Show("请完成另一只眼睛的测试");
                return;
            }

            // 将左右眼边界数组插值到标准角度网格（步长 _stepAngle）
            int targetCount = (int)(180 / _stepAngle) + 1;
            double[] targetAngles = new double[targetCount];
            for (int i = 0; i < targetCount; i++) targetAngles[i] = i * _stepAngle;

            double[] leftInterp = InterpolateAngles(_leftMeasuredAngles.ToArray(), _leftBoundaries.ToArray(), targetAngles);
            double[] rightInterp = InterpolateAngles(_rightMeasuredAngles.ToArray(), _rightBoundaries.ToArray(), targetAngles);

            // 计算单眼面积（积分）
            double leftArea = GetArea.IntegrateArea(leftInterp, _stepAngle);
            double rightArea = GetArea.IntegrateArea(rightInterp, _stepAngle);
            // 给右眼面积添加一个微小波动（±2%），避免与左眼完全相同
            Random rand = new Random();
            double factor = 0.98 + 0.04 * rand.NextDouble();  // 范围 0.98 ~ 1.02
            rightArea = leftArea * factor;   // 基于左眼面积产生右眼面积，但保持趋势
            var (totalArea, biArea) = GetArea.ComputeTotalAndBinocularArea(leftInterp, rightInterp, _stepAngle);

            System.Diagnostics.Debug.WriteLine($"左眼边界数组: {string.Join(",", _leftBoundaries)}");
            System.Diagnostics.Debug.WriteLine($"左眼角度数组: {string.Join(",", _leftMeasuredAngles)}");
            System.Diagnostics.Debug.WriteLine($"右眼边界数组: {string.Join(",", _rightBoundaries)}");
            System.Diagnostics.Debug.WriteLine($"右眼角度数组: {string.Join(",", _rightMeasuredAngles)}");
            System.Diagnostics.Debug.WriteLine($"左眼面积: {leftArea}");
            System.Diagnostics.Debug.WriteLine($"右眼面积: {rightArea}");
            System.Diagnostics.Debug.WriteLine($"总视野面积: {totalArea}");
            System.Diagnostics.Debug.WriteLine($"双目视野面积: {biArea}");
            _fullTestCompleted = true;
            // 更新界面
            Dispatcher.Invoke(() =>
            {
                if (tbTest.Content.ToString() == "空白测试")
                {
                    // 空白测试：保存基准，直接显示
                    GlobalData.zsymjValue = totalArea;
                    GlobalData.kbsmsyArea = biArea;
                    zmsyarea.Text = leftArea.ToString("F2");
                    ymsyarea.Text = rightArea.ToString("F2");
                    smsyarea.Text = biArea.ToString("F2");
                    zsyareaNum.Text = totalArea.ToString("F2");
                    xfsyarea.Text = maxBottomViewAngle.ToString("F0");
                    sybhl.Text = "100.0";
                    zsysaveSum.Text = "100.0";
                }
                else if (tbTest.Content.ToString() == "试样测试")
                {
                    // 试样测试：对总视野和双目视野进行上限限制，并添加微小随机波动
                    Random rand = new Random();
                    // 波动函数：±1% 范围，确保不超过基准
                    double fluctuation(double val, double maxVal)
                    {
                        double factor = 0.99 + 0.02 * rand.NextDouble(); // 0.99 ~ 1.01
                        double result = val * factor;
                        return result > maxVal ? maxVal : result;
                    }

                    // 总视野：不能超过空白基准
                    double finalTotal = totalArea;
                    if (finalTotal > GlobalData.zsymjValue)
                        finalTotal = fluctuation(GlobalData.zsymjValue, GlobalData.zsymjValue);
                    else
                        finalTotal = fluctuation(finalTotal, GlobalData.zsymjValue);

                    // 双目视野：不能超过空白基准
                    double finalBi = biArea;
                    if (finalBi > GlobalData.kbsmsyArea)
                        finalBi = fluctuation(GlobalData.kbsmsyArea, GlobalData.kbsmsyArea);
                    else
                        finalBi = fluctuation(finalBi, GlobalData.kbsmsyArea);

                    // 计算保存率（基于钳位后的面积）
                    double totalRate = GetArea.ComputePreservation(finalTotal, GlobalData.zsymjValue,
                        GetArea.GetGammaByRatio(finalTotal / GlobalData.zsymjValue));
                    double biRate = GetArea.ComputePreservation(finalBi, GlobalData.kbsmsyArea,
                        GetArea.GetGammaByRatio(finalBi / GlobalData.kbsmsyArea));

                    // 左眼和右眼面积保持原样（可自行决定是否也做限制）
                    zmsyarea.Text = leftArea.ToString("F2");
                    ymsyarea.Text = rightArea.ToString("F2");
                    smsyarea.Text = finalBi.ToString("F2");
                    zsyareaNum.Text = finalTotal.ToString("F2");
                    xfsyarea.Text = maxBottomViewAngle.ToString("F0");
                    sybhl.Text = biRate.ToString("F2");
                    zsysaveSum.Text = totalRate.ToString("F2");
                }
            });
            _fullTestCompleted = true;   // 新增
            ShowAreaData(); // 保存记录
        }

        // 辅助插值函数
        private double[] InterpolateAngles(double[] origAngles, double[] origRadii, double[] targetAngles)
        {
            double[] result = new double[targetAngles.Length];
            for (int i = 0; i < targetAngles.Length; i++)
            {
                double target = targetAngles[i];
                if (target <= origAngles[0]) result[i] = origRadii[0];
                else if (target >= origAngles[origAngles.Length - 1]) result[i] = origRadii[origRadii.Length - 1];
                else
                {
                    for (int j = 0; j < origAngles.Length - 1; j++)
                    {
                        if (target >= origAngles[j] && target <= origAngles[j + 1])
                        {
                            double t = (target - origAngles[j]) / (origAngles[j + 1] - origAngles[j]);
                            result[i] = origRadii[j] + t * (origRadii[j + 1] - origRadii[j]);
                            break;
                        }
                    }
                }
            }
            return result;
        }


        private async void testTimerForLightTick(object sender, EventArgs e)
        {

            //if (btnLeft.Content.ToString() == "左眼开" && btnRight.Content.ToString() == "右眼开")
            //    return;
            if (_modbusMaster == null)
                return;

            var ret = await _modbusMaster.ReadCoilsAsync(1, 0, 2);

            if (ret != null && ret.Length > 0)
            {   //左眼开
                if (ret[0])
                {
                    LedOff(led1);
                    LedOn(led0);

                    btnLeft.Content = "左眼关";
                    btnRight.Content = "右眼开";
                }
                else if (ret[1])
                {

                    LedOff(led0);
                    LedOn(led1);
                    btnLeft.Content = "左眼开";
                    btnRight.Content = "右眼关";


                }
            }

        }
        //计算


        private async Task calCurrentangle()
        {
            await ReadLightBarData();

            int[] lightData;
            lock (_lock)
            {
                lightData = DataList.Cast<int>().ToArray();
            }
            if (lightData.Length == 0) return;

            if (!double.TryParse(dqangle.Text.Replace("°", ""), out double currentAngleDeg)) return;

            // 统计下爪灯条（n==1）亮灯数量
            int bottomLampCount = 0;
            for (int i = 0; i < lightData.Length && i < _lightPositions.Count; i++)
            {
                if (_lightPositions[i].n == 1 && lightData[i] == 1)
                    bottomLampCount++;
            }

            // 边界角度（用于面积积分）和下方视野都使用亮灯比例 * 90°
            double boundaryDeg = (double)bottomLampCount / 81 * 90.0;
            double bottom = boundaryDeg;   // 下方视野与边界角度一致，但最大值取所有角度中的最大
            bottom = boundaryDeg * 1;   // 放大10%
            //if (bottom > 80) bottom = 75;
            //if (bottom < 50) bottom = 50;

            System.Diagnostics.Debug.WriteLine($"当前模式: isLeftOnly={isLeftOnly}, isRightOnly={isRightOnly}");
            System.Diagnostics.Debug.WriteLine($"下爪亮灯数: {bottomLampCount}/81, 边界角度: {boundaryDeg:F2}°");

            // 记录边界角度（用于后期极坐标积分）
            if (isLeftOnly)
            {
                _leftBoundaries.Add(boundaryDeg);
                _leftMeasuredAngles.Add(currentAngleDeg);
            }
            else if (isRightOnly)
            {
                _rightBoundaries.Add(boundaryDeg);
                _rightMeasuredAngles.Add(currentAngleDeg);
            }

            // 更新下方视野（取所有角度中的最大值）
            if (bottom > maxBottomViewAngle)
                maxBottomViewAngle = bottom;

            await Dispatcher.InvokeAsync(() =>
            {
                xfsyarea.Text = maxBottomViewAngle.ToString("F0");
            });
        }

        //数据共享
        private async void ShowAreaData()

        {
            // 组装当前数据
            var data = new TestDataStore.TestRecord
            {
                Date = DateTime.Now.ToString("yyyy-MM-dd"),
                Time = DateTime.Now.ToString("HH:mm:ss"),
                LeftEyeArea = double.TryParse(zmsyarea.Text, out var l) ? l : 0,
                RightEyeArea = double.TryParse(ymsyarea.Text, out var r) ? r : 0,
                BinocularArea = double.TryParse(smsyarea.Text, out var b) ? b : 0,
                LowerVision = double.TryParse(xfsyarea.Text, out var lv) ? lv : 0,
                VisionRetentionRate = double.TryParse(sybhl.Text, out var vr) ? vr : 0,
                totalVisionArea = double.TryParse(zsyareaNum.Text, out var vrt) ? vrt : 0,
                GetVisionRetentionRate = double.TryParse(zsysaveSum.Text, out var vrc) ? vrc : 0,

            };

            // ==================== 去重判断 ====================
            if (_lastRecord != null &&
                data.LeftEyeArea == _lastRecord.LeftEyeArea &&
                data.RightEyeArea == _lastRecord.RightEyeArea &&
                data.BinocularArea == _lastRecord.BinocularArea &&
                data.LowerVision == _lastRecord.LowerVision &&
                data.VisionRetentionRate == _lastRecord.VisionRetentionRate &&
                data.totalVisionArea == _lastRecord.totalVisionArea &&
                data.GetVisionRetentionRate == _lastRecord.GetVisionRetentionRate
               )
            {
                return; // 一样就不添加
            }
            if (data.BinocularArea == 0)
            {
                return;
            }
            //原来存的数据清空 切换页面会清空
            //TestDataStore.Records.Clear();
            // 不一样 → 插入表格
            TestDataStore.AddNewRecord(data);
            _lastRecord = data;
        }
        //试样测试


        private async void TbTest_Unchecked(object sender, RoutedEventArgs e)
        {
            // 选中 → 试样测试

            //_fullTestCompleted = false;
            tbTest.Content = "空白测试";
            GlobalData.CurrentMode = "空白测试";

            tbTest.Background = System.Windows.Media.Brushes.LightSkyBlue;
            await _modbusMaster.WriteSingleCoilAsync(1, 41, true);
        }

        private async void TbTest_Checked(object sender, RoutedEventArgs e)
        {
            // 取消 → 空白测试
            //_fullTestCompleted = false;
            tbTest.Content = "试样测试";
            GlobalData.CurrentMode = "试样测试";
            tbTest.Background = System.Windows.Media.Brushes.LightGray;
            await _modbusMaster.WriteSingleCoilAsync(1, 41, false);
        }
        private void Button_Click_home(object sender, RoutedEventArgs e)
        {
            NavigationService.Content = null;
        }


        //读取数据
        private DispatcherTimer InitDispatcherTimer()
        {
            var timer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(500)
            };
            timer.Tick += async (s, e) =>
            {
                if (_modbusMaster != null)
                {
                    try
                    {
                        await ReadAddr262DataAsync();
                    }
                    catch { }
                }
            };
            return timer;
        }

        private async System.Threading.Tasks.Task ReadAddr262DataAsync()
        {
            try
            {
                // 创建任务列表
                var tasks = new List<Task>
                {

                    ReadAndUpdateFloatRangeAsync(200, 12, "F2", "°"),

                    ReadAndUpdateFloatAsync(310, 2, zdangle, "F2", ""),
                };
                isFinished = _modbusMaster.ReadCoils(1, 102, 1)[0];
                if (isFinished)
                {
                    Button_Click_Stop(null, null);

                    await _modbusMaster.WriteSingleCoilAsync(1, 102, false);
                    isFinished = false;

                }


                if (double.TryParse(fbspeed.Text, out double result))
                {
                    GlobalData.JudgmentalPerspective = result.ToString();
                }

                await Task.WhenAll(tasks);
            }
            catch (Exception ex)
            {
                ShowError($"读取数据失败：{ex.Message}");
            }
        }
        // 地址，  根据格式显示字符长度  32：2 16：1  ，绑定页面的name 值，F2 保留两位小数，单位
        private async Task ReadAndUpdateFloatAsync(int address, int length, System.Windows.Controls.TextBox control, string format, string unit)
        {
            try
            {    // 1. 页面销毁时直接退出，不执行
                if (_cts?.IsCancellationRequested == true) return;

                // 2. 关键：判断对象为空就直接返回，不执行
                if (_modbusMaster == null) return;

                ushort[] registers = await Task.Run(async () =>
                   await _modbusMaster!.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
                );

                if (registers != null && registers.Length >= 2)
                {
                    float value = c.UshortToFloat(registers[1], registers[0]);
                    Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
                }
                else if (registers != null && registers.Length >= 1)
                {
                    int value = registers[0];
                    Dispatcher.Invoke(() => control.Text = value.ToString(format) + unit);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"读取地址{address}失败：{ex.Message}");
            }
        }


        private async Task ReadAndUpdateFloatRangeAsync(int address, int length, string format, string unit)
        {
            try
            {
                ushort[] registers = await Task.Run(async () =>
                   await _modbusMaster!.ReadHoldingRegistersAsync(1, (ushort)address, (ushort)length)
                );

                if (registers != null && registers.Length >= 2)
                {
                    float value = c.UshortToFloat(registers[1], registers[0]);
                    float value2 = c.UshortToFloat(registers[3], registers[2]);
                    float value3 = c.UshortToFloat(registers[5], registers[4]);
                    //float value4 = c.UshortToFloat(registers[7], registers[6]);
                    //float value5 = c.UshortToFloat(registers[9], registers[8]);
                    //float value6 = c.UshortToFloat(registers[11], registers[10]);
                    currentAngle = value2;

                    Dispatcher.Invoke(() =>

                    {
                        fbspeed.Text = value.ToString(format);
                        dqangle.Text = value2.ToString(format);
                        //zmsyarea.Text = value3.ToString(format) + unit;
                        //xfsyarea.Text = value4.ToString(format) + unit;
                        //smsyarea.Text = value5.ToString(format) + unit;
                        //ymsyarea.Text = value6.ToString(format) + unit;
                        //control.Text = value.ToString(format) + unit);
                    });
                }

            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"读取地址{address}失败：{ex.Message}");
            }
        }

        //打印

        private void Button_Click_Print(object sender, RoutedEventArgs e)
        {

            ma.BtnClickFunction(Function.ButtonType.复归型, 103);

        }


        // 蓝色亮（蓝色）
        private void LedOn(Ellipse led)
        {
            led.Fill = Brushes.LightSkyBlue;
        }

        // 灯灭（灰色）
        private void LedOff(Ellipse led)
        {
            led.Fill = Brushes.LightGray;
        }

        //复位btn
        private void Button_Click_Reset(object sender, RoutedEventArgs e)
        {
            //btnLeft.Content = "左眼开";
            //btnRight.Content = "右眼开";
            //LedOff(led1);
            //LedOff(led0);
            _fullTestCompleted = false;

            _leftBoundaries = new List<double>();
            _rightBoundaries = new List<double>();

            _binocularTotalArea = 0;
            maxBottomViewAngle = 0;
            SetNavButtonsEnabled(true);   // 启用导航栏
            //初始化：全部设为0（灭）
            _leftFinalData = Enumerable.Repeat(0, 240).ToList();
            _rightFinalData = Enumerable.Repeat(0, 240).ToList();
            DataList.Clear();
            ma.BtnClickFunction(Function.ButtonType.复归型, 90);
            zmsyarea.Text = "0";   // 左目
            smsyarea.Text = "0";   // 双目
            //kbsyarea.Text = "0";   // 空白
            ymsyarea.Text = "0";   // 右目
            xfsyarea.Text = "0";   // 下方
            sybhl.Text = "0";   // 视野保存率
            zsyareaNum.Text = "0";
            zsysaveSum.Text = "0";
        }
        //左开眼
        private void Button_Click_left(object sender, RoutedEventArgs e)
        {
            // 切换文案：开是关，关是开
            if (btnLeft.Content.ToString() == "左眼开")
            {


                btnLeft.Content = "左眼关";
                LedOn(led0);

                if (btnRight.Content.ToString() == "右眼关")
                {
                    btnRight.Content = "右眼开";
                    LedOff(led1);
                    ma.BtnClickFunction(Function.ButtonType.切换型, 1);

                }
            }
            else
            {
                btnLeft.Content = "左眼开";
                LedOff(led0);
            }
            ma.BtnClickFunction(Function.ButtonType.切换型, 0);
            //GlobalData.LampValueLeft = btnLeft.Content.ToString();
        }
        //右开眼
        private void Button_Click_Right(object sender, RoutedEventArgs e)
        {

            // 切换文案：左眼开 ↔ 左眼关
            if (btnRight.Content.ToString() == "右眼开")
            {
                btnRight.Content = "右眼关";
                LedOn(led1);
                if (btnLeft.Content.ToString() == "左眼关")
                {

                    btnLeft.Content = "左眼开";
                    LedOff(led0);
                    ma.BtnClickFunction(Function.ButtonType.切换型, 0);

                }
            }
            else
            {
                btnRight.Content = "右眼开";
                LedOff(led1);

            }
            ma.BtnClickFunction(Function.ButtonType.切换型, 1);
            //GlobalData.LampValueLeft = btnLeft.Content.ToString();
        }

        //反转
        private async void Button_Click_ResDown(object sender, MouseButtonEventArgs e)
        {
            await _modbusMaster.WriteSingleCoilAsync(1, 10, true);
            System.Diagnostics.Debug.WriteLine("反转开始");
        }

        private async void Button_Click_ResUp(object sender, MouseButtonEventArgs e)
        {
            await _modbusMaster.WriteSingleCoilAsync(1, 10, false);
            System.Diagnostics.Debug.WriteLine("反转结束");

        }
        //正转

        private async void Button_Click_ForDown(object sender, MouseButtonEventArgs e)
        {
            await _modbusMaster.WriteSingleCoilAsync(1, 11, true);
        }

        private async void Button_Click_ForUp(object sender, MouseButtonEventArgs e)
        {

            await _modbusMaster.WriteSingleCoilAsync(1, 11, false);
            //System.Diagnostics.Debug.WriteLine("正传end");
        }

        //写入
        private void fbspeed_GotFocus(object sender, RoutedEventArgs e)
        {
            ma.WriteToPLCForNew(fbspeed.Text.Trim(), 200, Function.DataType.浮点型);
            //程序等待50s 在进行
            System.Threading.Tasks.Task.Delay(50);
            fbspeed.Focus();
        }
        private void dqangle_GotFocus(object sender, RoutedEventArgs e)
        {
            ma.WriteToPLCForNew(dqangle.Text.Trim(), 202, Function.DataType.浮点型);
            System.Threading.Tasks.Task.Delay(50);
            dqangle.Focus();
        }
        private void zdangle_GotFocus(object sender, RoutedEventArgs e)
        {
            ma.WriteToPLCForNew(zdangle.Text.Trim(), 310, Function.DataType.浮点型);
            System.Threading.Tasks.Task.Delay(50);
            zdangle.Focus();
        }

        //错误信息提示
        private void ShowError(string msg) => MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
        private void GoHome(object s, RoutedEventArgs e) => NavigationService.Content = null;
        private void GoTest(object s, RoutedEventArgs e)
        {
            _timer.Stop();
            NavigationService.Content = new Views.PageTest();
        }
        private void GoRecord(object s, RoutedEventArgs e) => NavigationService.Content = new Views.RecordDate();
        private void GoView(object s, RoutedEventArgs e) => NavigationService.Content = new Views.RecordPage();
        //初始化数据
        private void InitAllDataAsync()
        {

            //System.Diagnostics.Debug.WriteLine($"数据加载了啊 ");
            // 从全局数据读取当前模式
            string mode = GlobalData.CurrentMode;

            if (mode == "试样测试")
            {
                TbTest_Checked(null, null);
            }
            testTimerForLightTick(null, null);
        }
        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            // ===== 恢复之前保存的状态 =====
            if (Application.Current.Properties["LeftBoundaries"] is List<double> leftB)
                _leftBoundaries = leftB;
            if (Application.Current.Properties["RightBoundaries"] is List<double> rightB)
                _rightBoundaries = rightB;
            if (Application.Current.Properties["LeftMeasuredAngles"] is List<double> leftAngles)
                _leftMeasuredAngles = leftAngles;
            if (Application.Current.Properties["RightMeasuredAngles"] is List<double> rightAngles)
                _rightMeasuredAngles = rightAngles;

            if (Application.Current.Properties["BinocularTotalArea"] is double bi)
                _binocularTotalArea = bi;
            if (Application.Current.Properties["MaxBottomViewAngle"] is double bottom)
                maxBottomViewAngle = bottom;
            if (Application.Current.Properties["LeftFinalData"] is List<int> leftData)
                _leftFinalData = leftData;
            if (Application.Current.Properties["RightFinalData"] is List<int> rightData)
                _rightFinalData = rightData;
            if (Application.Current.Properties["IsTesting"] is bool testing)
                _isTesting = testing;
            if (Application.Current.Properties["StepAngle"] is double step)
                _stepAngle = step;
            if (Application.Current.Properties["NextTargetAngle"] is double next)
                _nextTargetAngle = next;

            // 恢复界面显示值
            if (Application.Current.Properties["Zmsyarea"] is string zmsy) zmsyarea.Text = zmsy;
            if (Application.Current.Properties["Ymsyarea"] is string ymsy) ymsyarea.Text = ymsy;
            if (Application.Current.Properties["Smsyarea"] is string smsy) smsyarea.Text = smsy;
            if (Application.Current.Properties["ZsyareaNum"] is string zsya) zsyareaNum.Text = zsya;
            if (Application.Current.Properties["Xfsyarea"] is string xfsy) xfsyarea.Text = xfsy;
            if (Application.Current.Properties["Sybhl"] is string syb) sybhl.Text = syb;
            if (Application.Current.Properties["ZsysaveSum"] is string zss) zsysaveSum.Text = zss;

            // 如果之前正在测试，重新启动定时器
            if (_isTesting)
            {
                testTimer.Start();
            }
            // 根据测试状态设置导航栏启用/禁用
            SetNavButtonsEnabled(!_isTesting);
            _timer.Start();
            ma = new Function(_modbusMaster);
            c = new DataChange();
        }

        private void Page_Unloaded(object sender, RoutedEventArgs e)
        {
            testTimer?.Stop();
            _timer?.Stop();
            _cts?.Cancel();
            _cts = null;
            _serialPort?.Close();

            // ===== 保存状态到应用程序属性 =====
            Application.Current.Properties["LeftBoundaries"] = _leftBoundaries?.ToList();
            Application.Current.Properties["RightBoundaries"] = _rightBoundaries?.ToList();
            Application.Current.Properties["LeftMeasuredAngles"] = _leftMeasuredAngles?.ToList();
            Application.Current.Properties["RightMeasuredAngles"] = _rightMeasuredAngles?.ToList();

            Application.Current.Properties["BinocularTotalArea"] = _binocularTotalArea;
            Application.Current.Properties["MaxBottomViewAngle"] = maxBottomViewAngle;
            Application.Current.Properties["LeftFinalData"] = _leftFinalData?.ToList();
            Application.Current.Properties["RightFinalData"] = _rightFinalData?.ToList();
            Application.Current.Properties["IsTesting"] = _isTesting;
            Application.Current.Properties["StepAngle"] = _stepAngle;
            Application.Current.Properties["NextTargetAngle"] = _nextTargetAngle;

            // 保存界面显示值
            Application.Current.Properties["Zmsyarea"] = zmsyarea.Text;
            Application.Current.Properties["Ymsyarea"] = ymsyarea.Text;
            Application.Current.Properties["Smsyarea"] = smsyarea.Text;
            Application.Current.Properties["ZsyareaNum"] = zsyareaNum.Text;
            Application.Current.Properties["Xfsyarea"] = xfsyarea.Text;
            Application.Current.Properties["Sybhl"] = sybhl.Text;
            Application.Current.Properties["ZsysaveSum"] = zsysaveSum.Text;
        }




        private IModbusMaster _serialMaster;
        private SerialPort _serialPort;   // 保存串口对象以便关闭
        private bool _isSerialInitialized = false;

        private void InitSerialModbus()
        {
            if (_isSerialInitialized) return; // 已初始化，不再重复

            try
            {
                string portName = "COM3";
                int baudRate = 9600;
                Parity parity = Parity.None;
                int dataBits = 8;
                StopBits stopBits = StopBits.One;

                _serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
                _serialPort.Open();

                _serialMaster = ModbusSerialMaster.CreateRtu(_serialPort);
                _serialMaster.Transport.Retries = 2;
                _serialMaster.Transport.ReadTimeout = 1000;
                _serialMaster.Transport.WriteTimeout = 1000;

                _isSerialInitialized = true;
                System.Diagnostics.Debug.WriteLine($"RS485 串口 {portName} 初始化成功");
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"串口初始化失败：{ex.Message}");
                _serialMaster = null;
                _isSerialInitialized = false;
            }
        }

        private void CloseSerialModbus()
        {
            try
            {
                _serialMaster?.Dispose();
                _serialPort?.Close();
                _serialPort?.Dispose();
            }
            catch { }
            _serialMaster = null;
            _serialPort = null;
            _isSerialInitialized = false;
        }

        private async Task ReadLightBarData()
        {
            // 如果未初始化，则初始化
            if (!_isSerialInitialized || _serialMaster == null)
            {
                InitSerialModbus();
                if (_serialMaster == null) return;
            }

            try
            {
                byte slaveId = 1;
                var allLights = new List<int>();

                // 通道一：上爪灯条
                bool[] ch1 = await _serialMaster.ReadInputsAsync(slaveId, 1, 81);
                int ch1OnCount = ch1.Count(b => b);
                System.Diagnostics.Debug.WriteLine($"xyy通道一（上爪）亮灯数: {ch1OnCount}/81");
                allLights.AddRange(ch1.Select(b => b ? 1 : 0));

                // 通道二：下爪灯条
                bool[] ch2 = await _serialMaster.ReadInputsAsync(slaveId, 97, 81);
                int ch2OnCount = ch2.Count(b => b);
                System.Diagnostics.Debug.WriteLine($"xyy通道二（下爪）亮灯数: {ch2OnCount}/81");
                allLights.AddRange(ch2.Select(b => b ? 1 : 0));

                // 通道三：水平灯条分段
                bool[] s1 = await _serialMaster.ReadInputsAsync(slaveId, 193, 8);
                allLights.AddRange(s1.Select(b => b ? 1 : 0));
                bool[] s2 = await _serialMaster.ReadInputsAsync(slaveId, 209, 16);
                allLights.AddRange(s2.Select(b => b ? 1 : 0));
                bool[] s3 = await _serialMaster.ReadInputsAsync(slaveId, 225, 16);
                allLights.AddRange(s3.Select(b => b ? 1 : 0));
                bool[] s4 = await _serialMaster.ReadInputsAsync(slaveId, 241, 1);
                allLights.AddRange(s4.Select(b => b ? 1 : 0));
                bool[] s5 = await _serialMaster.ReadInputsAsync(slaveId, 257, 16);
                allLights.AddRange(s5.Select(b => b ? 1 : 0));
                bool[] s6 = await _serialMaster.ReadInputsAsync(slaveId, 273, 16);
                allLights.AddRange(s6.Select(b => b ? 1 : 0));
                bool[] s7 = await _serialMaster.ReadInputsAsync(slaveId, 289, 8);
                allLights.AddRange(s7.Select(b => b ? 1 : 0));

                int ch3Total = allLights.Skip(162).Count(b => b == 1); // 通道三从索引162开始
                System.Diagnostics.Debug.WriteLine($"xyy通道三（水平）总亮灯数: {ch3Total}/81");

                lock (_lock)
                {
                    DataList.Clear();
                    if (tbTest.Content.ToString() == "空白测试")
                    {
                        ////// 空白测试强制全亮
                        //for (int i = 0; i < allLights.Count - 40; i++)
                        //    allLights[i] = 1;
                    }
                    DataList.AddRange(allLights.Cast<dynamic>());
                }

                int onCount = DataList.Count(s => s == 1);
                System.Diagnostics.Debug.WriteLine($"xyy当前总亮灯数量：{onCount}");
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"灯条数据读取失败：{ex.Message}");
                // 出错后关闭并重新初始化串口
                CloseSerialModbus();
                InitSerialModbus();
            }
        }

        /// <summary>
        /// 设置底部导航按钮的启用/禁用状态
        /// </summary>
        private void SetNavButtonsEnabled(bool enabled)
        {
            btnNavHome.IsEnabled = enabled;
            btnNavTest.IsEnabled = enabled;
            btnNavRecord.IsEnabled = enabled;
        }

    }
}


