using Pms.DataLibrary.Order;
using Pms.Models;
using ProjectManagementSystem.Common.Extenions;
using ProjectManagementSystem.Common.Logger;
using ProjectManagementSystem.Common.WebApi;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ProjectManagementSystem.Common.Core
{
    public class TaskBehavior
    {
        private static TaskBehavior m_instance;

        private static ConcurrentDictionary<string, string> tempLog = new ConcurrentDictionary<string, string>();

        public static ConcurrentDictionary<int, BaseTaskBookBehaviorV2> BehaviorDict { get; set; } = new ConcurrentDictionary<int, BaseTaskBookBehaviorV2>();
        public static ConcurrentDictionary<int, PmsBehaviorLoop> PmsBehaviorLoopDict { get; set; } = new ConcurrentDictionary<int, PmsBehaviorLoop>();
        public static TaskBehavior Instance
        {
            get
            {
                if (m_instance == null)
                {
                    m_instance = new TaskBehavior();
                    if (!m_instance.Initialize())
                    {
                        m_instance = null;
                    }
                }
                return m_instance;
            }
        }

        private TaskBehavior()
        {
        }


        private static bool CheckLogRepeat(string taskId, string log)
        {
            bool result = tempLog.ContainsKey(taskId) ? tempLog[taskId] == log : false;

            tempLog.AddOrUpdate(taskId, log, (key, vaule) => log);
            return result;
        }

        public static void Log(TaskData taskData, StepData stepData, string log)
        {
            string strLog = $"{taskData.TaskID} Step{taskData.CurrentStepID} {stepData.PmsBehavior} {stepData.AgvBehavior} {taskData.Carrier}# {stepData.WareHouseID} {log}";

            if (CheckLogRepeat(taskData.TaskID, log)) return;

            CLog.Instance.GetAgvLog(taskData.Carrier).WriteInfo(strLog);
        }

        public static void RemoveTempLog(string taskId)
        {
            if (string.IsNullOrEmpty(taskId)) return;
            tempLog.TryRemove(taskId, out string _);
        }

        public static string GetTempLog(string taskId)
        {
            if (string.IsNullOrEmpty(taskId)) return null;
            return tempLog.ContainsKey(taskId) ? tempLog[taskId] : null;
        }

        private bool Initialize()
        {
            try
            {
                Task.Factory.StartNew(UserThread);
                return true;
            }
            catch (Exception ex)
            {
                CLog.Instance.SystemLog.WriteException("TaskBehavior Initialize", ex);
            }

            return false;
        }

        private void ProcessPmsBehavior()
        {
            DateTime start = DateTime.Now;

            var dataDict = PmsApi.GetPmsBehavior();
            if (dataDict == null || dataDict.Count == 0) return;

            var taskList = PmsApi.GetTaskList();
            if (taskList == null || taskList.Count == 0) return;

            Parallel.ForEach(dataDict.Values, data =>
            {
                try
                {
                    if (!BehaviorDict.ContainsKey(data.PmsBehavior)) return;

                    //获取任务数据
                    var taskData = taskList.FirstOrDefault(d => d.TaskID == data.TaskId);
                    if (taskData == null) return;

                    var stepList = PmsApi.GetStepList(data.TaskId);
                    if (stepList == null) return;

                    taskData.StepList = stepList;
                    var stepData = taskData.GetCurrentStepInfo();
                    if (stepData == null) return;
                    if (stepData.PmsBehavior != data.PmsBehavior) return;

                    var taskApiTimeSpan = (DateTime.Now - start).TotalMilliseconds;

                    //执行PMS行为码
                    DateTime start3 = DateTime.Now;
                    bool result = BehaviorDict[data.PmsBehavior].TaskBookOperator(taskData, stepData);
                    var operatorTimeSpan = (DateTime.Now - start3).TotalMilliseconds;

                    //上报PMS行为码
                    if (result)
                    {
                        bool setResult = PmsApi.SetPmsBehaviorFinish(data.TaskId, taskData.Carrier, data.PmsBehavior);

                        var totalTimeSpan = (DateTime.Now - start).TotalMilliseconds;
                        CLog.Instance.GetAgvLog(taskData.Carrier).WriteDebug($"{data.TaskId} Step{taskData.CurrentStepID} {data.PmsBehavior} {data.agvId}# PMS行为码完成上报{setResult.ToChineseString()}" +
                            $" 耗时: {taskApiTimeSpan:F1}ms {operatorTimeSpan:F1}ms 总耗时:{totalTimeSpan:F1}ms");
                    }
                }
                catch (Exception ex)
                {
                    CLog.Instance.SystemLog.WriteExceptionCaller(ex);
                }

            });
        }

        private void ProcessPmsBehaviorTask()
        {
            //独立线程执行
            var dataDict = PmsApi.GetPmsBehavior();
            if (dataDict == null || dataDict.Count == 0) return;

            var dataDictValues = dataDict.Values.ToArray();
            foreach (var item in dataDictValues)
            {
                if (!BehaviorDict.ContainsKey(item.PmsBehavior)) continue;

                if (!PmsBehaviorLoopDict.ContainsKey(item.agvId))
                {
                    PmsBehaviorLoop loop = new PmsBehaviorLoop();
                    loop.BehavoirInfo = item;
                    loop.Start();

                    PmsBehaviorLoopDict.AddOrUpdate(loop.AgvId, loop, (key, value) => loop);
                }
                else
                {
                    var loop = PmsBehaviorLoopDict[item.agvId];
                    if (!loop.IsStart)
                    {
                        loop.BehavoirInfo = item;
                        loop.Start();
                    }
                }
            }
        }

        private void UserThread()
        {
            CLog.Instance.SystemLog.WriteDebug($"TaskBehavior已启动");
            while (true)
            {
                try
                {
                    ProcessPmsBehaviorTask();
                }
                catch (Exception ex)
                {
                    CLog.Instance.SystemLog.WriteException("TaskBehavior", ex);
                    Thread.Sleep(5000);
                }
                Thread.Sleep(100);
            }
        }
    }

    public class PmsBehaviorLoop
    {

        public int AgvId { get { return BehavoirInfo.agvId; } }
        public bool IsStart { get; set; }

        public RequestPmsTaskInfo BehavoirInfo { get; set; }

        public PmsBehaviorLoop()
        {

        }

        public void Start()
        {
            IsStart = true;
            Task.Factory.StartNew(UserThread);
        }

        private bool Process()
        {
            DateTime start = DateTime.Now;

            var dataDict = PmsApi.GetPmsBehavior();
            if (dataDict == null)
            {
                LogDebug("获取所有PMS行为码失败");
                return true;
            }

            if (dataDict.Count == 0)
            {
                LogDebug("获取所有PMS行为码数量为0");
                return true;
            }

            var find = dataDict.Values.FirstOrDefault(d => d.TaskId == BehavoirInfo.TaskId && d.PmsBehavior == BehavoirInfo.PmsBehavior && d.agvId == BehavoirInfo.agvId);
            if (find == null)
            {
                LogDebug("未找到当前PMS行为码");
                return true;
            }

            //获取任务数据
            var taskData = PmsApi.GetTaskData(BehavoirInfo.TaskId);
            if (taskData == null)
            {
                LogDebug("获取当前任务失败");
                return true;
            }

            var stepData = taskData.GetCurrentStepInfo();
            if (stepData == null)
            {
                LogDebug("获取当前任务StepData失败");
                return true;
            }

            if (stepData.PmsBehavior != BehavoirInfo.PmsBehavior)
            {
                LogDebug($"PMS行为码不匹配，当前任务Step{taskData.CurrentStepID} {stepData.PmsBehavior}");
                return true;
            }

            var taskApiTimeSpan = (DateTime.Now - start).TotalMilliseconds;


            //执行PMS行为码
            DateTime start3 = DateTime.Now;
            bool result = TaskBehavior.BehaviorDict[BehavoirInfo.PmsBehavior].TaskBookOperator(taskData, stepData);
            var operatorTimeSpan = (DateTime.Now - start3).TotalMilliseconds;

            //上报PMS行为码
            if (result)
            {
                bool setResult = PmsApi.SetPmsBehaviorFinish(BehavoirInfo.TaskId, taskData.Carrier, BehavoirInfo.PmsBehavior);

                var totalTimeSpan = (DateTime.Now - start).TotalMilliseconds;
                CLog.Instance.GetAgvLog(taskData.Carrier).WriteDebug($"{BehavoirInfo.TaskId} Step{taskData.CurrentStepID} {BehavoirInfo.PmsBehavior} {BehavoirInfo.agvId}# PMS行为码完成上报{setResult.ToChineseString()}" +
                    $" 耗时: {taskApiTimeSpan:F1}ms {operatorTimeSpan:F1}ms 总耗时:{totalTimeSpan:F1}ms");

                return setResult;
            }

            return false;
        }

        private void LogDebug(string log)
        {
            CLog.Instance.GetAgvLog(BehavoirInfo.agvId).WriteDebug($"{BehavoirInfo.TaskId} {BehavoirInfo.PmsBehavior} {BehavoirInfo.agvId}# {log}");
        }

        private void UserThread()
        {
            LogDebug("PmsBehaviorLoop已启动");
            while (IsStart)
            {
                bool processResult = false;
                try
                {
                    processResult = Process();

                    if (processResult)
                    {
                        TaskBehavior.RemoveTempLog(BehavoirInfo.TaskId);
                    }
                }
                catch (Exception ex)
                {
                    CLog.Instance.SystemLog.WriteException("PmsBehaviorLoop", ex);
                    Thread.Sleep(5000);

                    //抛异常退出循环
                    processResult = true;
                }

                if (processResult)
                {
                    break;
                }

                Thread.Sleep(100);
            }
            LogDebug("PmsBehaviorLoop已退出");
            IsStart = false;
        }
    }

    public abstract class BaseTaskBookBehaviorV2
    {
        public int Behavior { get; set; }
        public string Remark { get; set; }
        public BaseTaskBookBehaviorV2(int behavior, string remark)
        {
            Behavior = behavior;
            Remark = remark;

            TaskBehavior.BehaviorDict.AddOrUpdate(Behavior, this, (key, value) => this);
        }

        public abstract bool TaskBookOperator(TaskData taskData, StepData stepData);

        public void Log(TaskData taskData, StepData stepData, string log)
        {
            TaskBehavior.Log(taskData, stepData, log);
        }

        public void LogException(Exception ex)
        {
            CLog.Instance.TaskLog.WriteException("TaskBookBehavior", ex);
        }
    }
}
