using BPA.Message;
using BPA.Message.Enum;
using BPASmartClient.Helper;
using BPASmartClient.Message;
using BPASmartClient.Model;
using BPASmartClient.Peripheral;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BPASmartClient.Device
{
    /// <summary>
    /// 设备基类
    /// </summary>
    public abstract class BaseDevice : IDevice
    {
        public BaseDevice()
        {
        }

        #region 属性
        /// <summary>
        /// 订单物料信息
        /// </summary>
        public OrderMaterialDelivery orderMaterialDelivery { get; set; } = new OrderMaterialDelivery();

        /// <summary>
        /// 配方数据信息
        /// </summary>
        public RecipeBoms recipeBoms { get; set; } = new RecipeBoms();

        /// <summary>
        /// 设备ID
        /// </summary>
        public int DeviceId { get; set; }

        /// <summary>
        /// 设备所有状态
        /// </summary>
        public DeviceStatus Status { get; set; } = new DeviceStatus();

        /// <summary>
        /// 设备名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 当前订单数量
        /// </summary>
        protected int OrderCount { get; set; }

        /// <summary>
        /// 设备初始化中
        /// </summary>
        protected bool Initing { get; set; }

        /// <summary>
        /// 设备类型
        /// </summary>
        public abstract DeviceClientType DeviceType { get; }

        /// <summary>
        /// 是否忙碌
        /// </summary>
        public bool IsBusy { get; protected set; }

        /// <summary>
        /// 是否健康
        /// </summary>
        public bool IsHealth { get; protected set; }

        /// <summary>
        /// 设备运行日志
        /// </summary>
        public List<object> Log { get; set; } = new List<object>();

        /// <summary>
        /// 设备运行告警与错误
        /// </summary>
        public List<object> Error { get; set; } = new List<object>();

        /// <summary>
        /// 设备变量监控
        /// </summary>
        public List<VariableMonitor> variableMonitors { get; set; } = new List<VariableMonitor>();

        /// <summary>
        /// 外设状态,硬件设备数据
        /// </summary>
        protected ConcurrentDictionary<string, object> peripheralStatus = new ConcurrentDictionary<string, object>();

        /// <summary>
        /// 外设设备集合
        /// </summary>
        private List<IPeripheral> peripherals;

        public Action<int, object> AddErrorAction { get; set; }
        public Action<int, object> DeleteErrorAction { get; set; }
        public List<Alarm> alarms { get; set; } = new List<Alarm>();
        public IAlarm InterfaceAlarm { get; set; }
        public AlarmHelper alarmHelper { get; set; } = new AlarmHelper();

        #endregion

        /// <summary>
        /// 设备过程日志显示
        /// </summary>
        /// <param name="info"></param>
        public void DeviceProcessLogShow(string info)
        {
            Log.Insert(0, new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Type = "流程", Text = info });
            MessageLog.GetInstance.DeviceProcessLogShow(DeviceId.ToString(), info);
            if (Log.Count > 100) { Log.RemoveAt(Log.Count - 1); }
        }

        public void Initliaze()
        {
        }

        public void Initliaze(List<IPeripheral> peripherals)
        {
            peripherals.ForEach(p =>
            {
                p.DeviceId = this.DeviceId;
                p.Init();
            });
            this.peripherals = peripherals;
        }

        public virtual void StartMain()
        {
            ThreadManage.GetInstance().StartLong(new Action(() =>
            {
                foreach (var peripheral in peripherals)
                {
                    string TypeName = peripheral.GetType().FullName.Replace("BPASmartClient.", "");
                    Status.Update($"{TypeName}.IsConnected", peripheral.IsConnected);
                    Status.Update($"{TypeName}.IsWork", peripheral.IsWork);
                    foreach (var key in peripheral.GetAllStatus().Keys)
                    {
                        peripheralStatus[key] = peripheral.GetAllStatus()[key];
                        if (TypeName != "PLC.PLCMachine")
                        {
                            Status.Update($"{TypeName}.{key}", peripheral.GetAllStatus()[key]);
                        }
                    }
                }

                if (AddErrorAction != null && DeleteErrorAction != null)
                {
                    foreach (var item in Status.GetStatusT())
                    {
                        if (item.Name == "Warning" || item.Name == "Fault")
                        {
                            if (item.Status != "无故障" && item.Status != "无警告" && item.Status != "未发生故障")
                            {
                                var res = Error?.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString() == item.Ms);
                                if (res == null)
                                {
                                    object obj = new
                                    {
                                        Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                                        Type = item.Name == "Warning" ? "警告" : "故障",
                                        Text = item.Ms
                                    };
                                    Error.Add(obj);
                                    AddErrorAction?.Invoke(DeviceId, obj);
                                }
                            }
                            else
                            {
                                var res = Error?.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString().Contains(item.id));
                                if (res != null)
                                {
                                    Error.Remove(res);
                                    DeleteErrorAction?.Invoke(DeviceId, res);
                                }
                            }
                        }
                    }
                }
                Thread.Sleep(100);
            }), $"GetAllStatus:{DeviceId}");
            DoMain();
            GetGvlStatus();
            InitResetTask();
            InitTask();
        }

        private void GetGvlStatus()
        {
            this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList().ForEach(item =>
            {
                var res = item.FieldType.GetInterfaces();
                if (res != null)
                {
                    foreach (var faces in res)
                    {
                        if (faces.Name == "IStatus")
                        {
                            IStatus status = item.GetValue(this) as IStatus;
                            GetMonitorData(status);
                            ThreadManage.GetInstance().StopTask($"{item.Name}:{DeviceId}", new Action(() =>
                             {
                                 ThreadManage.GetInstance().StartLong(new Action(() =>
                                 {
                                     UpdateValue(status);
                                     Thread.Sleep(1000);
                                 }), $"{item.Name}:{DeviceId}");
                             }));
                        }
                        else if (faces.Name == "IAlarm")
                        {
                            InterfaceAlarm = item.GetValue(this) as IAlarm;
                            //IAlarm alarm = item.GetValue(this) as IAlarm;
                            //AlarmHelper alarmHelper = new AlarmHelper();
                            alarmHelper.AddAction += new Action<string>((s) =>
                            {
                                var res = alarmHelper.Alarms.FirstOrDefault(p => p.Info == s);
                                if (res != null)
                                {
                                    object obj = new
                                    {
                                        Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                                        Type = res.Grade,
                                        Text = res.Info
                                    };
                                    Error.Insert(0, obj);
                                    AddErrorAction?.Invoke(DeviceId, obj);
                                }
                            });
                            alarmHelper.RemoveAction += new Action<string>((s) =>
                            {
                                var res = Error.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString() == s);
                                if (res != null && Error.Contains(res))
                                {
                                    Error.Remove(res);
                                    DeleteErrorAction?.Invoke(DeviceId, res);
                                }
                            });
                            ThreadManage.GetInstance().StartLong(new Action(() =>
                            {
                                AlarmMonitoring();
                                Thread.Sleep(500);
                            }), $"报警检测监控:{DeviceId}");
                        }
                    }
                }
            });
        }

        /// <summary>
        /// 报警监控
        /// </summary>
        /// <param name="alarm"></param>
        /// <param name="alarmHelper"></param>
        private void AlarmMonitoring()
        {
            if (InterfaceAlarm == null) return;
            foreach (var item in InterfaceAlarm.GetType().GetProperties())
            {
                var res = item.GetValue(InterfaceAlarm);
                if (res != null && res is bool blen)
                {
                    if (item.CustomAttributes.Count() > 0 && item.CustomAttributes.ElementAt(0)?.ConstructorArguments.Count() > 0)
                    {
                        var info = item.GetCustomAttribute<AlarmAttribute>().AlarmInfo;
                        if (info != null) alarmHelper.EdgeAlarm(blen, info.ToString());
                    }
                }
            }
        }

        private void InitResetTask()
        {
            #region 复位程序
            ThreadManage.GetInstance().StartLong(new Action(() =>
            {
                if (RTrig.GetInstance($"ResetProgram:{DeviceId}").Start(Initing))
                {
                    ThreadManage.GetInstance().StopTask($"MainTask:{DeviceId}", new Action(() =>
                    {
                        ThreadManage.GetInstance().StopTask($"ReadData:{DeviceId}", new Action(() =>
                        {
                            ResetProgram();
                            InitTask();
                        }));
                    }));
                }
                Thread.Sleep(10);
            }), $"ResetProgram:{DeviceId}");
            #endregion
        }

        private void InitTask()
        {
            #region 数据读取
            ThreadManage.GetInstance().StartLong(new Action(() =>
            {
                ReadData();
                Thread.Sleep(10);
            }), $"ReadData:{DeviceId}");
            #endregion

            #region 任务流程
            ThreadManage.GetInstance().StartLong(new Action(() =>
            {
                MainTask();
                Thread.Sleep(10);
            }), $"MainTask:{DeviceId}");
            #endregion

        }

        /// <summary>
        /// 获取监控信息
        /// </summary>
        private void GetMonitorData(IStatus status)
        {
            if (status == null) return;
            foreach (var item in status.GetType().GetProperties())
            {
                if (item.CustomAttributes.Count() > 0)
                {
                    var attributeName = item.CustomAttributes.FirstOrDefault(p => p.AttributeType.Name == "VariableMonitorAttribute");
                    if (attributeName == null) return;
                    var plcadd = item.GetCustomAttribute<VariableMonitorAttribute>()?.PLCAddress;
                    var modadd = item.GetCustomAttribute<VariableMonitorAttribute>()?.ModbusTcpAddress;
                    var notes = item.GetCustomAttribute<VariableMonitorAttribute>()?.Notes;

                    if (item.PropertyType?.BaseType?.Name == "Array")
                    {
                        if (plcadd?.Length > 0)
                        {
                            var arrayRes = item.GetValue(status, null);
                            if (arrayRes != null && arrayRes is Array arr)
                            {
                                for (int i = 0; i < arr.Length; i++)
                                {
                                    var res = variableMonitors.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}");
                                    if (res == null)
                                    {
                                        string[] plc = plcadd?.Substring(1).Split('.');
                                        string TempPlcAddress = string.Empty;
                                        if (plc?.Length == 2)
                                        {
                                            int add = int.Parse(plc[1]);
                                            int firstAdd = int.Parse(plc[0]);
                                            if (add >= 0 && add < 7)
                                            {
                                                add += i;
                                            }
                                            else if (add >= 7)
                                            {
                                                add = 0;
                                                firstAdd++;
                                            }
                                            plc[0] = firstAdd.ToString();
                                            plc[1] = add.ToString();
                                            TempPlcAddress = $"M{plc[0]}.{plc[1]}";
                                        }

                                        variableMonitors.Add(new VariableMonitor()
                                        {
                                            Id = variableMonitors.Count,
                                            VarName = $"{item.Name}_{i + 1}",
                                            Notes = $"{notes}_{i + 1}",
                                            ModbusTcpAddress = $"{int.Parse(modadd) + i}",
                                            PLCAddress = TempPlcAddress,

                                        });
                                    }
                                }
                            }
                        }
                        else
                        {
                            var arrayRes = item.GetValue(status, null);
                            if (arrayRes != null && arrayRes is Array arr)
                            {
                                for (int i = 0; i < arr.Length; i++)
                                {
                                    var res = variableMonitors.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}");
                                    if (res == null)
                                    {
                                        variableMonitors.Add(new VariableMonitor()
                                        {
                                            Id = variableMonitors.Count,
                                            VarName = $"{item.Name}_{i + 1}",
                                            Notes = $"{notes}_{i + 1}",

                                        });
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        var res = variableMonitors.FirstOrDefault(p => p.VarName == item.Name);
                        if (res == null)
                        {
                            variableMonitors.Add(new VariableMonitor()
                            {
                                Id = variableMonitors.Count,
                                VarName = item.Name,
                                Notes = notes,
                                ModbusTcpAddress = modadd,
                                PLCAddress = plcadd,

                            });
                        }
                    }

                }
            }
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="status"></param>
        public void UpdateValue(IStatus status)
        {
            if (status == null) return;
            foreach (var item in status.GetType().GetProperties())
            {
                if (item.CustomAttributes.Count() > 0)
                {
                    if (item.PropertyType?.BaseType?.Name == "Array")
                    {
                        var arrayRes = item.GetValue(status);
                        if (arrayRes != null && arrayRes is Array arr)
                        {
                            for (int i = 0; i < arr.Length; i++)
                            {
                                int index = Array.FindIndex(variableMonitors.ToArray(), p => p.VarName == $"{item.Name}_{i + 1}");
                                if (index >= 0 && index < variableMonitors.Count)
                                {
                                    variableMonitors.ElementAt(index).CurrentValue = arr.GetValue(i)?.ToString();
                                }
                            }
                        }
                    }
                    else
                    {
                        int index = Array.FindIndex(variableMonitors.ToArray(), p => p.VarName == item.Name);
                        if (index >= 0 && index < variableMonitors.Count)
                        {
                            variableMonitors.ElementAt(index).CurrentValue = item.GetValue(status)?.ToString();
                        }
                    }

                }
            }
        }

        public abstract void DoMain();

        public abstract void Stop();

        /// <summary>
        /// 数据读取
        /// </summary>
        public abstract void ReadData();
        /// <summary>
        /// 主流程控制
        /// </summary>
        public abstract void MainTask();
        /// <summary>
        /// 复位程序
        /// </summary>
        public abstract void ResetProgram();

        public object GetError()
        {
            return new { data = Error };
        }

        public object GetLog()
        {
            return new { data = Log };
        }

        public object GetVariableMonitor()
        {
            return new { data = variableMonitors };
        }

        /// <summary>
        /// 获取某个对象中的属性值
        /// </summary>
        /// <param name="info"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        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);
        }
    }
}
