
using BPA.Message.Enum;
using BPA.Message.IOT;
using BPASmartClient.Business;
using BPASmartClient.Device;
using BPASmartClient.Helper;
using BPASmartClient.IoT.Model;
using BPASmartClient.Message;
using BPASmartDatavDeviceClient.IoT;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace BPASmartClient.IoT
{
    /// <summary>
    /// DataV客户端数据中心
    /// </summary>
    public class DataVClient
    {
        #region 单例模式
        public static DataVClient init = null;
        public static DataVClient GetInstance()
        {
            if (init == null)
            {
                init = new DataVClient();
            }
            return init;
        }
        /// <summary>
        /// 显示定义构造函数为私有，表示只允许自己实例化自己
        /// </summary>
        public DataVClient()
        {
            DataVApiAddress = System.Configuration.ConfigurationManager.AppSettings["DataVServiceUri"].ToString();
            ClientId = System.Configuration.ConfigurationManager.AppSettings["ClientId"].ToString();
            DeviceName = System.Configuration.ConfigurationManager.AppSettings["DeviceName"].ToString();
            ProductKey = System.Configuration.ConfigurationManager.AppSettings["ProductKey"].ToString();
            DeviceSecret = System.Configuration.ConfigurationManager.AppSettings["DeviceSecret"].ToString();
            StartupMode = System.Configuration.ConfigurationManager.AppSettings["StartupMode"].ToString();
            BroadcastPubTopic = System.Configuration.ConfigurationManager.AppSettings["BroadcastPubTopic"].ToString();
        }
        #endregion

        #region 公有变量
        public string StartupMode { set; get; }
        public string DeviceName { set; get; }
        public string ProductKey { set; get; }
        public string DeviceSecret { set; get; }
        public string BroadcastPubTopic { set; get; }
        /// <summary>
        /// DataV 服务地址
        /// </summary>
        public string DataVApiAddress { set; get; }
        /// <summary>
        /// 客户端ID
        /// </summary>
        public string ClientId { set; get; }
        /// <summary>
        /// MQTT上报集合
        /// </summary>
        public DataVReport DeviceDataV = new DataVReport();
        /// <summary>
        /// 大屏上报Model
        /// </summary>
        public DataVAPI.Tool.IOT.IOTDevSXModel iOTDevSXModel = new DataVAPI.Tool.IOT.IOTDevSXModel() { };
        /// <summary>
        /// key值
        /// </summary>
        public Dictionary<string, string> keyValues = new Dictionary<string, string>();
        #endregion

        #region API调用
        /// <summary>
        /// 增加告警信息
        /// </summary>
        /// <param name="alarmTable"></param>
        /// <returns>返回ID</returns>
        public string HttpAddAlarm(AlarmTable alarmTable)
        {
            try
            {
                if (DeviceDataV != null && DeviceDataV.GetIsConnected() && DeviceDataV.deviceTable != null)
                {
                    alarmTable.ClientId = ClientId;
                    alarmTable.devicename = DeviceDataV.deviceTable.devicename;
                    DeviceDataV.IOT_Publish(BroadcastPubTopic, Tools.JsonConvertTools(alarmTable));
                }
            }
            catch (Exception ex)
            {
                MessageLog.GetInstance.Show(ex.Message);
            }
            return alarmTable.KeyID;
        }

        /// <summary>
        /// 增加日志信息
        /// </summary>
        /// <param name="alarmTable"></param>
        /// <returns>返回ID</returns>
        public string HttpAddLog(LogTable logTable)
        {
            string id = string.Empty;
            try
            {
                if (DeviceDataV != null && DeviceDataV.GetIsConnected() && DeviceDataV.deviceTable != null)
                {
                    logTable.ClientId = ClientId;
                    logTable.devicename = DeviceDataV.deviceTable.devicename;
                    DeviceDataV.IOT_Publish(BroadcastPubTopic, Tools.JsonConvertTools(logTable));
                }
            }
            catch (Exception ex)
            {
                MessageLog.GetInstance.Show(ex.Message);
            }
            return id;
        }
        #endregion

        #region 公用
        /// <summary>
        /// 释放
        /// </summary>
        public void Dispose()
        {
            ThreadManage.GetInstance().StopTask("DataV数据上报");
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public void Initialize()
        {
            string message = string.Empty;
            if (StartupMode == "API")
            {
                if (DeviceDataV.Initialize(DataVApiAddress, ClientId, "", ref message))
                {
                    ProductKey = DeviceDataV.deviceTable.productkey;
                    DeviceName = DeviceDataV.deviceTable.devicename;
                    DeviceSecret = DeviceDataV.deviceTable.devicesecret;
                    DeviceDataV.DataVMessageAction += DevIOTActionHandler;
                    MessageLog.GetInstance.Show($"客户端:【{ClientId}】,设备名称{DeviceName}阿里云连接成功");
                    UpDataFile();
                }
                else
                {
                    MessageLog.GetInstance.ShowEx(message);
                }
            }
            else
            {
                if (DeviceDataV.InitializeNo(ProductKey, DeviceName, DeviceSecret, ref message))
                {
                    MessageLog.GetInstance.Show($"客户端:【{ClientId}】,设备名称{DeviceName}阿里云连接成功");
                    UpDataFile();
                }
                else
                    MessageLog.GetInstance.ShowEx(message);
            }
            Plugin.GetInstance()?.GetPlugin<DeviceMgr>()?.GetDevices()?.ForEach(device =>
            {
                device.AddErrorAction += AddErrorAction;
                device.DeleteErrorAction += DeleteErrorAction;
            });
        }

        /// <summary>
        /// 启动DataV数据上报
        /// </summary>
        public void Start()
        {
            ThreadManage.GetInstance().StartLong(new Action(() =>
            {
                if (DeviceDataV != null && DeviceDataV.GetIsConnected() && DeviceDataV.deviceTable != null)
                {
                    iOTDevSXModel.Device1=String.Empty;iOTDevSXModel.Device2=String.Empty;iOTDevSXModel.Device3 = String.Empty;
                    List<object> dataVNode = new List<object>();
                    Plugin.GetInstance()?.GetPlugin<DeviceMgr>()?.GetDevices()?.ForEach(device =>
                    {
                        var obj = new
                        {
                            DeviceId = device.DeviceId.ToString(),
                            devicename = DeviceDataV.deviceTable.devicename,
                            Name = device.Name,
                            DeviceType = device.DeviceType.ToString(),
                            IsBusy = device.IsBusy ? "忙碌" : "空闲",
                            IsBusyColor = device.IsBusy ? new ALYColor { r = 255, g = 0, b = 0, a = 1 } : new ALYColor { r = 51, g = 232, b = 34, a = 1 },
                            IsHealth = device.IsHealth ? "健康" : "故障",
                            IsHealthColor = !device.IsHealth ? new ALYColor { r = 255, g = 0, b = 0, a = 1 } : new ALYColor { r = 51, g = 232, b = 34, a = 1 },
                            Status = device.Status.GetIOTStatus(),
                            gjxx = device.GetError(),
                            rzxx = device.GetLog(),
                            VariableMonitor = device.GetVariableMonitor(),
                        };
                        dataVNode.Add(obj);

                        if (string.IsNullOrEmpty(iOTDevSXModel.Device1)) iOTDevSXModel.Device1 = $"[{device.Name}]:{(device.IsBusy ? "忙碌" : "空闲")}-{(device.IsHealth ? "健康" : "故障")}";
                        else if (string.IsNullOrEmpty(iOTDevSXModel.Device2)) iOTDevSXModel.Device2 = $"[{device.Name}]:{(device.IsBusy ? "忙碌" : "空闲")}-{(device.IsHealth ? "健康" : "故障")}";
                        else if (string.IsNullOrEmpty(iOTDevSXModel.Device3)) iOTDevSXModel.Device3 = $"[{device.Name}]:{(device.IsBusy ? "忙碌" : "空闲")}-{(device.IsHealth ? "健康" : "故障")}";
                    });
                    if (dataVNode.Count > 0)
                    {
                        iOTDevSXModel.NodeStatus = Tools.JsonConvertTools(new { data = dataVNode });
                        DeviceDataV.IOT_Publish(DeviceDataV.PubTopic, iOTDevSXModel.Tojson());
                    }
                }
                Thread.Sleep(3000);
            }), "DataV数据上报", true);
        }

        /// <summary>
        /// 文件上传请求
        /// </summary>
        public void UpDataFile()
        {
            try
            {
                if (DeviceDataV != null && DeviceDataV.GetIsConnected() && DeviceDataV.deviceTable != null)
                {
                    FileUpload.FileRequest(DeviceDataV);
                }
            }
            catch (Exception ex)
            {
                MessageLog.GetInstance.Show(ex.Message);
            }
        }
        #endregion

        #region 私有
        /// <summary>
        /// 增加告警
        /// </summary>
        /// <param name="obj"></param>
        private void AddErrorAction(int Devid, object obj)
        {
            string id = Guid.NewGuid().ToString();
            HttpAddAlarm(new AlarmTable
            {
                AlarmTime = GetPropertyValue(obj, "Time").ToString(),
                AlarmType = GetPropertyValue(obj, "Type").ToString(),
                AlarmMessage = GetPropertyValue(obj, "Text").ToString(),
                AlarmVla = "告警",
                DeviceId = Devid.ToString(),
                KeyID = id,
            });
            keyValues[GetPropertyValue(obj, "Time").ToString() + GetPropertyValue(obj, "Type").ToString() + GetPropertyValue(obj, "Text").ToString()] = id;
            //MessageLog.GetInstance.AddDeviceAlarmLogShow(GetPropertyValue(obj, "Time").ToString() + GetPropertyValue(obj, "Type").ToString() + GetPropertyValue(obj, "Text").ToString(),id);

        }

        /// <summary>
        /// 删除告警
        /// </summary>
        /// <param name="obj"></param>
        private void DeleteErrorAction(int Devid, object obj)
        {
            string message = GetPropertyValue(obj, "Time").ToString() + GetPropertyValue(obj, "Type").ToString() + GetPropertyValue(obj, "Text").ToString();
            if (keyValues.ContainsKey(message))
            {
                HttpAddAlarm(new AlarmTable
                {
                    AlarmTime = GetPropertyValue(obj, "Time").ToString(),
                    AlarmType = GetPropertyValue(obj, "Type").ToString(),
                    AlarmMessage = GetPropertyValue(obj, "Text").ToString(),
                    AlarmVla = "告警",
                    DeviceId = Devid.ToString(),
                    KeyID = keyValues[message],
                    State = "n"
                });
                //MessageLog.GetInstance.DeleteDeviceAlarmLogShow(message, keyValues[message]);

            }
        }

        /// <summary>
        /// 接收云端消息
        /// </summary>
        /// <param name="topic"></param>
        /// <param name="message"></param>
        private void DevIOTActionHandler(string deviceId, string topic, string message)
        {
            if (DeviceDataV.BroadcastTopic == topic && !string.IsNullOrEmpty(message))//广播主题消息，将广播消息发送到相应客户端
            {
                IOTCommandModel iOTCommand = Tools.JsonToObjectTools<IOTCommandModel>(message);
                if (iOTCommand.deviceName == DeviceDataV.deviceTable.devicename)
                    ActionManage.GetInstance.Send("IotBroadcast", iOTCommand);
            }
            else if (DeviceDataV.FileUpLoadReplyTopic == topic)//文件请求上传响应Topic
            {
                FileUploadModelResult result = Tools.JsonToObjectTools<FileUploadModelResult>(message);
                if (result.code == 200)
                {
                    string FileName = result.data?.fileName;
                    string uploadId = result.data?.uploadId;
                    FileUpload.SetUploadData(result.id,uploadId);
                    FileUpload.FileSend(DeviceDataV, uploadId);
                    MessageLog.GetInstance.Show($"请求上传【阿里云】成功,准备上传日志文件【HBL.LogDir{DateTime.Now.ToString("yyyy_M_d")}.log】");
                }
                else
                    MessageLog.GetInstance.Show($"【HBL.LogDir{DateTime.Now.ToString("yyyy_M_d")}.log】请求上传【阿里云】失败，{result.message}");

            }
            else if (DeviceDataV.FileUpLoadSendReplyTopic == topic)//文件上传Topic
            {
                FileUploadModelResult result = Tools.JsonToObjectTools<FileUploadModelResult>(message);
                if (result.code == 200)
                {
                    MessageLog.GetInstance.Show($"今日日志文件“HBL.LogDir{DateTime.Now.ToString("yyyy_M_d")}.log”更新上传【阿里云】成功");
                    bool complete = result.data.complete;
                    string uploadId = result.data?.uploadId;
                }else
                    MessageLog.GetInstance.Show($"今日日志文件“HBL.LogDir{DateTime.Now.ToString("yyyy_M_d")}.log”更新上传【阿里云】失败，{result.message}");

            }
            else if (DeviceDataV.CancelFileUpLoadSendReplyTopic == topic)//取消文件上传Topic
            {
                FileUploadModelResult result = Tools.JsonToObjectTools<FileUploadModelResult>(message);
            }
            
        }

        /// <summary>
        /// 获取某个对象中的属性值
        /// </summary>
        /// <param name="info"></param>
        /// <param name="field"></param>
        public object GetPropertyValue(object info, string field)
        {
            if (info == null) return null;
            Type t = info.GetType();
            IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
            return property.First().GetValue(info, null);
        }
        #endregion
    }

    //命令实体类   
    public class IOTCommandModel
    {
        /// <summary>
        /// 设备名称
        /// </summary>
        public string deviceName
        {
            get;
            set;
        }

        /// <summary>
        /// 命令名称：0 控制类 1 设置属性 2 通知信息类
        /// </summary>
        public int CommandName
        {
            get;
            set;
        }

        /// <summary>
        /// 命令变量：执行变量 key为属性或时间 value为值或者消息
        /// </summary>
        public Dictionary<string, string> CommandValue
        {
            get;
            set;
        }
    }


}
