using Common.Attributes;
using DeviceCommand.Base;
using Model.Models;
using System;
using System.Globalization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DeviceCommand.Devices
{
    [ADPCommand]
    public class SDS2000X_HD : Tcp
    {
        // 示波器底层 Socket 字符串命令以换行符 \n 结束
        private const string ScpiDelimiter = "\n";

        /// <summary>
        /// 构造函数：传入 <see cref="TcpConfig"/> 一次性初始化示波器通信参数。
        /// </summary>
        public SDS2000X_HD(TcpConfig config) : base(config)
        {
        }

        #region 1. IEEE 488.2 公共命令

        /// <summary>
        /// 清除标准事件状态寄存器和错误队列
        /// </summary>
        public virtual async Task 清除状态(CancellationToken ct = default)
        {
            await SendAsync($"*CLS{ScpiDelimiter}", ct);
        }
        /// <summary>
        /// 查询错误信息
        /// </summary>
        public virtual async Task<string> 查询错误信息(CancellationToken ct = default)
        {
            return await WriteReadAsync($":SYSTem:ERRor?{ScpiDelimiter}", ScpiDelimiter, ct); //[cite: 1]
        }
        /// <summary>
        /// 读取示波器识别字符串（制造商、型号、序列号、固件版本）
        /// </summary>
        public virtual async Task<string> 查询设备标识(CancellationToken ct = default)
        {
            return await WriteReadAsync($"*IDN?{ScpiDelimiter}", ScpiDelimiter, ct);
        }

        /// <summary>
        /// 复位命令。使示波器恢复到默认的出厂设置
        /// </summary>
        public virtual async Task 重置设备(CancellationToken ct = default)
        {
            await SendAsync($"*RST{ScpiDelimiter}", ct);
        }

        /// <summary>
        /// 查询先前操作是否完成。
        /// </summary>
        public virtual async Task<bool> 检查操作完成_OPC(CancellationToken ct = default)
        {
            string res = await WriteReadAsync($"*OPC?{ScpiDelimiter}", ScpiDelimiter, ct);
            return res.Trim() == "1";
        }

        #endregion

        #region 2. 运行与捕获控制 (Run / Stop / Single)

        /// <summary>
        /// 控制示波器开始捕获波形
        /// </summary>
        public virtual async Task 启动捕获_RUN(CancellationToken ct = default)
        {
            await SendAsync($":TRIGger:RUN{ScpiDelimiter}", ct);
        }

        /// <summary>
        /// 停止捕获波形
        /// </summary>
        public virtual async Task 停止捕获_STOP(CancellationToken ct = default)
        {
            await SendAsync($"TRIGger:STOP{ScpiDelimiter}", ct);
        }

        /// <summary>
        /// 强制示波器进入单次触发捕获模式
        /// </summary>
        public virtual async Task 单次触发_SINGLE(CancellationToken ct = default)
        {
            await SendAsync($":TRIGger:MODE SINGle{ScpiDelimiter}", ct);
        }

        /// <summary>
        /// 触发一次波形采样
        /// </summary>
        public virtual async Task 强制触发(CancellationToken ct = default)
        {
            await SendAsync($"::TRIGger:MODE FTRIG{ScpiDelimiter}", ct);
        }
        /// <summary>
        /// 示波器触发控制模式（符合 SDS2000X-HD 规范）。
        /// </summary>
        public enum TriggerMode
        {
            /// <summary>
            /// 自动触发模式 (即使无触发信号也周期性刷屏)
            /// </summary>
            AUTO,

            /// <summary>
            /// 普通触发模式 (仅当满足触发条件时才刷新)
            /// </summary>
            NORM,

            /// <summary>
            /// 单次触发模式 (捕捉到一次满足条件的信号后立刻 STOP)
            /// </summary>
            SINGLE
        }
        /// <summary>
        /// 设置触发模式 (AUTO 自动, NORM 普通, SINGLE 单次)
        /// </summary>
        /// <param name="mode">触发模式枚举</param>
        /// <param name="ct">取消令牌</param>
        public virtual async Task 设置触发模式(TriggerMode mode, CancellationToken ct = default)
        {
            // 例如发送：TRMD AUTO\n、TRMD NORM\n 或 TRMD SINGLE\n
            string cmd = $"TRMD {mode}{ScpiDelimiter}";
            await SendAsync(cmd, ct);
        }
        #endregion

        #region 3. Channel 垂直控制子系统 (C1 ~ C4)

        /// <summary>
        /// 开启或关闭指定的模拟通道 (符合手册 57 页规范)
        /// </summary>
        public virtual async Task 设置通道开关(int channel, bool enable, CancellationToken ct = default)
        {
            string state = enable ? "ON" : "OFF";
            await SendAsync($"C{channel}:TRAce {state}{ScpiDelimiter}", ct);
        }

        /// <summary>
        /// 设置指定通道的垂直电压档位 (Volts/Div)
        /// </summary>
        public virtual async Task 设置通道电压档位(int channel, double volts, CancellationToken ct = default)
        {
            string cmd = string.Format(CultureInfo.InvariantCulture, "C{0}:VDIV {1:F4}{2}", channel, volts, ScpiDelimiter);
            await SendAsync(cmd, ct);
        }

        /// <summary>
        /// 查询指定通道当前的电压档位
        /// </summary>
        public virtual async Task<string> 查询通道电压档位(int channel, CancellationToken ct = default)
        {
            return await WriteReadAsync($"C{channel}:VDIV?{ScpiDelimiter}", ScpiDelimiter, ct);
        }

        /// <summary>
        /// 设置指定通道的垂直偏移量 (Offset)
        /// </summary>
        public virtual async Task 设置通道垂直偏移(int channel, double offset, CancellationToken ct = default)
        {
            string cmd = string.Format(CultureInfo.InvariantCulture, "C{0}:OFST {1:F4}{2}", channel, offset, ScpiDelimiter);
            await SendAsync(cmd, ct);
        }
        /// <summary>
        /// 示波器通道输入阻抗类型。
        /// </summary>
        public enum ImpedanceType
        {
            /// <summary>50Ω 阻抗</summary>
            FIFty,

            /// <summary>1MΩ 阻抗</summary>
            ONEM
        }
        public virtual async Task 设置通道阻抗(int channel, ImpedanceType impedance, CancellationToken ct = default)
        {
            // 例如发送：C1:IMPedance FIFty\n 或 C1:IMPedance ONEM\n
            string cmd = $"CHANnel{channel}:IMPedance {impedance}{ScpiDelimiter}";
            await SendAsync(cmd, ct);
        }

        #endregion

        #region 4. Timebase 水平时基子系统

        /// <summary>
        /// 设置示波器的水平时基档位 (Time/Div)
        /// </summary>
        public virtual async Task 设置水平时基(double scale, CancellationToken ct = default)
        {
            string cmd = string.Format(CultureInfo.InvariantCulture, "TDIV {0:E6}{1}", scale, ScpiDelimiter);
            await SendAsync(cmd, ct);
        }

        /// <summary>
        /// 设置示波器的触发水平延迟位置 (Horizontal Delay)
        /// </summary>
        public virtual async Task 设置水平延迟(double delay, CancellationToken ct = default)
        {
            string cmd = string.Format(CultureInfo.InvariantCulture, "TRDL {0:E6}{1}", delay, ScpiDelimiter);
            await SendAsync(cmd, ct);
        }

        #endregion

        #region 5. Trigger 触发子系统

        /// <summary>
        /// 设置边沿触发的电平值 (Trigger Level)
        /// </summary>
        public virtual async Task 设置触发电平(double level, CancellationToken ct = default)
        {

            string cmd = string.Format(CultureInfo.InvariantCulture, "TRIGger:EDGE:LEVel {0:F3}{1}", level, ScpiDelimiter);
            await SendAsync(cmd, ct);
        }

        /// <summary>
        /// 设置边沿触发的触发源 (例如: C1, C2, C3, C4, EX, LINE)
        /// </summary>
        public virtual async Task 设置触发源(string source, CancellationToken ct = default)
        {
            await SendAsync($"TRSE EDGE,SR,{source.ToUpper()}{ScpiDelimiter}", ct);
        }

        #endregion

        #region 6. Measure 自动测量参数回读

        /// <summary>
        /// 查询指定通道自动测量项的当前实时测量数值
        /// </summary>
        public virtual async Task<string> 查询通道测量项参数(int channel, string paramName, CancellationToken ct = default)
        {
            string query = string.Format(CultureInfo.InvariantCulture, "C{0}:PAVA? {1}{2}", channel, paramName.ToUpper(), ScpiDelimiter);
            return await WriteReadAsync(query, ScpiDelimiter, ct);
        }

        /// <summary>
        /// 查询指定通道的电压峰峰值 (Vpp)
        /// </summary>
        public virtual async Task<string> 查询实际电压峰峰值(int channel, CancellationToken ct = default)
        {
            return await 查询通道测量项参数(channel, "PKPK", ct);
        }

        /// <summary>
        /// 查询指定通道的频率值 (Frequency)
        /// </summary>
        public virtual async Task<string> 查询实际频率(int channel, CancellationToken ct = default)
        {
            return await 查询通道测量项参数(channel, "FREQ", ct);
        }

        /// <summary>
        /// 查询指定通道的真均方根电压值 (Vrms)
        /// </summary>
        public virtual async Task<string> 查询实际电压均方根(int channel, CancellationToken ct = default)
        {
            return await 查询通道测量项参数(channel, "RMS", ct);
        }

        #endregion

        #region 7. 屏幕截图导出子系统
        /// 【一键获取并保存截图】
        /// 自动下发 :PRINt? PNG 指令，接收示波器返回的纯 PNG 二进制流并直接保存到指定路径。
        /// </summary>
        /// <param name="saveFilePath">本地绝对保存路径 (例如: @"D:\Oscilloscope\Screen_01.png")</param>
        /// <param name="ct">取消令牌</param>
        /// <returns>返回是否获取并保存成功</returns>
        public virtual async Task<bool> 获取屏幕图像并保存(string saveFilePath, CancellationToken ct = default)
        {
            try
            {
                // 1. 调用我们在基类 Tcp 中全新实现的 ReadRawAsync
                // 它会在内部下发 ":PRINt? PNG\n"，自动接收完整的网络字节流
                byte[] pureImageBytes = await ReadAllBytesAsync($":PRINt? PNG{ScpiDelimiter}", ct);

                // 2. 校验返回数据
                if (pureImageBytes == null || pureImageBytes.Length < 8)
                {
                    System.Diagnostics.Debug.WriteLine("错误：接收到的图片数据为空或长度不足。");
                    return false;
                }

                // 3. 核心校验：验证是否为标准的 PNG 文件格式 (PNG 头通常为 89 50 4E 47)
                if (pureImageBytes[0] != 0x89 || pureImageBytes[1] != 'P' || pureImageBytes[2] != 'N' || pureImageBytes[3] != 'G')
                {
                    System.Diagnostics.Debug.WriteLine("错误：接收到的二进制数据不符合标准 PNG 格式头！");
                    return false;
                }

                // 4. 如果传入的目标文件夹路径不存在，自动帮其创建
                string directory = Path.GetDirectoryName(saveFilePath);
                if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                // 5. 使用文件流直接将 PNG 字节数据落地写入本地硬盘
                using (FileStream fs = new FileStream(saveFilePath, FileMode.Create, FileAccess.Write))
                {
                    await fs.WriteAsync(pureImageBytes, 0, pureImageBytes.Length, ct);
                    await fs.FlushAsync(ct); // 强制刷新，确保数据完整落地
                }

                System.Diagnostics.Debug.WriteLine($"成功：截图已保存至路径: {saveFilePath}");
                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"崩溃：保存截图时发生未知异常: {ex.Message}");
                return false;
            }
        }

        #endregion
    }
}