using ASTM_D7896_Tester.Helpers;
using ASTM_D7896_Tester.Models;
using ASTM_D7896_Tester.Services;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace ASTM_D7896_Tester.ViewModels;

public partial class D7896ViewModel : ObservableObject
{
    private readonly IPlcService _plcService;
    private AppConfig _config;
    private readonly ReportService _reportService;

    // 电压表服务
    private Th1963LanService _th1963Ustd;   // 6位半测量标准电阻电压 U_std
    private Th1963LanService _th1953Ustd;   // 6位半测量标准电阻电压 U_std
    //private FiveHalfDmmService _fiveHalfUpt; // 5位半测量铂丝电压 U_pt

    private CancellationTokenSource _testCts; // 用于停止测试
    private bool _stopRequested;

    // 后台监控定时器
    private Timer? _monitorTimer;

    // 常量: 标准电阻值 1Ω
    private const double StandardResistor = 1.0;

    // 铂丝电阻温度系数 (纯铂)
    private const double AlphaPt = 0.00385; // /°C

    // 加热功率 Q 计算相关
    private double _heatingCurrent;   // 实际加热电流平均值
    private double _wireResistanceAvg; // 铂丝平均电阻

    // 温升曲线数据
    [ObservableProperty] private string _curveTitle = "温升曲线";
    [ObservableProperty] private PlotModel _temperatureCurveModel;

    // UI 绑定属性 (与之前一致)
    public ObservableCollection<string> ReferenceLiquids { get; } = new() { "蒸馏水", "甲苯", "乙二醇" };
    [ObservableProperty] private string _sampleId = "未命名样品";
    [ObservableProperty] private double _testTemperature = 25.0;
    [ObservableProperty] private string _testDateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    [ObservableProperty] private bool _isTesting = false;
    [ObservableProperty] private string _statusMessage = "就绪";
    [ObservableProperty] private int _currentMeasurementIndex = 0;
    [ObservableProperty] private ObservableCollection<MeasurementResult> _measurements = new();
    [ObservableProperty] private double _averageThermalConductivity;
    [ObservableProperty] private double _averageThermalDiffusivity;
    [ObservableProperty] private double _averageVolumetricHeatCapacity;

    [ObservableProperty] private double _sampleVolume = 40.0;
    [ObservableProperty] private bool _bubbleRemoved = true;
    [ObservableProperty] private bool _usePressure = false;
    [ObservableProperty] private double _pressureValue = 0.0;
    [ObservableProperty] private bool _isCleanConfirmed = true;
    [ObservableProperty] private string _cleanerName = "";
    [ObservableProperty] private double _ambientTemperature = 25.0;
    [ObservableProperty] private bool _ambientCalibrated = true;
    [ObservableProperty] private bool _platinumCompatible = true;
    [ObservableProperty] private string _liquidReactivityNote = "";

    [ObservableProperty] private double _platinumResistance = 0.0;
    [ObservableProperty] private double _chamberPressure = 0.0;
    [ObservableProperty] private double _currentTestTemperature = 0.0;

    [ObservableProperty] private bool _isCalibrating = false;
    [ObservableProperty] private string _calibrationStatus = "";
    [ObservableProperty] private string _selectedReferenceLiquid = "蒸馏水";
    [ObservableProperty] private double _referenceConductivity = 0.606;
    [ObservableProperty] private double _measuredConductivity = 0.0;
    [ObservableProperty] private double _calibrationErrorPercent = 0.0;

    // 实时电压显示（可选）
    [ObservableProperty] private double _platinumVoltage;
    [ObservableProperty] private double _standardResistorVoltage;


    private const double EulerGamma = 0.5772156649;   // 欧拉常数
    //private const double WireRadius = 0.00003;        // 铂丝半径 (0.03 mm)
    [ObservableProperty] private double _sampleDensity = 1000.0;   // 新增，密度默认值1000 kg/m³（水）
    int samples = 1000; // 1秒 * 1000点/秒
    double heatingDuration = 1;        // 加热时间 0.8 秒（需与您的加热脉冲宽度一致）
    double totalDuration = 2;            // 总采样时间（加热 + 冷却）
    public D7896ViewModel()
    {
        _config = App.PlcConfig ?? new AppConfig();
        _plcService = App.PlcService;
        _reportService = new ReportService(_config.TestParameters.ReportOutputPath);

        SampleVolume = _config.TestParameters.DefaultSampleVolume;
        UsePressure = _config.TestParameters.UsePressure;
        PressureValue = _config.TestParameters.DefaultPressure;
        SelectedReferenceLiquid = _config.TestParameters.ReferenceLiquid;
        ReferenceConductivity = _config.TestParameters.ReferenceConductivity;

        IsCleanConfirmed = true;
        BubbleRemoved = true;
        PlatinumCompatible = true;
        AmbientCalibrated = true;

        // 初始化电压表服务
        // TH1963 IP 地址需要根据实际配置修改，建议从配置文件读取
        _th1963Ustd = new Th1963LanService();

        _th1953Ustd = new Th1963LanService();

        StartBackgroundMonitoring();
    }

