using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ASTM_D7896_Tester.Services
{
    /// <summary>
    /// 基于 LAN (TCP/IP) 的 TH1963 数字多用表通信服务
    /// 支持 SCPI 命令，实现高速批量采集
    /// </summary>
    public class Th1963LanService : IDisposable
    {
        private TcpClient _tcpClient;
        private NetworkStream _stream;
        private bool _disposed = false;

        public int ReceiveBufferSize { get; set; } = 2 * 1024 * 1024;
        public int ConnectTimeoutMs { get; set; } = 3000;
        public int ReadWriteTimeoutMs { get; set; } = 5000;

        // 默认电压量程（伏特），可根据实际信号修改，例如 0.1, 1, 10, 100, 1000
        public double DefaultVoltageRange { get; set; } = 1.0;

        public async Task ConnectAsync(string ipAddress, int port = 45454)
        {
            if (_tcpClient != null && _tcpClient.Connected)
                return;

            _tcpClient = new TcpClient();
            _tcpClient.ReceiveBufferSize = ReceiveBufferSize;
            _tcpClient.SendBufferSize = ReceiveBufferSize;

            var connectTask = _tcpClient.ConnectAsync(ipAddress, port);
            if (await Task.WhenAny(connectTask, Task.Delay(ConnectTimeoutMs)) != connectTask)
                throw new TimeoutException($"连接 TH1963 ({ipAddress}:{port}) 超时");

            _stream = _tcpClient.GetStream();
            _stream.ReadTimeout = ReadWriteTimeoutMs;
            _stream.WriteTimeout = ReadWriteTimeoutMs;
        }

        /// <summary>
        /// 发送命令并等待完整响应（支持多行/大数据量）
        /// </summary>
        public async Task<string> QueryAsync(string command)
        {
            EnsureConnected();
            byte[] cmdBytes = Encoding.ASCII.GetBytes(command + "\n");
            await _stream.WriteAsync(cmdBytes, 0, cmdBytes.Length);

            var responseBuilder = new StringBuilder();
            byte[] buffer = new byte[65536];
            int bytesRead;
            bool endReached = false;

            while (!endReached)
            {
                bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length);
                if (bytesRead == 0) break;
                string chunk = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                responseBuilder.Append(chunk);
                // 如果收到换行符，再等50ms确认没有更多数据（TCP分包情况）
                if (chunk.Contains("\n"))
                {
                    await Task.Delay(50);
                    if (!_stream.DataAvailable)
                        endReached = true;
                }
            }
            return responseBuilder.ToString().Trim();
        }

        /// <summary>
        /// 发送命令，不等待响应
        /// </summary>
        public async Task SendCommandAsync(string command)
        {
            EnsureConnected();
            byte[] cmdBytes = Encoding.ASCII.GetBytes(command + "\n");
            await _stream.WriteAsync(cmdBytes, 0, cmdBytes.Length);
        }

        /// <summary>
        /// 配置为高速直流电压测量（BUS触发模式，固定量程，0.02PLC，关闭自归零）
        /// </summary>
        public async Task ConfigureForHighSpeedDcvAsync()
        {
            // 1. 重置到默认状态（可选）
            await SendCommandAsync("*RST");
            await Task.Delay(100);

            // 2. 固定量程（避免自动量程降低速度）
            await SendCommandAsync($"VOLT:DC:RANG {DefaultVoltageRange}");

            // 3. 设置积分时间 0.02PLC（最快速度）
            await SendCommandAsync("VOLT:DC:NPLC 10");

            // 4. 关闭自动归零（提高速度）
            await SendCommandAsync("VOLT:DC:ZERO:AUTO OFF");

            // 5. 触发源设为 BUS（软件触发）
            await SendCommandAsync("TRIG:SOUR BUS");

            // 6. 关闭自动延迟，延迟设为0
            await SendCommandAsync("TRIG:DEL:AUTO OFF");
            await SendCommandAsync("TRIG:DEL 0");
        }

        /// <summary>
        /// 预置采样点数并进入等待触发状态（发送 INIT）
        /// </summary>
        public async Task PrepareBatchAsync(int sampleCount)
        {
            await SendCommandAsync($"SAMP:COUN {sampleCount}");
            await SendCommandAsync("INIT");   // 进入等待触发状态
        }

        /// <summary>
        /// 发送软件触发信号（*TRG），开始采集
        /// </summary>
        public async Task TriggerAsync()
        {
            await SendCommandAsync("*TRG");
        }

        /// <summary>
        /// 获取批量采集结果（FETCh?）
        /// </summary>
        public async Task<double[]> FetchBatchAsync()
        {
            string response = await QueryAsync("FETCh?");
            return ParseResponse(response);
        }

        /// <summary>
        /// 一次性批量采集（简化接口，内部自动完成 SAMP:COUN + READ?）
        /// 注意：此方法会阻塞直到采集完成，适合不需要分离触发时序的场景
        /// </summary>
        public async Task<double[]> ReadBatchAsync(int sampleCount)
        {
            await SendCommandAsync($"SAMP:COUN {sampleCount}");
            string response = await QueryAsync("READ?");
            return ParseResponse(response);
        }

        /// <summary>
        /// 解析逗号分隔的电压值数组
        /// </summary>
        private double[] ParseResponse(string response)
        {
            if (string.IsNullOrWhiteSpace(response))
                throw new Exception("返回数据为空");

            string[] parts = response.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            double[] values = new double[parts.Length];
            for (int i = 0; i < parts.Length; i++)
            {
                if (!double.TryParse(parts[i], System.Globalization.NumberStyles.Float,
                        System.Globalization.CultureInfo.InvariantCulture, out values[i]))
                    throw new Exception($"解析电压值失败: {parts[i]}");
            }
            return values;
        }

        /// <summary>
        /// 单次读取电压（保留，但不推荐用于高速采集）
        /// </summary>
        public async Task<double> ReadVoltageAsync()
        {
            string resp = await QueryAsync("MEAS:VOLT:DC?");
            if (double.TryParse(resp, System.Globalization.NumberStyles.Float,
                    System.Globalization.CultureInfo.InvariantCulture, out double value))
                return value;
            throw new Exception($"电压读数无效: {resp}");
        }

        public async Task ResetAsync() => await SendCommandAsync("*RST");
        public async Task<string> IdentifyAsync() => await QueryAsync("*IDN?");

        private void EnsureConnected()
        {
            if (_tcpClient == null || !_tcpClient.Connected)
                throw new InvalidOperationException("未连接到 TH1963，请先调用 ConnectAsync");
        }

        public void Dispose()
        {
            if (!_disposed)
            {
                _stream?.Close();
                _tcpClient?.Close();
                _stream?.Dispose();
                _tcpClient?.Dispose();
                _disposed = true;
            }
        }
    }
}