using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MegaRobo.C00225155.ControlDevices
{
    public class HighTemperatureUartHCM
    {
        #region 协议常量定义
        private const byte ST = 0x5E;               // 帧头
        private const byte HELLO = 0x01;            // 握手指令
        private const byte RDTEMP = 0x08;           // 读取温度
        private const byte RDADC = 0x09;            // 读取传感器AD
        private const byte RDEE = 0x11;             // 读取EEPROM
        private const byte WREE = 0x12;             // 写入EEPROM
        private const byte Calb = 0x15;             // 校准温度
        private const byte SETHOTTEMP = 0x16;       // 加热温度控制
        private const byte RESPONSE_FLAG = 0x80;    // 上传指令标志
        #endregion

        #region 校验和计算（协议第6点：前n-1字节之和的低8位）
        /// <summary>
        /// 计算帧的校验和（核心：前length字节之和的低8位）
        /// </summary>
        private static byte CalculateChecksum(byte[] data, int length)
        {
            if (data == null || length <= 0 || length > data.Length)
                throw new ArgumentException("校验和计算参数无效");

            int sum = 0;
            for (int i = 0; i < length; i++)
                sum += data[i];
            return (byte)(sum & 0xFF); // 取低8位，确保1字节
        }
        #endregion

        #region 帧间隔控制（协议1.1g：帧与帧间隔>2ms，用Thread.Sleep确保阻塞）
        /// <summary>
        /// 帧间隔时间（预留3ms余量，确保符合协议要求）
        /// </summary>
        private static void AddFrameInterval()
        {
            Task.Delay(3); 
        }
        #endregion

        #region 下传指令构建（PC→主控板，严格遵循协议指令格式）
        /// <summary>
        /// 握手指令（系统开机必发）
        /// </summary>
        public static byte[] SendHello(byte deviceId = 0)
        {
            byte[] frame = new byte[5]; // 协议固定帧长5字节
                                        // 帧结构：ST → HELLO(0x01) → 设备ID → LTH=5 → 校验和
            frame[0] = ST;
            frame[1] = HELLO; // 移除序号或运算，CMD为固定指令码（协议3.1）
            frame[2] = deviceId;
            frame[3] = 5; // LTH固定为5
            frame[4] = CalculateChecksum(frame, 4); // 前4字节求和

            AddFrameInterval();
            return frame;
        }

        /// <summary>
        /// 读取温度指令
        /// </summary>
        public static byte[] SendReadTempRequest(byte deviceId = 0)
        {
            byte[] frame = new byte[5]; // 协议固定帧长5字节
                                        // 帧结构：ST → RDTEMP(0x08) → 设备ID → LTH=5 → 校验和
            frame[0] = ST;
            frame[1] = RDTEMP;
            frame[2] = deviceId;
            frame[3] = 5;
            frame[4] = CalculateChecksum(frame, 4);

            AddFrameInterval();
            return frame;
        }

        /// <summary>
        /// 读取传感器AD指令
        /// </summary>
        public static byte[] SendReadAdcRequest(byte deviceId = 0)
        {
            byte[] frame = new byte[5]; // 协议固定帧长5字节
                                        // 帧结构：ST → RDADC(0x09) → 设备ID → LTH=5 → 校验和
            frame[0] = ST;
            frame[1] = RDADC;
            frame[2] = deviceId;
            frame[3] = 5;
            frame[4] = CalculateChecksum(frame, 4);

            AddFrameInterval();
            return frame;
        }

        /// <summary>
        /// 读取EEPROM指令
        /// </summary>
        public static byte[] SendReadEepromRequest(byte addrHigh, byte addrMid, byte addrLow, int readLength, byte deviceId = 0)
        {
            if (readLength < 1)
                throw new ArgumentOutOfRangeException(nameof(readLength), "读取长度必须≥1");

            int frameLength = 9 + readLength; // 帧长=9（固定段）+ 读取长度（协议3.4）
            byte[] frame = new byte[frameLength];
            // 帧结构：ST → RDEE(0x11) → 设备ID → LTH=N → 地址高→中→低 → 读取长度 → 校验和
            frame[0] = ST;
            frame[1] = RDEE;
            frame[2] = deviceId;
            frame[3] = (byte)frameLength;
            frame[4] = addrHigh;
            frame[5] = addrMid;
            frame[6] = addrLow;
            frame[7] = (byte)readLength;
            frame[frameLength - 1] = CalculateChecksum(frame, frameLength - 1);

            AddFrameInterval();
            return frame;
        }

        /// <summary>
        /// 写入EEPROM指令
        /// </summary>
        public static byte[] SendWriteEepromRequest(byte addrHigh, byte addrMid, byte addrLow, byte[] writeData, byte deviceId = 0)
        {
            if (writeData == null || writeData.Length == 0)
                throw new ArgumentException("写入数据不能为空", nameof(writeData));

            int frameLength = 9 + writeData.Length; // 帧长=9（固定段）+ 数据长度（协议3.5）
            byte[] frame = new byte[frameLength];
            // 帧结构：ST → WREE(0x12) → 设备ID → LTH=N → 地址高→中→低 → 写入数据 → 校验和
            frame[0] = ST;
            frame[1] = WREE;
            frame[2] = deviceId;
            frame[3] = (byte)frameLength;
            frame[4] = addrHigh;
            frame[5] = addrMid;
            frame[6] = addrLow;
            Array.Copy(writeData, 0, frame, 7, writeData.Length);
            frame[frameLength - 1] = CalculateChecksum(frame, frameLength - 1);

            AddFrameInterval();
            return frame;
        }

        /// <summary>
        /// 校准温度指令（设置B值=(实际温度-目标温度)×100）
        /// </summary>
        public static byte[] SendCalibrateTempRequest(int calibBValue, byte deviceId = 0)
        {
            if (calibBValue < short.MinValue || calibBValue > short.MaxValue)
                throw new ArgumentOutOfRangeException(nameof(calibBValue), "校准B值必须在-32768~32767之间");

            byte[] frame = new byte[7]; // 协议固定帧长7字节
            short bParam = (short)calibBValue; // 16位有符号数（支持负值）
                                               // 帧结构：ST → Calb(0x15) → 设备ID → LTH=7 → 参数1(高8) → 参数2(低8) → 校验和
            frame[0] = ST;
            frame[1] = Calb;
            frame[2] = deviceId;
            frame[3] = 7;
            frame[4] = (byte)(bParam >> 8); // 高位在前（协议3.6）
            frame[5] = (byte)(bParam & 0xFF);
            frame[6] = CalculateChecksum(frame, 6);

            AddFrameInterval();
            return frame;
        }

        /// <summary>
        /// 加热温度控制（设置目标温度或释放控制）
        /// </summary>
        public static byte[] SendSetHotTemp(double targetTemp, byte deviceId = 0, bool releaseControl = false)
        {
            byte[] frame = new byte[7]; // 协议固定帧长7字节
            ushort tempParam;

            if (releaseControl)
            {
                tempParam = 0xFFFF; // 协议约定：释放控制=0xFFFF（关断功率）
            }
            else
            {
                // 协议范围：室温~100℃（对应室温×100~10000），室温暂以20℃为参考
                if (targetTemp < 20.0 || targetTemp > 100.0)
                    throw new ArgumentOutOfRangeException(nameof(targetTemp), "温度必须在[20.0, 100.0]℃之间（符合协议室温要求）");
                tempParam = (ushort)(targetTemp * 100); // 放大100倍（协议3.7）
            }

            // 帧结构：ST → SETHOTTEMP(0x16) → 设备ID → LTH=7 → 参数1(高8) → 参数2(低8) → 校验和
            frame[0] = ST;
            frame[1] = SETHOTTEMP;
            frame[2] = deviceId;
            frame[3] = 7;
            frame[4] = (byte)(tempParam >> 8); // 高位在前（协议3.7）
            frame[5] = (byte)(tempParam & 0xFF);
            frame[6] = CalculateChecksum(frame, 6);

            AddFrameInterval();
            return frame;
        }
        #endregion

        #region 指令解析
        /// <summary>
        /// 解析主控板返回的帧数据（入口方法）
        /// </summary>
        public static ParseResult ParseReceivedFrame(byte[] receivedFrame)
        {
            // 基础校验：帧非空、最短帧≥6字节（上传指令最短为握手响应6字节）
            if (receivedFrame == null || receivedFrame.Length < 6)
                return new ParseResult(false, "无效帧：数据为空或长度不足", null);

            // 1. 校验帧头
            if (receivedFrame[0] != ST)
                return new ParseResult(false, $"帧头错误：实际0x{receivedFrame[0]:X2}，期望0x{ST:X2}", null);

            // 2. 提取核心字段
            byte cmdWithFlag = receivedFrame[1];
            byte deviceId = receivedFrame[2];
            byte frameLength = receivedFrame[3];
            byte checksum = receivedFrame[frameLength - 1];

            // 3. 校验帧长（实际长度=帧长字段）
            if (receivedFrame.Length != frameLength)
                return new ParseResult(false, $"帧长不匹配：实际{receivedFrame.Length}字节，期望{frameLength}字节", null);

            // 4. 校验和验证
            byte calculatedChecksum = CalculateChecksum(receivedFrame, frameLength - 1);
            if (calculatedChecksum != checksum)
                return new ParseResult(false, $"校验和错误：实际0x{checksum:X2}，计算0x{calculatedChecksum:X2}", null);

            // 5. 去除响应标志，获取原始指令码
            byte originalCmd = (byte)(cmdWithFlag & ~RESPONSE_FLAG);

            // 6. 按指令类型分发解析
            switch (originalCmd)
            {
                case HELLO:
                    return ParseHelloResponse(receivedFrame, deviceId);
                case RDTEMP:
                    return ParseReadTempResponse(receivedFrame, deviceId);
                case RDADC:
                    return ParseReadAdcResponse(receivedFrame, deviceId);
                case RDEE:
                    return ParseReadEepromResponse(receivedFrame, deviceId);
                case WREE:
                    return ParseWriteEepromResponse(receivedFrame, deviceId);
                case Calb:
                    return ParseCalibrateTempResponse(receivedFrame, deviceId);
                case SETHOTTEMP:
                    return ParseSetHotTempResponse(receivedFrame, deviceId);
                default:
                    return new ParseResult(false, $"未知指令：0x{originalCmd:X2}", null);
            }
        }

        #region 各指令解析实现（严格对齐协议响应格式）
        /// <summary>
        /// 解析握手响应
        /// </summary>
        private static ParseResult ParseHelloResponse(byte[] frame, byte deviceId)
        {
            if (frame.Length != 6) // 协议固定响应帧长6字节
                return new ParseResult(false, "握手响应帧长错误（需6字节）", null);

            byte status = frame[4]; // 状态位（协议3.1）
            var data = new Dictionary<string, object>
        {
            { "设备ID", deviceId },
            { "状态码", status },
            { "状态描述", status == 0 ? "握手成功" : $"握手失败（错误码：{status}）" }
        };
            return new ParseResult(true, "握手响应解析成功", data);
        }

        /// <summary>
        /// 解析读取温度响应
        /// </summary>
        private static ParseResult ParseReadTempResponse(byte[] frame, byte deviceId)
        {
            if (frame.Length != 0x0D) // 协议固定响应帧长13字节（0x0D）
                return new ParseResult(false, $"读取温度响应帧长错误：需13字节，实际{frame.Length}字节", null);

            // 提取数据：参数1(设置温度)、参数2(实际温度)、参数3(预留)、标志位、状态位（协议3.2）
            ushort setTempParam = (ushort)((frame[4] << 8) | frame[5]); // 高位在前
            ushort actualTempParam = (ushort)((frame[6] << 8) | frame[7]); // 高位在前
            byte flag = frame[10]; // 预留标志位（NC）
            byte status = frame[11];

            // 转换为实际温度（除以100，精度0.1℃）
            double setTemp = setTempParam / 100.0;
            double actualTemp = actualTempParam / 100.0;

            var data = new Dictionary<string, object>
        {
            { "设备ID", deviceId },
            { "状态码", status },
            { "状态描述", status == 0 ? "读取温度成功" : $"读取失败（错误码：{status}）" },
            { "设置温度（℃）", setTemp },
            { "实际温度（℃）", actualTemp },
            { "预留标志位", flag },
            { "原始设置温度参数", $"0x{setTempParam:X4}" },
            { "原始实际温度参数", $"0x{actualTempParam:X4}" }
        };
            return new ParseResult(true, "读取温度响应解析成功", data);
        }

        /// <summary>
        /// 解析读取AD响应
        /// </summary>
        private static ParseResult ParseReadAdcResponse(byte[] frame, byte deviceId)
        {
            if (frame.Length != 0x0A) // 协议固定响应帧长10字节（0x0A），修正原13字节错误
                return new ParseResult(false, $"读取AD响应帧长错误：需10字节，实际{frame.Length}字节", null);

            // 提取数据：AD值（5-6字节）、预留（7-8字节）、状态位（9字节）（协议3.3）
            ushort adcValue = (ushort)((frame[4] << 8) | frame[5]); // 高位在前
            byte status = frame[8];

            var data = new Dictionary<string, object>
        {
            { "设备ID", deviceId },
            { "状态码", status },
            { "状态描述", status == 0 ? "读取AD成功" : $"读取失败（错误码：{status}）" },
            { "AD值", adcValue },
            { "原始AD参数", $"0x{adcValue:X4}" }
        };
            return new ParseResult(true, "读取AD响应解析成功", data);
        }

        /// <summary>
        /// 解析读取EEPROM响应
        /// </summary>
        private static ParseResult ParseReadEepromResponse(byte[] frame, byte deviceId)
        {
            if (frame.Length < 6) // 协议响应帧长≥6字节
                return new ParseResult(false, "读取EEPROM响应帧长不足（需≥6字节）", null);

            // 提取数据：参数1~n（5到N-2字节）、状态位（N-2字节）（协议3.4）
            int dataLength = frame.Length - 6; // 数据字节数=N-6
            byte[] eepromData = new byte[dataLength];
            Array.Copy(frame, 4, eepromData, 0, dataLength);
            byte status = frame[frame.Length - 2];

            var data = new Dictionary<string, object>
        {
            { "设备ID", deviceId },
            { "状态码", status },
            { "状态描述", status == 0 ? "读取EEPROM成功" : $"读取失败（错误码：{status}）" },
            { "读取数据长度（字节）", dataLength },
            { "读取数据（十六进制）", BitConverter.ToString(eepromData).Replace("-", " ") },
            { "原始数据数组", eepromData }
        };
            return new ParseResult(true, "读取EEPROM响应解析成功", data);
        }

        /// <summary>
        /// 解析写入EEPROM响应
        /// </summary>
        private static ParseResult ParseWriteEepromResponse(byte[] frame, byte deviceId)
        {
            if (frame.Length != 6) // 协议固定响应帧长6字节
                return new ParseResult(false, "写入EEPROM响应帧长错误（需6字节）", null);

            byte status = frame[4]; // 状态位（协议3.5）
            var data = new Dictionary<string, object>
        {
            { "设备ID", deviceId },
            { "状态码", status },
            { "状态描述", status == 0 ? "写入EEPROM成功" : $"写入失败（错误码：{status}）" }
        };
            return new ParseResult(true, "写入EEPROM响应解析成功", data);
        }

        /// <summary>
        /// 解析校准温度响应
        /// </summary>
        private static ParseResult ParseCalibrateTempResponse(byte[] frame, byte deviceId)
        {
            if (frame.Length != 6) // 协议固定响应帧长6字节
                return new ParseResult(false, "校准温度响应帧长错误（需6字节）", null);

            byte status = frame[4]; // 状态位（协议3.6）
            var data = new Dictionary<string, object>
        {
            { "设备ID", deviceId },
            { "状态码", status },
            { "状态描述", status == 0 ? "温度校准成功" : $"校准失败（错误码：{status}）" }
        };
            return new ParseResult(true, "校准温度响应解析成功", data);
        }

        /// <summary>
        /// 解析加热温度控制响应
        /// </summary>
        private static ParseResult ParseSetHotTempResponse(byte[] frame, byte deviceId)
        {
            if (frame.Length != 6) // 协议固定响应帧长6字节
                return new ParseResult(false, "加热温度响应帧长错误（需6字节）", null);

            byte status = frame[4]; // 状态位（协议3.7）
            var data = new Dictionary<string, object>
        {
            { "设备ID", deviceId },
            { "状态码", status },
            { "状态描述", status == 0 ? "加热温度指令接收成功" : $"接收失败（错误码：{status}）" }
        };
            return new ParseResult(true, "加热温度响应解析成功", data);
        }
        #endregion
        #endregion

        #region 预留CRC16校验（协议未使用，保留以备扩展）
        public static byte[] CRC16(byte[] data)
        {
            int len = data.Length;
            if (len <= 0)
                return new byte[] { 0, 0 };

            ushort crc = 0xFFFF;
            for (int i = 0; i < len; i++)
            {
                crc = (ushort)(crc ^ data[i]);
                for (int j = 0; j < 8; j++)
                {
                    crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
                }
            }

            byte hi = (byte)((crc & 0xFF00) >> 8);
            byte lo = (byte)(crc & 0x00FF);
            return BitConverter.IsLittleEndian ? new byte[] { lo, hi } : new byte[] { hi, lo };
        }
        #endregion
    }
}
