using HighWayIot.Log4net;
using HighWayIot.Plc.PlcHelper;
using HighWayIot.Repository.domain;
using HighWayIot.Repository.service;
using HighWayIot.Rfid;
using HighWayIot.Rfid.Entity;
using HighWayIot.TouchSocket;
using HighWayIot.Winform.Properties;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HighWayIot.Winform.Business
{
    /// <summary>
    /// TCP数据工厂类
    /// </summary>
    public class TCPClientFactory
    {
        /// <summary>
        /// 标签服务类
        /// </summary>
        private ZxTagSettingService _tagrService = ZxTagSettingService.Instance;

        /// <summary>
        /// 标签实体类
        /// </summary>
        private List<ZxTagSettingEntity> _tagSetting;

        /// <summary>
        /// 读写器服务类
        /// </summary>
        private ZxReaderSettingService _readerService = ZxReaderSettingService.Instance;

        /// <summary>
        /// 读写器实体类
        /// </summary>
        private List<ZxReaderSettingEntity> _readerSetting;

        /// <summary>
        /// RFID数据分析
        /// </summary>
        private RfidDataAnalyse _RfidDataAnalyse = new RfidDataAnalyse();

        /// <summary>
        /// PLC
        /// </summary>
        private WorkStationHelper _workStationHelper = new WorkStationHelper();

        /// <summary>
        /// TCP客户端
        /// </summary>
        private TouchSocketTcpClient _touchSocketTcpClient = TouchSocketTcpClient.Instance;

        /// <summary>
        /// 心跳检测
        /// </summary>
        private Dictionary<string, DateTime> _heartBeatRecord = new Dictionary<string, DateTime>();

        /// <summary>
        /// Timer
        /// </summary>
        private Timer _heartbeatTimer;

        /// <summary>
        /// 工位识别历史记录
        /// </summary>
        public Dictionary<int, int> StationRecord = new Dictionary<int, int>();

        public TCPClientFactory()
        {
            _tagSetting = _tagrService.GetTagInfos();
            _readerSetting = _readerService.GetReaderInfos();
            _heartbeatTimer = new Timer(new TimerCallback(HeartbeatJudge), null, 0, 10000);
        }

        /// <summary>
        /// 对接收到的数据进行初步解析分发到各个报文类型的解析类中
        /// </summary>
        public void ReciveDataRoute(byte[] bytes, string ip)
        {
            BaseReciveDataEntity reciveData = BaseRFIDDataAnalyse.BaseReceiveAnalyse(bytes);
            if (reciveData == null)
            {
                return;
            }
            switch (reciveData.Code)
            {
                case 0x02: //盘点结果
                    ReciveHeartBeatSignal(ip);
                    Receive02HEntity data02Hentity = _RfidDataAnalyse.Receive02H(reciveData.Data);
                    if (data02Hentity == null || data02Hentity.Data == null)
                    {
                        return;
                    }
                    ReciveRFIDSingal(data02Hentity, ip);
                    break;
                case 0xBF: //心跳信号
                    ReciveHeartBeatSignal(ip);
                    if (reciveData.Status != 0x00)
                    {
                        LogHelper.Instance.Error($"读写器[{ip}]心跳返回异常，异常代码[{reciveData.Status}]");
                    }
                    break;
                default:
                    LogHelper.Instance.Error($"接收到未知报文，识别代码[{reciveData.Code.ToString("X2")}]");
                    return;

            }
        }

        /// <summary>
        /// 接收信息的信号
        /// </summary>
        /// <param name="bytes"></param>
        public void ReciveRFIDSingal(Receive02HEntity entity, string ip)
        {
            //找到读取次数最大的标签EPC
            byte[] epcData = entity.Data.Where(x => x.Count == entity.Data.Max(y => y.Count)).First().EPC;

            //标签号byte数组转换成字符串
            string epcResult = string.Join(" ", epcData.Select(x => x.ToString("X2")));

            //根据IP和标签EPC获取工位和对应设备号
            string deviceNo = _tagSetting.Where(x => x.RfidEpc == epcResult).FirstOrDefault().DeviceNo;
            string workstationNo = _readerSetting.Where(x => x.RfidIp == ip).FirstOrDefault().WorkstationNo;

            if (string.IsNullOrEmpty(deviceNo))
            {
                LogHelper.Instance.Error($"未查询到 [{epcResult}] 标签相关的信息！");
                return;
            }
            if (string.IsNullOrEmpty(workstationNo))
            {
                LogHelper.Instance.Error($"未查询到 [{ip}] 读写器相关的信息！");
                return;
            }

            try
            {
                //记录当前配方对应的小车
                if (int.Parse(workstationNo) == 1)
                {
                    RecipeSendBusiness.RecipeNeededVehicleNo = int.Parse(deviceNo);
                }
                //如果对应位置成功写入，记录上次该工位写入的是该小车，如果下次还是，不再写入(防止重复写入)
                int stationNo = int.Parse(workstationNo);
                int vehicleNo = int.Parse(deviceNo);
                //if (StationRecord.ContainsKey(stationNo)) //判断上次是不是写入的该点位
                //{
                //    //上次就写入的该车 就不继续写入了
                //    if (StationRecord[stationNo] == vehicleNo)
                //    {
                //        return;
                //    }
                //}
                ///写入对应的PLC信号
                if (_workStationHelper.WriteStationSingal(stationNo, vehicleNo))
                {
                    ////写入成功后记录，上次已写入了该点位，不继续写入
                    //if (StationRecord.ContainsKey(stationNo))
                    //{
                    //    StationRecord[stationNo] = vehicleNo;
                    //}
                    //else
                    //{
                    //    StationRecord.Add(stationNo, vehicleNo);
                    //}
                    LogHelper.Instance.RfidLog($"{workstationNo}工位, {deviceNo}号车 [{DateTime.Now.ToString("yy-MM-dd HH:mm:ss:fff")}]");
                }
                else
                {
                    LogHelper.Instance.Error($"{workstationNo}工位, {deviceNo}号车 信号写入异常(测试阶段日志) [{DateTime.Now.ToString("yy-MM-dd HH:mm:ss:fff")}]");
                }
            }
            catch (Exception ex)
            {
                LogHelper.Instance.Error("数值转换发生错误", ex);
            }
        }

        /// <summary>
        /// 心跳信号接收
        /// </summary>
        public void ReciveHeartBeatSignal(string ip)
        {
            try
            {
                //初次心跳处理
                if (!_heartBeatRecord.ContainsKey(ip))
                {
                    LogHelper.Instance.RfidLog($"[{ip}] 初次心跳");
                    _heartBeatRecord.Add(ip, DateTime.Now);
                    return;
                }
                else //不是初次就更新
                {
                    _heartBeatRecord[ip] = DateTime.Now;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Instance.Error($"心跳信号接收异常 {ex.Message}");
            }
        }

        /// <summary>
        /// 心跳识别
        /// </summary>
        /// <param name="o"></param>
        public void HeartbeatJudge(object o)
        {
            try
            {
                foreach (var kvp in _heartBeatRecord.ToArray())
                {
                    TimeSpan timeSpan = DateTime.Now - kvp.Value;
                    if (timeSpan.TotalSeconds > 10)
                    {
                        LogHelper.Instance.RfidLog($"[{kvp.Key}] 可能掉线，准备重连");
                        _heartBeatRecord.Remove(kvp.Key);
                        _touchSocketTcpClient.DisposeClient(kvp.Key);
                        _touchSocketTcpClient.CreateTcpClient(kvp.Key, "20108");
                        _touchSocketTcpClient.Send(kvp.Key, _RfidDataAnalyse.SendBFH(3));
                        _heartBeatRecord.Remove(kvp.Key);
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Instance.Error($"心跳信号监测异常 {ex.Message}");
            }
        }
    }
}