    private async void StartBackgroundMonitoring()
    {
        await Task.Delay(1000);
        _monitorTimer = new Timer(async _ => await MonitorPlcValues(), null, 0, 1000);
    }

    private async Task MonitorPlcValues()
    {
        if (!await _plcService.IsConnectedAsync()) return;
        if (Application.Current == null || Application.Current.Dispatcher == null) return;
        try
        {
            float rawResistance = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Resistance);
            double newResistance = rawResistance;
            Application.Current?.Dispatcher.Invoke(() => PlatinumResistance = newResistance);

            float rawPressure = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Pressure);
            Application.Current?.Dispatcher.Invoke(() => ChamberPressure = rawPressure);

            float rawTemp = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Temperature);
            Application.Current?.Dispatcher.Invoke(() => CurrentTestTemperature = rawTemp);
        }
        catch { }
    }

    //private async Task<double> GetInitialResistanceAsync()
    //{
    //    if (!await _plcService.IsConnectedAsync()) return 0;
    //    try
    //    {
    //        float rawResistance = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Resistance);
    //        return rawResistance;
    //    }
    //    catch { return 0; }
    //}

    [RelayCommand]
    private async Task StartTestAsync()
    {
        if (IsTesting)
        {
            MessageBox.Show("测试正在进行中", "提示");
            return;
        }

        // 前置检查
        if (!IsCleanConfirmed || !BubbleRemoved || !PlatinumCompatible || !AmbientCalibrated)
        {
            MessageBox.Show("请完成所有测试前确认项", "前置条件未满足");
            return;
        }
        if (SampleVolume <= 0)
        {
            MessageBox.Show("请输入有效的样品量", "参数错误");
            return;
        }
        if (UsePressure && PressureValue <= 0)
        {
            MessageBox.Show("请设置有效的加压值", "参数错误");
            return;
        }

        // 连接PLC和电压表
        if (!await _plcService.IsConnectedAsync())
        {
            if (!await _plcService.ConnectAsync())
            {
                MessageBox.Show("无法连接到PLC", "错误");
                return;
            }
        }

        try
        {





            await _th1963Ustd.ConnectAsync("192.168.1.12", 45454); // 改为实际IP
            await _th1963Ustd.ConfigureForHighSpeedDcvAsync();

            await _th1953Ustd.ConnectAsync("192.168.1.13", 45454); // 改为实际IP
            await _th1953Ustd.ConfigureForHighSpeedDcvAsync();
        }
        catch (Exception ex)
        {
            MessageBox.Show($"电压表连接失败: {ex.Message}", "错误");
            return;
        }

        if (UsePressure)
        {
            StatusMessage = "正在加压...";
            await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.InletValveCoil, true);

            const int pressureStableTimeoutMs = 10000; // 30秒超时
            const double pressureTolerance = 5.0;      // 允许误差 ±5 kPa
            var startTime = DateTime.Now;
            bool pressureReached = false;

            while ((DateTime.Now - startTime).TotalMilliseconds < pressureStableTimeoutMs)
            {
                await Task.Delay(500); // 每0.5秒检测一次
                await UpdateRealTimeParametersAsync();
                if (ChamberPressure >= PressureValue - pressureTolerance)
                {
                    pressureReached = true;
                    break;
                }
            }

            if (!pressureReached)
            {
                // 加压失败，关闭进气阀，中止测试
                await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.InletValveCoil, false);
                MessageBox.Show($"加压超时，压力未能达到 {PressureValue} kPa（当前 {ChamberPressure:F1} kPa）", "错误");
                return;
            }

            // 压力已达到，可关闭进气阀（或保持，看系统需求）
            await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.InletValveCoil, false);
            StatusMessage = $"压力已稳定在 {ChamberPressure:F1} kPa";
        }

        //double initialResistance = await GetInitialResistanceAsync();
        //if (initialResistance > 0)
        //    StatusMessage = $"初始电阻: {initialResistance:F4} Ω";

        Measurements.Clear();
        IsTesting = true;
        _stopRequested = false;
        _testCts = new CancellationTokenSource();

        try
        {

            // 预热：进行一次虚拟测量
            await _th1963Ustd.ConfigureForHighSpeedDcvAsync();
            await _th1963Ustd.PrepareBatchAsync(10);
            await _th1963Ustd.TriggerAsync();
            await Task.Delay(100);
            await _th1963Ustd.FetchBatchAsync(); // 丢弃结果


            // 预热：进行一次虚拟测量
            await _th1953Ustd.ConfigureForHighSpeedDcvAsync();
            await _th1953Ustd.PrepareBatchAsync(10);
            await _th1953Ustd.TriggerAsync();
            await Task.Delay(100);
            await _th1953Ustd.FetchBatchAsync(); // 丢弃结果





            int requiredCount = _config.TestParameters.MeasurementCount;   // 需要多少有效数据
            int validCount = 0;
            int attemptCount = 0;
            int maxAttempts = requiredCount * 2;   // 最多尝试次数，防止死循环

            // 存储每次成功测量的结果（用于后续异常判断）
            List<double> validLambdaList = new List<double>();
            List<double> validAlphaList = new List<double>();
            List<double> validCpList = new List<double>();

            while (validCount < requiredCount && attemptCount < maxAttempts && !_stopRequested)
            {
                attemptCount++;
                CurrentMeasurementIndex = attemptCount;   // 显示当前尝试次数（不是有效次数）
                StatusMessage = $"正在执行第 {attemptCount} 次测量（有效：{validCount}/{requiredCount}）...";

                // --- 步骤1：基线采集（加热前）---
                await _th1963Ustd.PrepareBatchAsync(50);
                await _th1953Ustd.PrepareBatchAsync(50);
                await Task.WhenAll(_th1963Ustd.TriggerAsync(), _th1953Ustd.TriggerAsync());
                await Task.Delay(100);
                double[] ustdBase = await _th1963Ustd.FetchBatchAsync();
                double[] uptBase = await _th1953Ustd.FetchBatchAsync();

                double dynamicR0 = 2.45; // 默认值
                if (ustdBase != null && ustdBase.Length > 0 && uptBase != null && uptBase.Length > 0)
                {
                    double sumR0 = 0; int cnt = 0;
                    for (int j = 0; j < ustdBase.Length; j++)
                    {
                        if (ustdBase[j] > 0.01 && uptBase[j] > 0.01)
                        {
                            sumR0 += uptBase[j] / ustdBase[j];
                            cnt++;
                        }
                    }
                    if (cnt > 0)
                    {
                        dynamicR0 = sumR0 / cnt;
                        Logger.Log($"基线采集 R0 = {dynamicR0:F6} Ω (有效点数: {cnt})");
                    }
                    else
                    {
                        Logger.Log("基线采集数据无效（电压过低），使用加热前瞬间点");
                    }
                }
                else
                {
                    Logger.Log("基线采集未返回数据，将使用加热段早期点");
                }

                // --- 步骤2：正式加热采集 ---
                await _th1963Ustd.PrepareBatchAsync(samples);
                await _th1953Ustd.PrepareBatchAsync(samples);

                await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.StartCommand, true);
                try { await Task.Delay(5, _testCts.Token); } catch (OperationCanceledException) { break; }

                await Task.WhenAll(_th1963Ustd.TriggerAsync(), _th1953Ustd.TriggerAsync());

                try { await Task.Delay((int)(heatingDuration * 1000), _testCts.Token); } catch (OperationCanceledException) { break; }
                await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.StartCommand, false);

                int remainingMs = (int)((totalDuration - heatingDuration) * 1000) + 100;
                try { await Task.Delay(remainingMs, _testCts.Token); } catch (OperationCanceledException) { break; }

                double[] ustd = await _th1963Ustd.FetchBatchAsync();
                double[] upt = await _th1953Ustd.FetchBatchAsync();

                if (dynamicR0 == 2.45) // 基线无效
                {
                    double sumR0 = 0; int cnt = 0;
                    for (int j = 2; j < Math.Min(6, ustd.Length); j++)
                    {
                        if (ustd[j] > 0.01 && upt[j] > 0.01)
                        {
                            sumR0 += upt[j] / ustd[j];
                            cnt++;
                        }
                    }
                    if (cnt > 0)
                    {
                        dynamicR0 = sumR0 / cnt;
                        Logger.Log($"使用加热段第2~5点计算 R0 = {dynamicR0:F6} Ω");
                    }
                }

                // 记录原始电压（调试用）
                for (int j = 0; j < 20 && j < ustd.Length; j++)
                {
                    Logger.Log($"第{j}点: U_std={ustd[j]:F6} V, U_pt={upt[j]:F6} V");
                }

                StandardResistorVoltage = ustd.Average();
                PlatinumVoltage = upt.Average();
                Logger.Log($"测量 {attemptCount}: U_std 平均值={ustd.Average():F6} V, U_pt 平均值={upt.Average():F6} V");

                double[] timeArray = new double[ustd.Length];
                for (int idx = 0; idx < timeArray.Length; idx++)
                    timeArray[idx] = idx * totalDuration / samples;

                var (lambda, alpha, deltaT, coolingPoints) = ComputeThermalProperties(upt, ustd, timeArray, dynamicR0, CurrentTestTemperature);

                // 计算比热容 Cp
                double vhc = lambda / alpha;   // kJ/(m³·K)
                double cp = vhc / SampleDensity; // J/(kg·K)

                Logger.Log($"测量 {attemptCount} 结果: λ={lambda:F6} W/(m·K), α={alpha:E6} m²/s, Cp={cp:F2} J/(kg·K)");

                // ---- 异常值检测 ----
                bool isOutlier = false;
                double deviationThreshold = 0.20; // 20% 偏差阈值

                if (validCount >= 2) // 至少有两个有效数据后才开始剔除
                {
                    double avgLambda = validLambdaList.Average();
                    double avgAlpha = validAlphaList.Average();
                    double avgCp = validCpList.Average();

                    if (Math.Abs(lambda - avgLambda) / avgLambda > deviationThreshold ||
                        Math.Abs(alpha - avgAlpha) / avgAlpha > deviationThreshold ||
                        Math.Abs(cp - avgCp) / avgCp > deviationThreshold)
                    {
                        isOutlier = true;
                        Logger.Log($"第 {attemptCount} 次测量结果异常（偏差过大），予以舍弃。λ={lambda:F4}, α={alpha:E4}, Cp={cp:F2}");
                    }
                }

                if (!isOutlier)
                {
                    // 正常结果，添加到列表
                    validLambdaList.Add(lambda);
                    validAlphaList.Add(alpha);
                    validCpList.Add(cp);
                    validCount++;

                    GenerateTemperatureCurveFromData(timeArray, deltaT, coolingPoints);

                    var result = new MeasurementResult
                    {
                        Index = validCount,   // 使用有效次数编号
                        ThermalConductivity = lambda,
                        ThermalDiffusivity = alpha
                    };
                    result.CalculateVhcAndCp(SampleDensity);
                    Application.Current.Dispatcher.Invoke(() => Measurements.Add(result));
                    StatusMessage = $"第 {validCount} 次测量完成，λ={lambda:F4} W/m·K";

                    Logger.Log($"========== 第 {validCount} 次测量详细数据 ==========");
                    Logger.Log($"热导率 λ: {lambda:F6} W/(m·K)");
                    Logger.Log($"热扩散率 α: {alpha:E6} m²/s");
                    Logger.Log($"体积热容 VHC: {result.VolumetricHeatCapacity:F2} kJ/(m³·K)");
                    Logger.Log($"比热容 Cp: {cp:F2} J/(kg·K)");
                    Logger.Log($"初始电阻 R0: {dynamicR0:F6} Ω");
                    Logger.Log("===========================================");
                }

                // 测量间隔（即使舍弃也等待，让样品恢复）
                if (validCount < requiredCount && !_stopRequested && attemptCount < maxAttempts)
                {
                    try { await Task.Delay(_config.TestParameters.IntervalSeconds * 500, _testCts.Token); } catch (OperationCanceledException) { break; }
                }
            }

            if (validCount >= requiredCount)
            {
                CalculateAverages();
                StatusMessage = "测试完成";
            }
            else
            {
                StatusMessage = $"测试中止。";
                MessageBox.Show($"测试中止，未收集到足够有效数据（{validCount}/{requiredCount}）。请检查样品或仪器状态。", "提示");
            }
        }
        catch (Exception ex)
        {
            StatusMessage = $"测试出错: {ex.Message}";
            MessageBox.Show($"测试过程中发生错误: {ex.Message}", "错误");
        }
        finally
        {
            // 停止加热，泄压
            await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.StartCommand, false);
            if (UsePressure)
            {
                await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.InletValveCoil, false);
                await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.OutletValveCoil, true);
                await Task.Delay(1000);
                await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.OutletValveCoil, false);
            }
            IsTesting = false;
            //_fiveHalfUpt.Close();
            _th1963Ustd.Dispose();
            _th1953Ustd.Dispose();
            _testCts?.Dispose();
        }
    }



    private (double lambda, double alpha, double[] deltaT, List<DataPoint> coolingPoints) ComputeThermalProperties(
        double[] upt, double[] ustd, double[] time, double initialResistance, double bathTemp)
    {
        int n = Math.Min(upt.Length, ustd.Length);
        double[] deltaT = new double[n];
        double[] ptResistance = new double[n];
        double[] current = new double[n];
        double tStart = _config.TestParameters.FitStartTime;
        double tEnd = _config.TestParameters.FitEndTime;

        // 1. 瞬时计算（先用传入的 initialResistance）
        for (int i = 0; i < n; i++)
        {
            current[i] = ustd[i] / StandardResistor;
            if (current[i] > 0.001)
            {
                ptResistance[i] = upt[i] / current[i];
                deltaT[i] = (ptResistance[i] - initialResistance) / (AlphaPt * initialResistance);
            }
            else
            {
                ptResistance[i] = double.NaN;
                deltaT[i] = double.NaN;
            }
        }

        // 滑动平均平滑（窗口5）
        double[] smoothDeltaT = new double[n];
        for (int i = 0; i < n; i++)
        {
            int start = Math.Max(0, i - 2);
            int end = Math.Min(n - 1, i + 2);
            double sum = 0; int cnt = 0;
            for (int j = start; j <= end; j++)
                if (!double.IsNaN(deltaT[j])) { sum += deltaT[j]; cnt++; }
            smoothDeltaT[i] = cnt > 0 ? sum / cnt : double.NaN;
        }

        // 寻找温升峰值点
        double maxDeltaT = 0;
        for (int i = 5; i < n; i++)
        {
            if (!double.IsNaN(smoothDeltaT[i]) && smoothDeltaT[i] > maxDeltaT)
                maxDeltaT = smoothDeltaT[i];
        }
        Logger.Log($"最大温升 = {maxDeltaT:F4} ℃");

        // 拟合窗口
        int startIdx = FindIndex(time, tStart);
        int endIdx = FindIndex(time, tEnd);
        if (startIdx < 0) startIdx = 5;
        if (endIdx >= n) endIdx = n - 1;
        if (endIdx <= startIdx) endIdx = Math.Min(startIdx + 50, n - 1);
        Logger.Log($"拟合窗口: startIdx={startIdx}, endIdx={endIdx}, 点数={endIdx - startIdx + 1}");

        // 收集拟合点
        var points = new List<DataPoint>();
        for (int i = startIdx; i <= endIdx; i++)
        {
            if (i <= startIdx + 5)  // 只打印前5个点
                Logger.Log($"i={i}, time={time[i]:F6}, smoothDeltaT={smoothDeltaT[i]:F6}, deltaT={deltaT[i]:F6}");
            if (!double.IsNaN(smoothDeltaT[i]) && smoothDeltaT[i] > 0 && time[i] > 0)
                points.Add(new DataPoint(Math.Log(time[i]), smoothDeltaT[i]));
        }

        if (points.Count < 10)
        {
            Logger.Log($"警告：有效拟合点数仅 {points.Count}，测量无效");
            return (0, 0, deltaT, new List<DataPoint>());
        }

        (double slope, double intercept) = LinearRegression(points);
        if (slope <= 0.001)
        {
            Logger.Log($"警告：拟合斜率 {slope:E} 过小或为负，测量无效");
            return (0, 0, deltaT, new List<DataPoint>());
        }

        // 打印前10个拟合点
        foreach (var p in points.Take(10))
            Logger.Log($"ln(t)={p.X:F4}, ΔT={p.Y:F4}");

        // 计算功率密度
        double sumI = 0, sumR = 0;
        int cntI = 0, cntR = 0;
        for (int i = startIdx; i <= endIdx; i++)
        {
            if (!double.IsNaN(current[i]) && Math.Abs(current[i]) > 1e-12) { sumI += current[i]; cntI++; }
            if (!double.IsNaN(ptResistance[i]) && ptResistance[i] > 1e-12) { sumR += ptResistance[i]; cntR++; }
        }
        if (cntI == 0 || cntR == 0) return (0, 0, deltaT, new List<DataPoint>());
        double avgCurrent = sumI / cntI;
        double avgResistance = sumR / cntR;
        double wireLength = Math.Max(1e-12, _config.TestParameters.PlatinumWireLength);
        double powerPerLength = (avgCurrent * avgCurrent * avgResistance) / wireLength;

        double lambda = powerPerLength / (4 * Math.PI * slope);
        if (_config.TestParameters.UseFixedLambda)
        {
            lambda = _config.TestParameters.FixedLambda;
            Logger.Log($"使用固定 lambda={lambda:F6} W/(m·K)");
        }
        Logger.Log($"constantCurrent(avg)={avgCurrent:E6} A, avgResistance={avgResistance:F6} Ω, powerPerLength={powerPerLength:E6} W/m, 斜率 B = {slope:F5}");

        // 计算热扩散率
        double exponent = intercept / slope + EulerGamma;
        if (exponent > 30) exponent = 30;
        double alpha = (_config.TestParameters.PlatinumWireDiameter / 2 * _config.TestParameters.PlatinumWireDiameter / 2 / 4.0) * Math.Exp(exponent);

        alpha *= _config.TestParameters.CalibrationCoefficients.ThermalConductivityCorrection;
        if (_config.TestParameters.UseFixedAlpha)
        {
            alpha = _config.TestParameters.FixedAlpha;
            Logger.Log($"使用固定 alpha={alpha:E6} m²/s");
        }
        if (alpha <= 0 || double.IsNaN(alpha) || alpha > 1e-5)
        {
            Logger.Log($"警告：α 计算异常 ({alpha:E})，数据可能不可靠");
            alpha = double.NaN;
        }
        Logger.Log($"热导率 λ = {lambda:F6} W/(m·K) | 热扩散率 α = {alpha:E6} m²/s | 截距/斜率 = {intercept / slope:F3}");

        // 冷却曲线
        var coolingPoints = new List<DataPoint>();
        int coolStart = FindIndex(time, heatingDuration);
        int coolEnd = FindIndex(time, totalDuration);
        for (int i = coolStart; i <= coolEnd; i++)
            if (!double.IsNaN(deltaT[i]) && deltaT[i] > 0.01)
                coolingPoints.Add(new DataPoint(time[i], deltaT[i]));

        // 导出CSV
        try
        {
            string tmp = Path.GetTempPath();
            string baseName = $"measure_{SampleId}_{DateTime.Now:yyyyMMdd_HHmmss}_{CurrentMeasurementIndex}";
            string dataPath = Path.Combine(tmp, baseName + ".csv");
            ExportMeasurementCsv(dataPath, time, ustd, upt, deltaT, startIdx, endIdx);
            Logger.Log($"已导出测量数据 CSV: {dataPath}");

            string winPath = Path.Combine(tmp, baseName + "_windows.csv");
            ExportCandidateWindowsCsv(winPath, time, deltaT, startIdx, endIdx);
            Logger.Log($"已导出候选拟合窗 CSV: {winPath}");
        }
        catch (Exception ex)
        {
            Logger.Log($"导出CSV失败: {ex.Message}");
        }

        return (lambda, alpha, deltaT, coolingPoints);
    }

    /// <summary>
    /// 最小二乘法线性回归，返回 (斜率, 截距)
    /// </summary>
    private (double slope, double intercept) LinearRegression(List<DataPoint> points)
    {
        if (points.Count < 2) return (0.001, 0);
        double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
        foreach (var p in points)
        {
            sumX += p.X;
            sumY += p.Y;
            sumXY += p.X * p.Y;
            sumX2 += p.X * p.X;
        }
        double n = points.Count;
        double denominator = n * sumX2 - sumX * sumX;
        if (Math.Abs(denominator) < 1e-10) return (0.001, 0);
        double slope = (n * sumXY - sumX * sumY) / denominator;
        double intercept = (sumY - slope * sumX) / n;
        return (slope, intercept);
    }

    /// <summary>
    /// 查找时间数组中与目标时间最接近的索引
    /// </summary>
    private int FindIndex(double[] timeArray, double targetTime)
    {
        for (int i = 0; i < timeArray.Length; i++)
        {
            if (timeArray[i] >= targetTime)
                return i;
        }
        return timeArray.Length - 1;
    }

    private void ExportMeasurementCsv(string path, double[] time, double[] ustd, double[] upt, double[] deltaT, int fitStart, int fitEnd)
    {
        using var sw = new StreamWriter(path, false, Encoding.UTF8);
        sw.WriteLine("index,time,U_std,U_pt,deltaT,fitWindow");
        int n = Math.Min(Math.Min(time.Length, ustd.Length), deltaT.Length);
        for (int i = 0; i < n; i++)
        {
            bool inFit = (i >= fitStart && i <= fitEnd);
            sw.WriteLine($"{i},{time[i]:F6},{ustd[i]:F6},{upt[i]:F6},{(double.IsNaN(deltaT[i]) ? 0 : deltaT[i]):F6},{(inFit ? 1 : 0)}");
        }
    }

    private void ExportCandidateWindowsCsv(string path, double[] time, double[] deltaT, int startIdx, int endIdx)
    {
        using var sw = new StreamWriter(path, false, Encoding.UTF8);
        sw.WriteLine("s,e,t_start,t_end,meanDelta");
        int n = time.Length;
        int minPts = 10;
        for (int s = startIdx; s <= endIdx - minPts; s++)
        {
            for (int e = s + minPts - 1; e <= endIdx; e++)
            {
                double mean = deltaT.Skip(s).Take(e - s + 1).Where(x => !double.IsNaN(x)).DefaultIfEmpty(0).Average();
                sw.WriteLine($"{s},{e},{time[s]:F6},{time[e]:F6},{mean:F6}");
            }
        }
    }

    ///// <summary>
    ///// 最小二乘法拟合斜率 (X轴为横坐标，Y轴为纵坐标) — 用于加热段 ln(t) vs ΔT
    ///// </summary>
    //private double LeastSquaresSlope(List<DataPoint> points)
    //{
    //    if (points.Count < 2) return 0.001;
    //    double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
    //    foreach (var p in points)
    //    {
    //        sumX += p.X;
    //        sumY += p.Y;
    //        sumXY += p.X * p.Y;
    //        sumX2 += p.X * p.X;
    //    }
    //    double n = points.Count;
    //    double denominator = n * sumX2 - sumX * sumX;
    //    if (Math.Abs(denominator) < 1e-10) return 0.001;
    //    double slope = (n * sumXY - sumX * sumY) / denominator;
    //    return slope;
    //}

    ///// <summary>
    ///// 最小二乘法拟合斜率 (X轴为时间t，Y轴为 ln(ΔT)) — 用于冷却段
    ///// </summary>
    //private double LeastSquaresSlopeOnTime(List<DataPoint> points)
    //{
    //    if (points.Count < 2) return -1.0;
    //    double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0;
    //    foreach (var p in points)
    //    {
    //        sumX += p.X;
    //        sumY += p.Y;
    //        sumXY += p.X * p.Y;
    //        sumX2 += p.X * p.X;
    //    }
    //    double n = points.Count;
    //    double denominator = n * sumX2 - sumX * sumX;
    //    if (Math.Abs(denominator) < 1e-10) return -1.0;
    //    double slope = (n * sumXY - sumX * sumY) / denominator;
    //    return slope;
    //}

    private void GenerateTemperatureCurveFromData(double[] time, double[] deltaT, List<DataPoint> coolingPoints)
    {
        if (TemperatureCurveModel == null)
        {
            TemperatureCurveModel = new PlotModel { Title = "温升与冷却曲线", Background = OxyColors.White };
            TemperatureCurveModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "时间 (s)" });
            TemperatureCurveModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = "温升 (℃)" });
        }

        // 根据当前测量索引计算色相 (0 ~ 1)
        double hue = ((CurrentMeasurementIndex - 1) % 10) / 10.0;   // 0, 0.1, 0.2 ... 0.9
                                                                    // 加热曲线颜色：饱和度0.9，亮度0.8
        var heatColor = OxyColor.FromHsv(hue, 0.9, 0.8);
        // 冷却曲线颜色：色相偏移0.5（互补色），饱和度0.6，亮度0.8（较淡）
        double coolHue = hue + 0.5;
        if (coolHue >= 1.0) coolHue -= 1.0;
        var coolColor = OxyColor.FromHsv(coolHue, 0.6, 0.8);

        // 加热段曲线（红色系实线）
        var heatingSeries = new LineSeries
        {
            Title = $"第{CurrentMeasurementIndex}次 - 加热",
            Color = heatColor,
            StrokeThickness = 1.5
        };
        for (int i = 0; i < time.Length && time[i] <= 1.0; i++)
        {
            heatingSeries.Points.Add(new DataPoint(time[i], deltaT[i]));
        }
        TemperatureCurveModel.Series.Add(heatingSeries);

        // 冷却曲线（互补色，虚线）
        if (coolingPoints != null && coolingPoints.Count > 0)
        {
            var coolingSeries = new LineSeries
            {
                Title = $"第{CurrentMeasurementIndex}次 - 冷却",
                Color = coolColor,
                StrokeThickness = 1.5,
                LineStyle = LineStyle.Dash
            };
            foreach (var p in coolingPoints)
            {
                coolingSeries.Points.Add(p);
            }
            TemperatureCurveModel.Series.Add(coolingSeries);
        }

        TemperatureCurveModel.InvalidatePlot(true);
        CurveTitle = $"已完成 {CurrentMeasurementIndex} 次测量";
    }


    private void CalculateAverages()
    {
        if (Measurements.Count == 0) return;
        AverageThermalConductivity = Measurements.Average(m => m.ThermalConductivity);
        AverageThermalDiffusivity = Measurements.Average(m => m.ThermalDiffusivity);
        AverageVolumetricHeatCapacity = Measurements.Average(m => m.VolumetricHeatCapacity);
    }

    [RelayCommand]
    private void Reset()
    {
        Measurements.Clear();
        AverageThermalConductivity = AverageThermalDiffusivity = AverageVolumetricHeatCapacity = 0;
        CurrentMeasurementIndex = 0;
        StatusMessage = "已重置";
        TestDateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        TemperatureCurveModel = null;
    }

    [RelayCommand]
    private async Task GenerateReportAsync()
    {
        if (Measurements.Count == 0)
        {
            MessageBox.Show("没有测试数据", "提示");
            return;
        }
        try
        {
            var extraParams = new Dictionary<string, object>
            {
                ["SampleVolume"] = SampleVolume,
                ["BubbleRemoved"] = BubbleRemoved,
                ["UsePressure"] = UsePressure,
                ["PressureValue"] = PressureValue,
                ["IsCleanConfirmed"] = IsCleanConfirmed,
                ["CleanerName"] = CleanerName,
                ["AmbientTemperature"] = AmbientTemperature,
                ["AmbientCalibrated"] = AmbientCalibrated,
                ["PlatinumCompatible"] = PlatinumCompatible,
                ["LiquidReactivityNote"] = LiquidReactivityNote,
                ["InitialResistance"] = PlatinumResistance
            };
            string reportPath = await _reportService.GenerateReportAsync(SampleId, TestTemperature, Measurements.ToList(),
                AverageThermalConductivity, AverageThermalDiffusivity, AverageVolumetricHeatCapacity,
                _config.TestParameters, extraParams);
            MessageBox.Show($"报告已生成: {reportPath}", "成功");
        }
        catch (Exception ex)
        {
            MessageBox.Show($"生成报告失败: {ex.Message}", "错误");
        }
    }



    [RelayCommand]
    private async Task StopTest()
    {
        if (!IsTesting) return;
        _stopRequested = true;
        _testCts?.Cancel();           // 取消所有等待的 Delay
        StatusMessage = "正在停止测试...";
        await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.StartCommand, false);
        if (UsePressure)
        {
            await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.InletValveCoil, false);
            await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.OutletValveCoil, true);
            await Task.Delay(1000);
            await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.OutletValveCoil, false);
        }
        IsTesting = false;
        StatusMessage = "测试已停止。";
    }
    [RelayCommand] private async Task PressureCalibrationAsync() => await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.PressureCalibrationCoil, true);
    [RelayCommand] private async Task ResistanceZeroAsync() => await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.ResistanceZeroCoil, true);
    [RelayCommand]
    private async Task InletValveControlAsync()
    {
        bool current = await _plcService.ReadCoilAsync(_config.PlcRegisterAddresses.InletValveCoil);
        await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.InletValveCoil, !current);
        StatusMessage = $"进气阀已{(current ? "关闭" : "开启")}";
    }
    [RelayCommand]
    private async Task OutletValveControlAsync()
    {
        bool current = await _plcService.ReadCoilAsync(_config.PlcRegisterAddresses.OutletValveCoil);
        await _plcService.WriteCoilAsync(_config.PlcRegisterAddresses.OutletValveCoil, !current);
        StatusMessage = $"排气阀已{(current ? "关闭" : "开启")}";
    }
    [RelayCommand] private void ConfirmBubbleRemoved() => BubbleRemoved = true;
    [RelayCommand]
    private void ConfirmClean()
    {
        if (string.IsNullOrWhiteSpace(CleanerName))
        {
            MessageBox.Show("请输入清洁人员姓名", "提示");
            return;
        }
        IsCleanConfirmed = true;
    }
    [RelayCommand] private void ConfirmPlatinumCompatible() => PlatinumCompatible = true;
    [RelayCommand]
    private async Task CalibrateAmbientAsync()
    {
        await EnsureConnected();
        float temp = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Temperature);
        AmbientTemperature = temp;
        AmbientCalibrated = true;
        StatusMessage = $"环境温度校准完成：{AmbientTemperature:F1} °C";
    }
    [RelayCommand] private async Task PerformSystemCalibrationAsync() { /* 系统校准逻辑待实现 */ }
    private async Task EnsureConnected()
    {
        if (!await _plcService.IsConnectedAsync())
            await _plcService.ConnectAsync();
    }
    private async Task UpdateRealTimeParametersAsync()
    {
        if (!await _plcService.IsConnectedAsync()) return;
        try
        {
            float rawPressure = await _plcService.ReadFloatAsync(_config.PlcRegisterAddresses.Pressure);
            ChamberPressure = rawPressure / 10.0;
        }
        catch { }
    }
}