using HslCommunication;
using HslCommunication.Enthernet.Redis;
using HslCommunication.MQTT;
using MWS.Data.InterFace;
using MWS.Data.Manager;
using MWS.Library;
using MWS.Library.Common;
using MWS.Model;
using MWS.Model.Model;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading;

namespace MWS.Domain.Tasks.Weighing
{
    public class QCX_H4C_C11
    {
        public Hashtable HashCount;
        public ManualResetEvent eventX;
        public RedisClient _redisClient;
        private MqttClient _mqttClient;
        public int _frequency = 100;
        private SystemConfig _systemConfig;
        private IWeight weightManager;
        public QCX_H4C_C11(int frequency, SystemConfig systemConfig)
        {
            HashCount = new Hashtable();
            weightManager = new WeightManager();
            _frequency = frequency;
            #region Redis
            var redisAddress = ConfigurationManager.AppSettings["RedisAddress"];
            var redisPort = ConfigurationManager.AppSettings["RedisPort"];
            var redisTagDb = ConfigurationManager.AppSettings["RedisTagDb"];
            _redisClient = new RedisClient(redisAddress, int.Parse(redisPort), null);
            var operateResult = _redisClient.ConnectServer();
            _redisClient.SelectDB(int.Parse(redisTagDb));
            if (!operateResult.IsSuccess)
            {
                LogHelper.WriteLog("Redis服务连接失败！错误：" + operateResult.Message);
            }
            #endregion     
            #region MQTT
            var mqttPort = ConfigurationManager.AppSettings["MqttPort"];
            _mqttClient = new MqttClient(new MqttConnectionOptions
            {
                ClientId = Guid.NewGuid().ToString("N").ToUpper(),
                IpAddress = "127.0.0.1",
                Port = mqttPort.ToInt(),
            });
            operateResult = _mqttClient.ConnectServer();
            if (!operateResult.IsSuccess)
            {
                LogHelper.WriteLog("MQTT服务连接失败！错误：" + operateResult.Message);
            }
            _mqttClient.OnNetworkError += MqttClient_OnNetworkError;
            #endregion
            _systemConfig = systemConfig;
        }

        public void Listen(object state)
        {
            var indicatorConfig = state as IndicatorConfigModel.Device;
            IndicatorTagModel indicatorTag = new IndicatorTagModel();
            indicatorTag.DeviceId = indicatorConfig.DeviceId;
            WeightDataPickModel dataPick = new WeightDataPickModel { Weights = new List<WeightDataPickModel.WeightItem>() };
            WeightDataModel weightData = new WeightDataModel { Records = new List<WeightDataModel.DataItem>() };

            bool grabOpen = false;
            while (true)
            {
                Thread.Sleep(_frequency);
                #region 获取值
                indicatorTag.GrabOpen = GetTagValueByRedis<bool>(indicatorConfig.GrabOpenTagId);
                indicatorTag.IsSteady = GetTagValueByRedis<bool>(indicatorConfig.SteadyTagId);
                indicatorTag.CarInplace = GetTagValueByRedis<bool>(indicatorConfig.CarInplaceTagId);
                indicatorTag.NetWeight = GetTagValueByRedis<float>(indicatorConfig.NetWeightTagId);
                indicatorTag.TareWeight = GetTagValueByRedis<float>(indicatorConfig.TareWeightTagId);
                #endregion 获取值
                //刷新载荷值
                RefeshLoadWeight(indicatorConfig.LoadWeightTagId, indicatorTag.NetWeight, indicatorTag.TareWeight);
                //记录过程数据 保留最后300条重量记录 留作计算
                dataPick.Weights.Add(new WeightDataPickModel.WeightItem { Weight = indicatorTag.NetWeight, Time = DateTime.Now, IsSteady = indicatorTag.IsSteady });
                if (dataPick.Weights.Count > 100)
                {
                    dataPick.Weights.RemoveRange(0, 5);
                }
                //投料就位信号
                if (indicatorTag.CarInplace)
                {
                    if (indicatorTag.GrabOpen && !grabOpen)
                    {
                        Measure(dataPick, weightData);
                    }
                }
                else
                {
                    if (weightData.EntranceId != 0)
                    {
                        weightData.EntranceId = 0;
                    }
                    if (weightData.Records.Any())
                    {
                        Measure(dataPick, weightData);
                        var firstRecord = weightData.Records.First();
                        var lastRecord = weightData.Records.Count >= 2 ? weightData.Records.Last() : null;
                        float weight = firstRecord.Weight - (lastRecord?.Weight ?? 0);

                        if (weight < 0 || weight > _systemConfig.WeightItem.Threshold)
                        {
                            var teamId = GetCurrentTeam();
                            weightManager.Insert(new Record
                            {
                                Device = indicatorTag.DeviceId,
                                Entrance = dataPick.EntranceId,
                                NetWeight = weight,
                                TareWeight = indicatorTag.TareWeight,
                                GrossWeight = weight + indicatorTag.TareWeight,
                                CreationTime = DateTime.Now,
                                Team = teamId
                            });
                            #region 发送称重数据
                            var mqttMessage = new MqttApplicationMessage
                            {
                                Topic = "WeighingData",
                                Payload = Encoding.UTF8.GetBytes(new JObject(
                                                                    new JProperty("DeviceId", indicatorTag.DeviceId),
                                                                    new JProperty("NetWeight", weight),
                                                                    new JProperty("TeamId", teamId)
                                                                    ).ToString())
                            };
                            var publishResult = _mqttClient.PublishMessage(mqttMessage);
                            if (!publishResult.IsSuccess)
                            {
                                LogHelper.WriteLog("发布主题“WeighingData”时失败！错误：" + publishResult.Message);
                            }
                            #endregion
                        }
                        //清空开斗数据记录
                        weightData.Records.Clear();
                    }
                }
                grabOpen = indicatorTag.GrabOpen;
            }
        }

