using Logs;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using WCS.Entity;
using WCS.Service;
namespace WCS.Core
{
    /// 
    /// 逻辑处理器
    ///  
    public abstract class LogicHandler
    {
        /// 
        /// 停止
        ///  
        protected bool Stoped = false;
        /// 
        /// 描述
        ///  
        protected string Description { get; }
        /// 
        /// 所有对象
        ///  
        public static List AllObjects = new();
        /// 
        /// 所有处理器
        ///  
        private static readonly List Handlers = new();
        /// 
        /// 日志委托,暂时弃用
        ///  
        [Obsolete]
        public static Action DbLog;
        /// 
        /// 逻辑处理器
        ///  
        protected LogicHandler()
        {
            var attr = this.GetType().GetCustomAttributes(false).OfType().FirstOrDefault();
            Description = attr != null ? attr.Description : this.GetType().Name;
        }
        /// 
        /// 开始
        ///  
        public abstract void Start();
        /// 
        /// 是否并行
        ///  
        public virtual bool ParallelRun => false;
        /// 
        /// 数据刷新时触发
        ///  
        /// 
        /// 停止
        ///  
        public void Stop()
        {
            Stoped = true;
        }
        /// 
        /// 添加处理器
        ///  
        /// 
        /// 启动所有的处理器
        ///  
        public static void StartAll()
        {
            foreach (var h in Handlers)
            {
                h.Start();
            }
            var th = new Thread(Loop)
            {
                IsBackground = true //前台线程即主线程关闭,立即结束该线程
            };
            th.Start();
        }
        /// 
        /// 最后一次执行结束的时间
        ///  
        private static DateTime _last = DateTime.Now;
        /// 
        ///逻辑耗时
        ///  
        private static int _logicTimes;
        public static DateTime Frame { get; private set; }
        /// 
        /// 主循环体,用于PLC数据的读取与逻辑执行
        ///  
        private static void Loop()
        {
            var arr = AllObjects.OfType().Where(v => v.ENABLED).SelectMany(v => v.PROTOCOLS)
                .Where(v => v.ENABLED && v.DB.ENABLED && v.DB.PLC.ENABLED)
                .GroupBy(v => v.DB).Select(v => v.Key)
                .ToArray();
            while (true)
            {
                var dd = DateTime.Now;
                Frame = DateTime.Now;
                Parallel.ForEach(arr, db =>
                {
                    try
                    {
                        Ltc.SetChannel("刷新");
                        db.Ex().DataRefresh();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("更新" + db.NAME + "数据失败:" + ex.Message);
                    }
                });
                var dbTimes = (DateTime.Now - dd).TotalMilliseconds;
                var total = (DateTime.Now - _last).TotalMilliseconds;
                var s = (int)(600 - total);
                if (s > 0)
                    Thread.Sleep(s);
                total = (DateTime.Now - _last).TotalMilliseconds;
                Console.ForegroundColor = ConsoleColor.Blue;
                //此处打印的logicTimes实际是上一个周期的业务处理时长
                Console.WriteLine("------刷新DB块数据耗时:" + ((int)dbTimes).ToString().PadRight(4, ' ') + ";业务逻辑耗时:" + ((int)_logicTimes).ToString().PadRight(4, ' ') + ";周期总耗时" + ((int)total).ToString().PadRight(4, ' ') + "");
                Console.ResetColor();
                _last = DateTime.Now;
                Parallel.ForEach(Handlers, m =>
                {
                    var dm = DateTime.Now;
                    try
                    {
                        m.Update(total);
                    }
                    catch (Exception)
                    {
                        //TODO:增加一个异常记录
                    }
                    var dm2 = (DateTime.Now - dm).TotalMilliseconds;
                });
                Configs.Publish();
                _logicTimes = (int)(DateTime.Now - _last).TotalMilliseconds;
            }
        }
        /// 
        /// 停止所有的处理器
        ///  
        public static void StopAll()
        {
            foreach (var h in Handlers)
            {
                try
                {
                    h.Stop();
                }
                catch
                {
                    // TODO:等待处理
                }
            }
        }
    }
    /// 
    /// 逻辑处理器 泛型
    ///  
    ///  : LogicHandler where T : EntityEx
    {
        /// 
        /// 业务类集合
        ///  
        protected List> Works = new();
        /// 
        /// TODO:?
        ///  
        private IEnumerable _objects = null;
        protected IEnumerable Objects
        {
            get
            {
                _objects ??= AllObjects.OfType().Where(SelectDevice)
                    .Select(v => Activator.CreateInstance(typeof(T), v)).OfType().ToArray();
                return _objects.Where(v => v.Entity.ENABLED && v.Entity.PROTOCOLS.All(d => d.ENABLED && d.DB.ENABLED && d.DB.PLC.ENABLED));
            }
        }
        /// 
        /// 写入设备信息
        ///  
        /// 
        /// 添加Work
        ///  
        ///  condition, Action work, bool parallel = false)
        {
            var title = work.Method.Name;
            var attr = work.Method.GetCustomAttributes(false).OfType().FirstOrDefault();
            if (attr != null)
                title = attr.Description;
            var arr = Objects.Where(condition).ToArray();
            this.Works.Add(new WorkInfo { Work = work, Params = arr, Title = title, Parallel = parallel });
        }
        /// 
        ///
        ///  
        ///  arr, Action work, bool parallel = false)
        {
            var title = work.Method.Name;
            var attr = work.Method.GetCustomAttributes(false).OfType().FirstOrDefault();
            if (attr != null)
                title = attr.Description;
            this.Works.Add(new WorkInfo { Work = work, Params = arr, Title = title, Parallel = parallel });
        }
        /// 
        /// 开始执行业务流程
        ///  
        /// 
        /// 执行Work
        ///  
        ///  work)
        {
            if (work.Parallel)
            {
                Parallel.ForEach(work.Params, p =>
                {
                    Do(work, p);
                });
            }
            else
            {
                foreach (var p in work.Params)
                {
                    Do(work, p);
                }
            }
        }
        /// 
        /// 开始执行
        ///  
        ///  wi, T p)
        {
            var channel = Description + "." + wi.Title + "." + p;
            try
            {
                Ltc.SetChannel(channel);
                Ltc.Log("开始---------------------------------------");
                wi.Work(p);
            }
            catch (DoException ex)
            {
                InfoLog.INFO_INFO($"[{channel}]--{ex.Message}");
            }
            //WarnException进阶条件未满足,添加数据库,记录文本日志、数据库,上抛WCS,上抛WMS
            catch (WarnException ex)
            {
                InfoLog.INFO_WARN($"[{channel}]--{ex.Message}");
                Ltc.Log(ex.GetBaseException().Message);
                Configs.UploadException?.Invoke(p.ToString(), ex.GetBaseException().Message);
            }
            //未知异常,仅记录文本日志,需定期排查该文件,检查系统是否有未知异常,并处理
            catch (Exception ex)
            {
                InfoLog.INFO_ERROR($"[{channel}]--{ex.Message}--{ex.StackTrace}");
            }
            finally
            {
                Ltc.Log("结束\n");
            }
        }
        /// 
        /// 此方法不会被自动调用,请在Start方法中使用AddWork将其添加至工作队列
        ///  
        ///  GetObjs();
        public abstract void Execute(object obj);
    }
    public abstract class Work : Work
    {
        public override sealed void Execute(object obj)
        {
            Do((T)obj);
        }
        public override sealed IEnumerable GetObjs()
        {
            return InitObjects().OfType().ToArray();
        }
        protected abstract void Do(T obj);
        protected abstract bool SelectDevice(WCS_DEVICE dev);
        protected virtual IEnumerable InitObjects()
        {
            var arr = Device.Where(v => v.ENABLED)
                     .Where(SelectDevice).ToArray();
            var res = arr.Select(v => (T)Activator.CreateInstance(typeof(T), v));
            return res;
        }
    }
    public abstract class DeviceWork : Work where T : EntityEx
    {
        private readonly string[] _typenames;
        protected DeviceWork()
        {
            _typenames = typeof(T).GenericTypeArguments.Select(v => v.AssemblyQualifiedName).ToArray();
        }
        protected abstract override void Do(T obj);
        protected override sealed IEnumerable InitObjects()
        {
            var arr = Device.Where(v => v.ENABLED && v.PROTOCOLS.All(d => d.ENABLED && d.DB.ENABLED && d.DB.PLC.ENABLED))
                   .Where(v => _typenames.All(d => v.PROTOCOLS.Any(e => e.DB.PROTOCOL == d)))
                   .Where(SelectDevice).ToArray();
            var res = arr.Select(v => Activator.CreateInstance(typeof(T), v) as T);
            return res;
        }
    }
}