using DeviceCommand.Devices;
using Prism.Commands;
using Prism.Ioc;
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using UIShare.GlobalVariable;
using UIShare.ViewModelBase;
using static DeviceCommand.Devices.SDS2000X_HD;

namespace DeviceEditModule.ViewModels
{
    /// <summary>
    /// SDS2000X_HD 数字存储示波器控制面板 ViewModel。
    /// </summary>
    public class SDS2000X_HDViewModel : NavigateViewModelBase, IDisposable
    {
        #region 私有字段

        private readonly DeviceManager _deviceManager;
        private SDS2000X_HD? _device;
        private CancellationTokenSource? _cts;

        #endregion

        #region 设备信息属性

        private string _deviceName = "SDS2000X_HD";
        public string DeviceName
        {
            get => _deviceName;
            set => SetProperty(ref _deviceName, value);
        }

        private bool _isConnected;
        public bool IsConnected
        {
            get => _isConnected;
            set => SetProperty(ref _isConnected, value);
        }

        private bool _isBusy;
        public bool IsBusy
        {
            get => _isBusy;
            set => SetProperty(ref _isBusy, value);
        }

        #endregion

        #region 输入参数属性

        private int _channel = 1;
        /// <summary>当前操作通道（1~4）。</summary>
        public int Channel
        {
            get => _channel;
            set => SetProperty(ref _channel, value);
        }

        private double _voltsPerDiv = 1.0;
        /// <summary>垂直电压档位（V/div）。</summary>
        public double VoltsPerDiv
        {
            get => _voltsPerDiv;
            set => SetProperty(ref _voltsPerDiv, value);
        }

        private double _offset = 0.0;
        /// <summary>垂直偏移（V）。</summary>
        public double Offset
        {
            get => _offset;
            set => SetProperty(ref _offset, value);
        }

        private bool _is50Ohm;
        /// <summary>是否使用 50Ω 输入阻抗，false 为 1MΩ。</summary>
        public bool Is50Ohm
        {
            get => _is50Ohm;
            set => SetProperty(ref _is50Ohm, value);
        }

        private double _timeBase = 0.001;
        /// <summary>水平时基档位（s/div）。</summary>
        public double TimeBase
        {
            get => _timeBase;
            set => SetProperty(ref _timeBase, value);
        }

        private double _triggerLevel = 0.0;
        /// <summary>触发电平（V）。</summary>
        public double TriggerLevel
        {
            get => _triggerLevel;
            set => SetProperty(ref _triggerLevel, value);
        }

        private string _triggerSource = "C1";
        /// <summary>触发源（C1/C2/C3/C4/EX/LINE）。</summary>
        public string TriggerSource
        {
            get => _triggerSource;
            set => SetProperty(ref _triggerSource, value);
        }

        #endregion

        #region 测量结果属性

        private string _measuredVpp = "—";
        public string MeasuredVpp
        {
            get => _measuredVpp;
            set => SetProperty(ref _measuredVpp, value);
        }

        private string _measuredFrequency = "—";
        public string MeasuredFrequency
        {
            get => _measuredFrequency;
            set => SetProperty(ref _measuredFrequency, value);
        }

        private string _measuredRms = "—";
        public string MeasuredRms
        {
            get => _measuredRms;
            set => SetProperty(ref _measuredRms, value);
        }

        private string _responseLog = string.Empty;
        /// <summary>命令响应日志（最新消息在顶部）。</summary>
        public string ResponseLog
        {
            get => _responseLog;
            set => SetProperty(ref _responseLog, value);
        }

        #endregion

        #region 命令

        public ICommand QueryIdentityCommand { get; }
        public ICommand ResetDeviceCommand { get; }
        public ICommand RunCommand { get; }
        public ICommand StopCommand { get; }
        public ICommand SingleCommand { get; }
        public ICommand ForceTriggerCommand { get; }
        public ICommand SetChannelOnCommand { get; }
        public ICommand SetChannelOffCommand { get; }
        public ICommand SetVoltsDivCommand { get; }
        public ICommand SetOffsetCommand { get; }

        // 🛠️ 补全：设置阻抗的 Command
        public ICommand SetImpedance50Command { get; }
        public ICommand SetImpedance1MCommand { get; }

        public ICommand SetTimeBaseCommand { get; }
        public ICommand SetTriggerLevelCommand { get; }
        public ICommand SetTriggerSourceCommand { get; }
        public ICommand QueryMeasurementsCommand { get; }
        public ICommand QueryVppCommand { get; }
        public ICommand QueryFrequencyCommand { get; }
        public ICommand QueryRmsCommand { get; }