        private void RefeshLoadWeight(int tagId, float netWeight, float tareWeight)
        {
            float loadWeight;
            if (_systemConfig.WeightItem.LoadMode == 1)
            {
                loadWeight = netWeight;
            }
            else
            {
                loadWeight = netWeight + tareWeight;
            }
            var operateResult = _redisClient.WriteHashKey("Tags", tagId.ToString(), new JObject(new JProperty("TagId", tagId), new JProperty("Value", loadWeight), new JProperty("AD", loadWeight)).ToString());
            if (!operateResult.IsSuccess)
            {
                LogHelper.WriteLog("将载荷数据写入Redis时失败！错误：" + operateResult.Message);
            }
        }
        private T GetTagValueByRedis<T>(int tagId)
        {
            OperateResult<string> operateResult = _redisClient.ReadHashKey("Tags", tagId.ToString());
            if (operateResult.IsSuccess && !operateResult.Content.IsNullOrEmptyOrWhiteSpace())
            {
                JObject jObject = JObject.Parse(operateResult.Content);
                return jObject.GetValue("Value").ToObject<T>();
            }
            return default(T);
        }


        private short GetCurrentTeam()
        {
            var exitResult = _redisClient.ExistsKey("CurrentTeam");
            if (exitResult.IsSuccess)
            {
                if (exitResult.Content == 1)
                {
                    OperateResult<string> readResult = _redisClient.ReadKey("CurrentTeam");
                    if (readResult.IsSuccess && !readResult.Content.IsNullOrEmptyOrWhiteSpace())
                    {
                        JObject jObject = JObject.Parse(readResult.Content);
                        return jObject.GetValue("Id").ToObject<short>();
                    }
                }
            }
            return 0;
        }

        public void Measure(WeightDataPickModel dataPick, WeightDataModel weightData)
        {
            //是否有称重数据
            if (dataPick.Weights.Any())
            {
                var lastDataTime = dataPick.Weights.Last().Time;
                dataPick.Weights.Reverse();
                float weight;
                //截取有效值 即 松斗信号之前x毫秒数据内n条重量记录
                var effectWeights = dataPick.Weights.Where(c => c.Time < lastDataTime.AddMilliseconds(-_systemConfig.WeightItem.FrontTime)).Take(_systemConfig.WeightItem.EffectCount);
                //有效值数量是否满足
                if (effectWeights.Count() == _systemConfig.WeightItem.EffectCount)
                {
                    weight = effectWeights.OrderBy(c => c.Weight).Skip(1).Take(_systemConfig.WeightItem.FrontTime - 2).Average(c => c.Weight);
                }
                else
                {
                    weight = dataPick.Weights.Average(c => c.Weight);
                }

                //记录松斗记录（有可能一次投料 松斗合斗好几次 造成多次累积  故记录多次 离开或者归零时取首次）
                weightData.Records.Add(new WeightDataModel.DataItem
                {
                    Time = DateTime.Now,
                    Weight = weight,
                });
                dataPick.Weights = new List<WeightDataPickModel.WeightItem>();
            }
        }

        private void MqttClient_OnNetworkError(object sender, EventArgs e)
        {
            // 当网络异常的时候触发，可以在此处重连服务器
            if (sender is MqttClient client)
            {
                // 开始重连服务器，直到连接成功为止
                Console.WriteLine("网络异常，准备5秒后重新连接。");
                while (true)
                {
                    // 每隔5秒重连
                    Thread.Sleep(5000);
                    Console.WriteLine("准备重新连接服务器...");
                    OperateResult connect = client.ConnectServer();
                    if (connect.IsSuccess)
                    {
                        // 连接成功后，可以在下方break之前进行订阅，或是数据初始化操作
                        Console.WriteLine("连接服务器成功！");
                        break;
                    }
                    Console.WriteLine("连接失败，准备5秒后重新连接。");
                }
            }
        }
    }
}