using Edge.Core.Processor.Communicator;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HengshanPaymentTerminal
{
    public class StateMachineMessageCutter : IMessageCutter<byte[]>
    {
        #region Internal State enum

        private enum State
        {
            Uninitialized,
            LengthReady,
            BodyReady,
            EtxReady,
            CrcReady
        }

        #endregion

        #region Fields

        public byte[] Message { get; private set; }

        public event EventHandler OnMessageCut;
        public event EventHandler<MessageCutterInvalidMessageReadEventArg> OnInvalidMessageRead;

        private string loggerAppendix = "HengshanPay Terminal";
        private readonly SizableWindow<byte> window;

        //private State nextState = State.Uninitialized;

        private const int STX = 0xFA;

        #endregion

        #region Logger

        static NLog.Logger innerLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("Communicator");

        #endregion

        public StateMachineMessageCutter()
        {
            window = new SizableWindow<byte>();

            window.OnWindowFull += (data) =>
            {
                byte[] tempBytes = window.ToArray();
                string receiveStr = BitConverter.ToString(tempBytes).Replace("-", " ");
                //innerLogger.Info($"receive data : ${receiveStr}");

                int index = 0;//开始查找包头的下标
                //循环处理，避免数据粘包发送过来时只处理了第一个包
                while (true)
                {
                    //查找包头位置
                    int fristIndex = -1; //第一个包头位置
                    int secondIndex = -1; //第二个包头位置
                    for (; index < tempBytes.Length - 1; index++)
                    {
                        //fa+fa,为数据中带fa,跳过多加的 1 byte Fa
                        if (tempBytes[index] == STX && tempBytes[index+1] == STX)
                        {
                            index++;
                            continue;
                        }
                        
                        if (tempBytes[index] == STX && tempBytes[index + 1] != STX) // FA+非Fa ,包头
                        {
                            if (fristIndex == -1)
                            {
                                fristIndex = index;
                            }
                            else
                            {
                                secondIndex = index;
                                break;
                            }
                        } 
                        
                    }
                    //innerLogger.Info($"find head fristIndex = {fristIndex},secondIndex = {secondIndex}");
                    //若没有找到包头，证明目前缓存中都是垃圾数据，清掉
                    if (fristIndex == -1)
                    {
                        window.RemoveRange(0, tempBytes.Length);
                        return;
                    }
                    //长度不够表示部分数据还未接收到，等待下一轮接收数据再处理
                    //1byte FA + 1 byte 目标地址 + 1 byte 源地址 + 1 byte 帧号 + 2 byte 有效数据长度 + 2 byte 数据校验 = 8byte
                    if (fristIndex + 8 > tempBytes.Length)
                    {
                        innerLogger.Info($"Insufficient data length，at least ,need {fristIndex + 8},but length is {tempBytes.Length}");
                        return;
                    }
                    //获取有效数据长度
                    int dataLen = Bcd2Int(tempBytes[fristIndex + 4], tempBytes[fristIndex + 5]);
                    byte[] reduceFAData = Reduce0xFAPair(tempBytes,fristIndex,secondIndex);
                    string reduceFADataStr = BitConverter.ToString(reduceFAData).Replace("-", " ");
                    //innerLogger.Info($"data length is ${dataLen},reduceFAData len is ${reduceFAData.Length},value is ${reduceFADataStr}");
                    //去除多余FA后，实际数据不足有效数据长度，表示有粘包，仍非完整数据，等待下一轮接收数据再处理
                    //1byte FA + 1 byte 目标地址 + 1 byte 源地址 + 1 byte 帧号 + 2 byte 有效数据长度 + dataLen byte 数据 + 2 byte 数据校验
                    if (reduceFAData.Length < 6 + dataLen + 2)
                    {
                        innerLogger.Info("Insufficient data length");
                        return;
                    }
                    //计算crc,若值对应不上，表示数据错误
                    ushort calculatorValue = HengshanCRC16.ComputeChecksum(reduceFAData.AsSpan(1, 5 + dataLen).ToArray());
                    byte highByte = reduceFAData[6 + dataLen];
                    byte lowByte = reduceFAData[7 + dataLen];
                    int crcValue = (highByte << 8) | lowByte;
                    if (calculatorValue != crcValue)
                    {
                        //crc验证不通过，第一个包数据不正常，进入下一个循环，包头从第二个包头下标开始找（若没找到下个包头直接返回等待下一轮接收数据）
                        innerLogger.Info($"crc value error,get value is {crcValue},calculator value is {calculatorValue}");
                        if(secondIndex == -1)
                        {
                            window.RemoveRange(0, tempBytes.Length);
                            return;
                        }
                    }

                    //获取到实际数据包，并将缓存数据删除
                    Message = reduceFAData;
                    if (reduceFAData[6] != 0x10)
                    {
                        string reduceFaDataStr = BitConverter.ToString(reduceFAData).Replace("-", " ");
                        innerLogger.Info($"receive reduceFa data : {reduceFaDataStr}");
                    }
                    var safe = OnMessageCut;
                    safe?.Invoke(this, null);

                    //没有第二个包，清除缓存并结束
                    if(secondIndex == -1)
                    {
                        window.RemoveRange(0, tempBytes.Length);
                        return;
                    }
                    
                }
                

                
            };
        }

        public void Feed(byte[] data)
        {
            List<byte> list = new(data);
            window.Add(list);
            //for (int i = 0; i < data.Length; i++)
            //{
            //    window.Add(data[i]);
            //}
        }

        private int Get0xFAPairCountInWindow(IEnumerable<byte> data)
        {
            return (int)Math.Round(((double)(data.Count(w => w == 0xFA)) / 2), MidpointRounding.AwayFromZero);
        }

        /// <summary>
        /// 删除多余的FA，在接收到的一个完整数据包中，数据包头为FA，其余数据中每一个FA会替换为两个FA，这里要删除多余的fa来获取实际数据包
        /// </summary>
        /// <param name="data">原数据包</param>
        /// <param name="firstIndex">第一个包头下标</param>
        /// <param name="secondIndex">第二个包头下标</param>
        /// <returns></returns>
        public byte[] Reduce0xFAPair(byte[] data,int firstIndex,int secondIndex)
        {

            int endIndex = data.Length;
            if (secondIndex != -1 && secondIndex > firstIndex) endIndex = secondIndex;

            List<byte> list = new();
            for (int index = firstIndex; index < endIndex; index++)
            {
                if (index < data.Length -1 && data[index] == STX && data[index + 1] == STX)
                {
                    list.Add(STX);
                    index++;
                } 
                else
                {
                    list.Add(data[index]);
                }
            }
            return list.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;
        }
    }
}
