using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using SlnMesnac.Common;
using SlnMesnac.Model.dto;
using SlnMesnac.Rfid.Dto;
using SlnMesnac.Rfid.Enum;
using TouchSocket.Core;
using TouchSocket.Sockets;

#region << 版 本 注 释 >>
/*--------------------------------------------------------------------
* 版权所有 (c) 2024 WenJY 保留所有权利。
* CLR版本:4.0.30319.42000
* 机器名称:LAPTOP-E0N2L34V
* 命名空间:SlnMesnac.Rfid.Factory
* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82
*
* 创建者:WenJY
* 电子邮箱:wenjy@mesnac.com
* 创建时间:2024-03-27 21:58:35
* 版本:V1.0.0
* 描述:
*
*--------------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本:V1.0.0
*--------------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
namespace SlnMesnac.Rfid.Factory
{
    public class RflyFactory:RfidAbsractFactory
    {
        private ILogger<RflyFactory> _logger;
        private readonly TcpClient _tcpClient = new TcpClient();
        private readonly StringChange _stringChange;

        public RflyFactory(ILogger<RflyFactory> logger,StringChange stringChange)
        {
            _logger = logger;
            _stringChange = stringChange;
        }
        
        /// <summary>
        /// 建立连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override bool Connect(string ip, int port)
        {
            try
            {
                _tcpClient.Setup(new TouchSocketConfig().SetRemoteIPHost($"{ip}:{port}"));
                _tcpClient.Connect();
                return true;
            }
            catch (Exception e)
            {
                throw new InvalidOperationException($"设备连接异常:{e.Message}");
            }
        }

        /// <summary>
        /// 按时间段盘点
        /// </summary>
        /// <param name="timeout"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public override List<TagInfo> TimePeriodRead(int timeout = 5000)
        {
            byte[] u16byte = new byte[2];
            byte[] bCRC = new byte[4];
            try
            {
                #region 指令封装
                MessagePack pMessagePack = new MessagePack();
                pMessagePack.m_pData = new byte[8];
                pMessagePack.m_pData[0] = 0xAA;
                pMessagePack.m_pData[1] = 0x55;
                pMessagePack.m_pData[2] = 0x02;
                pMessagePack.m_pData[3] = 0x02;
                u16byte = BitConverter.GetBytes(timeout);  //超时时间
                u16byte = _stringChange.Swap16Bytes(u16byte);  //协议里为大端在前
                Array.Copy(u16byte, 0, pMessagePack.m_pData, 4, 2);
                Array.Copy(pMessagePack.m_pData, 2, bCRC, 0, 4);
                pMessagePack.m_pData[6] = _stringChange.CalculateVerify(bCRC, bCRC.Length);
                pMessagePack.m_pData[7] = 0x0D;
                #endregion

                var waitClient = _tcpClient.CreateWaitingClient(new WaitingOptions()
                {
                    FilterFunc = response =>
                    {
                        return true;
                    }
                });
                
                byte[] reciveBuffer = waitClient.SendThenReturn(pMessagePack.m_pData, timeout);
                
                _logger.LogInformation($"接收原始报文:{_stringChange.bytesToHexStr(reciveBuffer,reciveBuffer.Length)}");
                
                byte[] resultBuffer = PareReceiveBufferData(reciveBuffer,reciveBuffer.Length);
                
                List<TagInfo> tagInfoList = Device_DealTagInfoList(resultBuffer);
                
                return tagInfoList;
            }
            catch (Exception e)
            {
                throw new InvalidOperationException($"按时间段盘点异常:{e.Message}");
            }
        }

        #region 标签解析

        /// <summary>
        /// 状态机函数
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="iLen"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        private byte[] PareReceiveBufferData(byte[] buffer, int iLen)
        {
            RecvState enumRecvState = RecvState.WaitingBeginChar1_State;
            int m_iPosition = 0;
            UInt16 m_iFullMessageLength = 0;
            int iBarcodeLength = 0;//条码长度
            ArrayList m_FrecvData = new ArrayList();
            byte m_iVerify = 0;
            try
            {
                var bufferStr = _stringChange.bytesToHexStr(buffer, iLen);
                byte[] m_szFullMessage = new byte[iLen];
                for (int i = 0; i < iLen; i++)
                {
                    switch (enumRecvState)
                    {
                        case RecvState.WaitingBeginChar1_State:         //开始接受数据帧1 0xBB
                            Array.Clear(m_szFullMessage, 0, iLen);//清空为0
                            if (buffer[i] == 0xBB)
                            {
                                m_szFullMessage[m_iPosition] = buffer[i];
                                m_iPosition++;
                                enumRecvState = RecvState.WaitingBeginChar2_State;
                            }
                            else
                            {
                                m_iFullMessageLength = 0;
                                m_iPosition = 0;
                                enumRecvState = RecvState.WaitingBeginChar1_State;
                            }
                            break;
                        case RecvState.WaitingBeginChar2_State:             //开始接受数据帧1 0xDD
                            if (buffer[i] == 0xDD)
                            {
                                m_szFullMessage[m_iPosition] = buffer[i];
                                m_iPosition++;
                                enumRecvState = RecvState.WaitingForBarcodeLength_State;
                            }
                            else
                            {
                                m_iFullMessageLength = 0;
                                m_iPosition = 0;
                                enumRecvState = RecvState.WaitingBeginChar1_State;
                            }
                            break;
                        case RecvState.WaitingForBarcodeLength_State:         //开始接受数据长度(TagCount - EPC)                        
                            m_szFullMessage[m_iPosition] = buffer[i];
                            iBarcodeLength = buffer[i];                      //单组标签:18;两组标签:35
                            m_iPosition++;
                            enumRecvState = RecvState.WaitingForCode_State;
                            break;

                        case RecvState.WaitingForCode_State:                //开始接受指令编号
                            if (buffer[i] == 0x02)
                            {
                                m_szFullMessage[m_iPosition] = buffer[i];
                                m_iPosition++;
                                enumRecvState = RecvState.WaitingForStus_State;
                            }
                            else if (buffer[i] == 0x90)          // 如果是心跳BB DD 01 90 00 1F 8E 0D 
                            {
                                m_szFullMessage[m_iPosition] = buffer[i];
                                m_iPosition++;
                                enumRecvState = RecvState.WaitingForEndChar_State;
                            }
                            else if (buffer[i] == 0xBF)          // 如果是心跳BB DD 04 BF 00 00 00 F9 0B 49 0D
                            {
                                m_szFullMessage[m_iPosition] = buffer[i];
                                m_iPosition++;
                                enumRecvState = RecvState.WaitingForEndChar_State;
                            }
                            else
                            {
                                m_iFullMessageLength = 0;
                                m_iPosition = 0;
                                enumRecvState = RecvState.WaitingBeginChar1_State;
                            }
                            break;
                        case RecvState.WaitingForStus_State:        //开始接受状态码
                            if (buffer[i] == 0x00)
                            {
                                m_szFullMessage[m_iPosition] = buffer[i];
                                m_iPosition++;
                                enumRecvState = RecvState.WaitingForTagCount_State;
                            }
                            else if (buffer[i] == 0x40)
                            {
                                m_szFullMessage[m_iPosition] = buffer[i];
                                //LogService.Instance.Debug("RFU620等待接受WaitingForEndChar_State:Noread");
                                lock (m_FrecvData)
                                {
                                    m_FrecvData.Add(m_szFullMessage);
                                }
                                m_iPosition = 0;
                                i = iLen;
                                enumRecvState = RecvState.WaitingBeginChar1_State;
                                //LogService.Instance.Debug("RFly-I160状态机结束。");
                            }
                            break;
                        case RecvState.WaitingForTagCount_State:         //开始接受标签组数                        
                            Array.Copy(buffer, i, m_szFullMessage, m_iPosition, iBarcodeLength);//m_iPosition = 5
                            byte[] tempData = new byte[iBarcodeLength];
                            Array.Clear(tempData, 0, iBarcodeLength);
                            Array.Copy(buffer, i, tempData, 0, iBarcodeLength);
                            m_iPosition = m_iPosition + iBarcodeLength;     //m_iPosition = 39
                            i = i + iBarcodeLength - 1;                         //i = 39
                            enumRecvState = RecvState.WaitingForXor_State;
                            break;
                        case RecvState.WaitingForXor_State:         //开始比对校验位 Rfly160 
                            byte[] m_CRCVerify = new byte[1024];     //此数组用于校验位计算
                            Array.Clear(m_CRCVerify, 0, m_CRCVerify.Length);
                            Array.Copy(m_szFullMessage, 2, m_CRCVerify, 0, iBarcodeLength + 3); //校验位计算是从Length - EPC 结束
                            m_szFullMessage[m_iPosition] = buffer[i];
                            m_iVerify = m_szFullMessage[m_iPosition];
                            if (m_iVerify == _stringChange.CalculateVerify(m_CRCVerify, m_CRCVerify.Length))
                            {
                                m_iPosition++;
                                enumRecvState = RecvState.WaitingForEndChar_State;
                            }
                            else	   //如果校验不成功
                            {
                                m_iFullMessageLength = 0;
                                m_iPosition = 0;
                                enumRecvState = RecvState.WaitingBeginChar1_State;
                            }
                            break;
                        case RecvState.WaitingForEndChar_State:
                            if (buffer[0] == 0xBB && buffer[1] == 0xDD && buffer[2] == 0x00 && buffer[3] != 0x90) //此处为Noread数据显示
                            {
                                m_szFullMessage[0] = 0xBB;
                                m_szFullMessage[1] = 0xDD;
                                m_szFullMessage[2] = 0x00;
                                lock (m_FrecvData)
                                {
                                    m_FrecvData.Add(m_szFullMessage);
                                }
                                m_iPosition = 0;
                                i = iLen;
                                enumRecvState = RecvState.WaitingBeginChar1_State;
                            }
                            else if (buffer[0] == 0xBB && buffer[1] == 0xDD && buffer[2] == 0x04 && buffer[3] == 0xBF)
                            {
                                Array.Copy(buffer, 0, m_szFullMessage, 0, 11);
                                i = 11;
                                lock (m_FrecvData)
                                {
                                    m_FrecvData.Add(m_szFullMessage);
                                }
                                i = iLen;
                            }
                            else if (buffer[i] == 0x00)         //获取温度
                            {
                                Array.Copy(buffer, 0, m_szFullMessage, 0, 8);
                                i = 8;
                                lock (m_FrecvData)
                                {
                                    m_FrecvData.Add(m_szFullMessage);
                                }
                                i = iLen;
                            }
                            else if (buffer[i] == 0x11)
                            {
                                Array.Copy(buffer, 0, m_szFullMessage, 0, 7);
                                i = 7;
                                lock (m_FrecvData)
                                {
                                    m_FrecvData.Add(m_szFullMessage);
                                }
                            }
                            else if (buffer[i] == 0x01)
                            {
                                Array.Copy(buffer, 0, m_szFullMessage, 0, 8);
                                i = 8;
                                lock (m_FrecvData)
                                {
                                    m_FrecvData.Add(m_szFullMessage);
                                }
                            }
                            else
                            {
                                m_szFullMessage[m_iPosition] = buffer[i];
                                m_iPosition++;
                                if (buffer[i] == 0x0D)
                                {
                                    lock (m_FrecvData)
                                    {
                                        m_FrecvData.Add(m_szFullMessage);
                                    }
                                }
                            }
                            m_iPosition = 0;
                            enumRecvState = RecvState.WaitingBeginChar1_State;
                            break;
                    }
                }

                return m_szFullMessage;
            }
            catch (Exception e)
            {
                throw new InvalidOperationException($"状态机逻辑处理异常:{e.Message}");
            }
        }
        
        private Mutex mutauto = new Mutex();
        /// <summary>
        /// 解析函数
        /// </summary>
        /// <param name="AutoDealReportData"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public List<TagInfo> Device_DealTagInfoList(byte[] AutoDealReportData)
        {
            List<TagInfo> tagInfoList = new List<TagInfo>();
            byte[] bResultEPC_Data = new byte[14];
            byte[] m_AutoReadEPC = null;
            int m_readEPCDataLen = 0;
            try
            {
                mutauto.WaitOne();
                int iFirstCountPos = 6;     //第一次读取标签次数位置
                int iFirstRSSIPos = 7;      //第一次读取标签强度位置
                int iFirstAnt = 8;
                int iFirstPC = 9;   //第一次读取标签天线位置
                int iFirstLeftBarcketPos = 11;//EPC数据起始位置
                UInt16 tempDataCount = 0;
                int tempDataRSSI = 0;
                UInt16 tempDataANT = 0;
                int iBarcodeGroupCount = Convert.ToInt32(AutoDealReportData[5].ToString()); //标签组数
                int iBarcodeLength = 16;        //标签长度
                int iCommonSecondFlag = 0;
                for (int j = 0; j < iBarcodeGroupCount; j++)
                {
                    TagInfo tag = new TagInfo();
                    byte[] tempPCByte = new byte[2];     //取出PC
                    Array.Clear(tempPCByte, 0, 2);
                    Array.Copy(AutoDealReportData, iFirstPC, tempPCByte, 0, 2);

                    int pc = Convert.ToInt32(tempPCByte[0].ToString("X"));
                    int epcLength = EPCLengthByPC(pc);
                    iBarcodeLength = epcLength;

                    byte[] tempDataByte = new byte[epcLength];
                    Array.Clear(tempDataByte, 0, iBarcodeLength);
                    Array.Copy(AutoDealReportData, iFirstLeftBarcketPos, tempDataByte, 0, iBarcodeLength);

                    byte[] tempCountByte = new byte[1];     //取出标签次数
                    Array.Clear(tempCountByte, 0, 1);
                    Array.Copy(AutoDealReportData, iFirstCountPos, tempCountByte, 0, 1);
                    tempDataCount = tempCountByte[0];

                    byte[] tempRSSIByte = new byte[1];     //取出标签强度
                    Array.Clear(tempRSSIByte, 0, 1);
                    Array.Copy(AutoDealReportData, iFirstRSSIPos, tempRSSIByte, 0, 1);

                    tempDataRSSI = _stringChange.HexStringToNegative(_stringChange.bytesToHexStr(tempRSSIByte, 1));

                    #region add by wenjy 20220829 取出天线号
                    byte[] tempAntByte = new byte[1];     //取出天线号
                    Array.Clear(tempAntByte, 0, 1);
                    Array.Copy(AutoDealReportData, iFirstAnt, tempAntByte, 0, 1);
                    tempDataANT = tempAntByte[0];
                    #endregion

                    tag.Count = tempDataCount;
                    tag.RSSI = tempDataRSSI;
                    tag.EPC = tempDataByte;

                    if (pc == 24)
                    {
                        tag.EPCstring = _stringChange.bytesToHexStr(tempDataByte, tempDataByte.Length).Substring(0, 7);
                    }
                    else
                    {
                        tag.EPCstring = Encoding.ASCII.GetString(tempDataByte);
                    }

                    tag.PC = tempPCByte;
                    tag.Antana = tempDataANT;
                    tagInfoList.Add(tag);
                    int iBarcodeListLen = tagInfoList.Count; //特别注意,必须这样,要不然会多一条数据

                    iFirstCountPos = iFirstCountPos + iBarcodeLength + 5; //次数
                    iFirstRSSIPos = iFirstCountPos + 1; //强度
                    iFirstAnt = iFirstRSSIPos + 1; //天线
                    iFirstPC = iFirstAnt + 1;
                    iFirstLeftBarcketPos = iFirstLeftBarcketPos + iBarcodeLength + 5;

                    _logger.LogInformation("----函数调用:Device_DealTagInfoList 第[" + (iCommonSecondFlag + 1) + "]次数据解析为:" + tag.EPCstring + ",读取标签次数:[" + tempDataCount + "],标签信号强度:[" + tempDataRSSI + "],天线号:[" + tempDataANT + "]");
                    iCommonSecondFlag++;
                    if (iCommonSecondFlag == iBarcodeGroupCount)
                    {
                        mutauto.ReleaseMutex();
                        _logger.LogInformation("《《《返回标签数据!");
                        return tagInfoList;
                    }
                }
                return tagInfoList;
            }
            catch (Exception ex)
            {
                mutauto.ReleaseMutex();
                throw new InvalidOperationException($"Device_AutoDealContent 自动处理函数异常:{ex.Message}");
            }
        }
        
        /// <summary>
        /// 根据PC获取EPC长度
        /// </summary>
        /// <param name="pcValue"></param>
        /// <returns></returns>
        private int EPCLengthByPC(int pcValue)
        {
            int epcLength = 0;
            if (pcValue >= 10 && pcValue < 20)
            {
                epcLength = 4;
            }
            else if (pcValue >= 20 && pcValue < 30)
            {
                epcLength = 8;
            }
            else if (pcValue >= 30 && pcValue < 40)
            {
                epcLength = 12;
            }
            else if (pcValue >= 40 && pcValue < 50)
            {
                epcLength = 16;
            }
            else if (pcValue >= 50 && pcValue < 60)
            {
                epcLength = 20;
            }
            else if (pcValue >= 60 && pcValue < 70)
            {
                epcLength = 24;
            }
            else if (pcValue >= 70 && pcValue < 80)
            {
                epcLength = 28;
            }
            else if (pcValue >= 80 && pcValue < 90)
            {
                epcLength = 30;
            }
            return epcLength;
        }

        #endregion
    }
}