        #endregion

        public SDS2000X_HDViewModel(IContainerProvider containerProvider) : base(containerProvider)
        {
            _deviceManager = containerProvider.Resolve<DeviceManager>();

            QueryIdentityCommand = new DelegateCommand(async () => await Exec(async () => AppendLog("IDN: " + await _device!.查询设备标识(Ct()))));
            ResetDeviceCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.重置设备(Ct()); AppendLog("设备已重置"); }));
            RunCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.启动捕获_RUN(Ct()); AppendLog("已开始捕获"); }));
            StopCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.停止捕获_STOP(Ct()); AppendLog("已停止捕获"); }));
            SingleCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.单次触发_SINGLE(Ct()); AppendLog("已触发单次捕获"); }));
            ForceTriggerCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.强制触发(Ct()); AppendLog("已强制触发"); }));
            SetChannelOnCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置通道开关(Channel, true, Ct()); AppendLog($"通道 {Channel} 已开启"); }));
            SetChannelOffCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置通道开关(Channel, false, Ct()); AppendLog($"通道 {Channel} 已关闭"); }));
            SetVoltsDivCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置通道电压档位(Channel, VoltsPerDiv, Ct()); AppendLog($"C{Channel} 电压档位已设为 {VoltsPerDiv} V/div"); }));
            SetOffsetCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置通道垂直偏移(Channel, Offset, Ct()); AppendLog($"C{Channel} 垂直偏移已设为 {Offset} V"); }));

            // 🛠️ 绑定：设置 50Ω 和 1MΩ 阻抗控制
            SetImpedance50Command = new DelegateCommand(async () => await Exec(async () =>
            {
                await _device!.设置通道阻抗(Channel, ImpedanceType.FIFty, Ct());
                Is50Ohm = true;
                AppendLog($"C{Channel} 输入阻抗已设为 50Ω");
            }));

            SetImpedance1MCommand = new DelegateCommand(async () => await Exec(async () =>
            {
                await _device!.设置通道阻抗(Channel, ImpedanceType.ONEM, Ct());
                Is50Ohm = false;
                AppendLog($"C{Channel} 输入阻抗已设为 1MΩ");
            }));

            SetTimeBaseCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置水平时基(TimeBase, Ct()); AppendLog($"水平时基已设为 {TimeBase} s/div"); }));
            SetTriggerLevelCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置触发电平(TriggerLevel, Ct()); AppendLog($"触发电平已设为 {TriggerLevel} V"); }));
            SetTriggerSourceCommand = new DelegateCommand(async () => await Exec(async () => { await _device!.设置触发源(TriggerSource, Ct()); AppendLog($"触发源已设为 {TriggerSource}"); }));

            QueryMeasurementsCommand = new DelegateCommand(async () => await Exec(async () =>
            {
                // 1. 保留设备原生吐出的完整原始字符串
                string rawVpp = await _device!.查询实际电压峰峰值(Channel, Ct());
                string rawFreq = await _device!.查询实际频率(Channel, Ct());
                string rawRms = await _device!.查询实际电压均方根(Channel, Ct());

                // 2. 清洗数据并将科学计数法转为常规小数后赋值给 UI 属性
                MeasuredVpp = ParseMeasurement(rawVpp);
                MeasuredFrequency = ParseMeasurement(rawFreq);
                MeasuredRms = ParseMeasurement(rawRms);

                // 3. 在日志中同时体现设备原始报文与解析呈现值，极方便联调
                AppendLog($"C{Channel} 测量原始数据 → Vpp:{rawVpp.Trim()} Freq:{rawFreq.Trim()} RMS:{rawRms.Trim()}");
                AppendLog($"C{Channel} 界面呈现数值 → Vpp:{MeasuredVpp}V Freq:{MeasuredFrequency}Hz RMS:{MeasuredRms}V");
            }));

            QueryVppCommand = new DelegateCommand(async () => await Exec(async () =>
            {
                string raw = await _device!.查询实际电压峰峰值(Channel, Ct());
                MeasuredVpp = ParseMeasurement(raw);
                AppendLog($"C{Channel} Vpp: {MeasuredVpp} (Raw: {raw.Trim()})");
            }));

            QueryFrequencyCommand = new DelegateCommand(async () => await Exec(async () =>
            {
                string raw = await _device!.查询实际频率(Channel, Ct());
                MeasuredFrequency = ParseMeasurement(raw);
                AppendLog($"C{Channel} Freq: {MeasuredFrequency} (Raw: {raw.Trim()})");
            }));

            QueryRmsCommand = new DelegateCommand(async () => await Exec(async () =>
            {
                string raw = await _device!.查询实际电压均方根(Channel, Ct());
                MeasuredRms = ParseMeasurement(raw);
                AppendLog($"C{Channel} RMS: {MeasuredRms} (Raw: {raw.Trim()})");
            }));

            Initialize();
        }

        #region 初始化 / Navigation

        public void Initialize(string? deviceName = null)
        {
            SDS2000X_HD? found = null;
            string? foundName = null;

            if (deviceName != null &&
                _deviceManager.DeviceMap.TryGetValue(deviceName, out var d) &&
                d is SDS2000X_HD s)
            {
                found = s;
                foundName = deviceName;
            }
            else
            {
                foreach (var kv in _deviceManager.DeviceMap)
                {
                    if (kv.Value is SDS2000X_HD sds)
                    {
                        found = sds;
                        foundName = kv.Key;
                        break;
                    }
                }
            }

            _device = found;
            DeviceName = foundName ?? "SDS2000X_HD (未找到)";
            IsConnected = _device?.IsConnected ?? false;

            AppendLog(found != null
                ? $"已关联设备 [{DeviceName}]，连接状态：{(IsConnected ? "已连接" : "未连接")}"
                : "未在 DeviceManager 中找到 SDS2000X_HD 设备，请先初始化设备配置。");
        }

        public override void OnNavigatedTo(NavigationContext context)
        {
            var name = context.Parameters.GetValue<string?>("DeviceName");
            Initialize(name);
        }

        #endregion

        #region 辅助

        private CancellationToken Ct() => (_cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))).Token;

        private async Task Exec(Func<Task> action)
        {
            if (_device == null)
            {
                AppendLog("错误：未关联到设备实例，请检查设备配置。");
                return;
            }
            if (IsBusy) return;
            IsBusy = true;
            try
            {
                await action();
                IsConnected = _device.IsConnected;
            }
            catch (OperationCanceledException)
            {
                AppendLog("命令超时或已取消。");
            }
            catch (Exception ex)
            {
                AppendLog($"错误：{ex.Message}");
            }
            finally
            {
                IsBusy = false;
            }
        }

        private void AppendLog(string message)
        {
            var line = $"[{DateTime.Now:HH:mm:ss}] {message}";
            ResponseLog = ResponseLog.Length > 4000
                ? line + "\n" + ResponseLog[..3000]
                : line + "\n" + ResponseLog;
        }

        /// <summary>
        /// 清洗示波器原始返回的测量字符串（例如 "C1:PAVA RMS,5.57E-03V"）并安全转化为无科学计数法的小数形式。
        /// </summary>
        /// <param name="rawResponse">设备原始应答数据</param>
        /// <returns>可直接绑定到 UI 呈现的字符串数字</returns>
        private string ParseMeasurement(string rawResponse)
        {
            if (string.IsNullOrWhiteSpace(rawResponse)) return "—";

            try
            {
                string cleanData = rawResponse.Trim();

                // 1. 斩断报头，提取逗号后面的具体内容（如 "5.57E-03V" 或 "****"）
                int commaIndex = cleanData.IndexOf(',');
                if (commaIndex == -1) return "—";

                string valStr = cleanData.Substring(commaIndex + 1);

                var match = Regex.Match(valStr, @"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?");
                if (match.Success)
                {
                    valStr = match.Value;
                }

                // 3. 校验并拦截设备未测出时的无效星号 "****"
                if (valStr.Contains("*") || string.IsNullOrWhiteSpace(valStr))
                {
                    return "0"; // 回归为零或 "—"，防止触发数据异常
                }

                // 4. 解析科学计数法，并重新以不带科学计数法的小数样式展开
                if (double.TryParse(valStr, NumberStyles.Any, CultureInfo.InvariantCulture, out double result))
                {
                    // "0.######" 样式会自动消除末尾无用的冗余零，并显示为普通小数（如 0.00557）
                    return result.ToString("0.######", CultureInfo.InvariantCulture);
                }
            }
            catch
            {
                // 捕获可能产生的边缘转换故障，保证轮询线程绝不崩溃
            }

            return "—";
        }

        #endregion

        public void Dispose()
        {
            _cts?.Cancel();
            _cts?.Dispose();
        }
    }
}