using Edge.Core.Parser;
using Edge.Core.Parser.BinaryParser.MessageEntity;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace HengshanPaymentTerminal.MessageEntity
{
    /// <summary>
    /// 与油机通讯的基础数据包对象
    /// </summary>
    public abstract class CommonMessage: MessageTemplateBase
    {
        public enum Command
        {
            /// <summary>
            /// 通用应答命令字
            /// </summary>
            COMMON = 0x55,

            /// <summary>
            /// 心跳命令字
            /// </summary>
            HEART_BRET = 0x10,

            /// <summary>
            /// 油枪信息命令字
            /// </summary>
            NOZZLE_INFO = 0x61,

            /// <summary>
            /// 油枪状态命令字
            /// </summary>
            NOZZLE_STATE = 0x62,

            /// <summary>
            /// 发送二维码给油机命令字
            /// </summary>
            SEND_QR_CODE = 0x63,

            /// <summary>
            /// 获取单价命令字
            /// </summary>
            GET_PRICE = 0x64,

            /// <summary>
            /// 授权命令字
            /// </summary>
            ACCREDIT = 0x65,

            /// <summary>
            /// 取消授权命令字
            /// </summary>
            CANCEL_ACCREDIT = 0x66,

            /// <summary>
            /// 接收油机订单命令字
            /// </summary>
            RECIEVE_TRANX = 0x18,

            /// <summary>
            /// 发送应付金额给油机命令字
            /// </summary>
            SEND_NEED_AMOUNT = 0x19


        }
        /// <summary>
        /// 包头 0xFA
        /// </summary>
        public Byte Head { get; set; }

        /// <summary>
        /// 目标地址
        /// </summary>
        public Byte DestinationAddr { get; set; }

        /// <summary>
        /// 源地址
        /// </summary>
        public Byte SourceAddr { get; set; }

        /// <summary>
        /// 帧号
        /// </summary>
        public int FrameNum { get; set; }

        /// <summary>
        /// 有效数据长度，标识油机数据包中，有效数据的长度
        /// </summary>
        public int DataLength { get; set; }

        /// <summary>
        /// 命令字，用来标识数据包传递的数据
        /// </summary>
        public Byte Handle { get; set; }

        /// <summary>
        /// crc 校验值
        /// </summary>
        public Byte[] CRC { get; set; }

        /// <summary>
        /// 是否为错误响应（与油机通讯协议无关）
        /// </summary>
        public bool IsError { get; set; } = false;

        /// <summary>
        /// 错误信息（与油机协议无关）
        /// </summary>
        public string ErrorMessage { get; set; }

        public CommonMessage getBaseData(byte[] data)
        {
            this.Handle = data[0];
            this.DestinationAddr = data[1];
            this.SourceAddr = data[2];
            this.FrameNum = data[3];
            this.DataLength = Bcd2Int(data[4], data[5]);
            this.Handle = data[6];
            this.CRC = new byte[]{ data[data.Length - 2],data[data.Length - 1] };
            return this;
        }

        /// <summary>
        /// 传入有效数据，拼接为要发送给油机包
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public byte[] content2data(byte[] content)
        {
            List<byte> list = new List<byte>();
            //目标地址，源地址，帧号
            byte[] head = new byte[] { this.SourceAddr, this.DestinationAddr, (byte)this.FrameNum };
            byte[] length = Int2BCD(content.Length);
            list.AddRange(head);
            list.AddRange(length);
            list.AddRange(content);
            byte[] crc = HengshanCRC16.ComputeChecksumToBytes(list.ToArray());
            list.AddRange(crc);
            List<byte> addFAList = addFA(list);
            addFAList.Insert(0,0xFA);
            return addFAList.ToArray();
        }

        public int Bcd2Int(byte byte1, byte byte2)
        {
            // 提取第一个字节的高四位和低四位  
            int digit1 = (byte1 >> 4) & 0x0F; // 高四位  
            int digit2 = byte1 & 0x0F;        // 低四位  

            // 提取第二个字节的高四位和低四位  
            int digit3 = (byte2 >> 4) & 0x0F; // 高四位  
            int digit4 = byte2 & 0x0F;        // 低四位  

            // 组合成一个整数  
            int result = digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4;

            return result;
        }

        public byte[] Int2BCD(int number)
        {
            // 提取千位、百位、十位和个位  
            int thousands = number / 1000;
            int hundreds = (number / 100) % 10;
            int tens = (number / 10) % 10;
            int units = number % 10;

            // 将千位和百位组合成一个字节（千位在高四位，百位在低四位）  
            byte firstByte = (byte)((thousands * 16) + hundreds); // 乘以16相当于左移4位  

            // 将十位和个位组合成一个字节（十位在高四位，个位在低四位）  
            byte secondByte = (byte)((tens * 16) + units);

            // 返回结果数组  
            return new byte[] { firstByte, secondByte };
        }

        /// <summary>
        /// 数组转数字
        /// </summary>
        /// <param name="datas">数组</param>
        /// <param name="startIndex">开始的截取的下标</param>
        /// <param name="length">截取长度</param>
        /// <returns></returns>
        public T Bytes2Number<T>(byte[] datas,int startIndex,int length) where T: unmanaged
        {
            int sizeOfT = Unsafe.SizeOf<T>();
            Span<byte> span = datas.AsSpan(startIndex, length);

            // 如果 span 的长度不够，补足长度
            if (span.Length < sizeOfT)
            {
                // 使用数组而不是 stackalloc，避免栈溢出
                byte[] paddedArray = new byte[sizeOfT];
                Span<byte> paddedSpan = paddedArray.AsSpan();
                // 在前面补零
                span.CopyTo(paddedSpan.Slice(sizeOfT - span.Length));
                if (BitConverter.IsLittleEndian)
                {
                    // 小端序：反转字节顺序
                    paddedSpan.Reverse();
                }

                return MemoryMarshal.Read<T>(paddedSpan);
            }

            // 如果长度足够，直接读取
            if (BitConverter.IsLittleEndian)
            {
                // 小端序：反转字节顺序
                span.Reverse();
            }

            return MemoryMarshal.Read<T>(span);
        }
        public List<Byte> addFA(List<Byte> list)
        {
            List<byte> result = new List<byte>();

            foreach (byte b in list)
            {
                if (b == 0xFA)
                {
                    result.Add(0xFA);
                    result.Add(0xFA);
                }
                else
                {
                    result.Add(b);
                }
            }

            return result;
        }

        public DateTime bytes2DateTime(byte[] timeBytes)
        {
            string formate = "yyyyMMddHHmmss";
            string timeStr = BitConverter.ToString(timeBytes).Replace("-", "");
            DateTime parsedDateTime;

            bool success = DateTime.TryParseExact(timeStr, formate, null, System.Globalization.DateTimeStyles.None, out parsedDateTime);
            return success ? parsedDateTime : DateTime.Now;
        }
    }
}
