using DbCommon.BusinessCore.BaseCore;
using DbCommon.Enties.DbModels;
using ProjectManagementSystem.Common.Config;
using ProjectManagementSystem.Common.Core;
using ProjectManagementSystem.Common.Extenions;
using ProjectManagementSystem.Common.Logger;
using ProjectManagementSystem.Device.CommandCallback;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ProjectManagementSystem.Dispatch
{
    /// <summary>
    /// 用于磁导航调度
    /// </summary>
    public class SimpleDispatch
    {
        protected CallTaskManager callTaskManager = new CallTaskManager();
        protected LocationPropertyManager locationManager = new LocationPropertyManager();

        public SimpleDispatch()
        {
            Task.Factory.StartNew(TaskThread);
        }

        private void ReleaseAgv(int mark, int route, string taskId = "")
        {
            var agvInfo = DeviceControl.Instance.Communication.InfoAgvDictionary.Values.FirstOrDefault(d => d.DataValid && d.Mark == mark);
            if (agvInfo == null)
            {
                CLog.Instance.TaskLog.WriteInfo($"{taskId}，ReleaseAgv，地标：{mark}，线路：{route}，没找到有效的AGV数据，放行取消！！！");
                return;
            }

            int agvId = agvInfo.AgvId;

            switch (agvInfo.StatusEnum)
            {
                case EnumInfoAgvStatus.停止点:
                    DeviceControl.Instance.ReleaseAgvOnStop(mark, route, agvId);
                    CLog.Instance.TaskLog.WriteInfo($"{taskId}，停止点放行，地标：{mark}，线路：{route}，AGVID：{agvId}");
                    break;
                case EnumInfoAgvStatus.结束点:
                    DeviceControl.Instance.ReleaseAgvOnStandby(mark, route, agvId);
                    CLog.Instance.TaskLog.WriteInfo($"{taskId}，待命点放行，地标：{mark}，线路：{route}，AGVID：{agvId}");
                    break;
                default:
                    CLog.Instance.TaskLog.WriteInfo($"{taskId}，ReleaseAgv，地标：{mark}，线路：{route}，AGVID：{agvId}，其他状态{agvInfo.StatusEnum}，放行取消！！！");
                    break;
            }
        }

        private void WriteTaskStatus(CallTask taskData)
        {
            string log = $"{taskData.TaskID}，{taskData.TaskStatus}，类型: {taskData.TaskType}，AGVID: {taskData.Carrier}，任务点: {taskData.AllWarehouse}，当前任务点: {taskData.CurrentWarehouse}";
            CLog.Instance.TaskLog.WriteInfo(log);
        }

        protected void WriteTaskInfo(CallTask taskData, string log)
        {
            if (taskData.Message != log)
            {
                taskData.Message = log;
                callTaskManager.Update(taskData);

                CLog.Instance.TaskLog.WriteInfo($"{taskData.TaskID}，{taskData.Carrier}号AGV：{log}");
            }
        }

        private bool UpdateTaskStatus(CallTask taskData, EnumTaskStatus status)
        {
            switch (status)
            {
                case EnumTaskStatus.叫料:
                    break;
                case EnumTaskStatus.任务创建:
                    taskData.CreateTime = DateTime.Now;
                    break;
                case EnumTaskStatus.任务启动:
                    taskData.StartTime = DateTime.Now;
                    break;
                case EnumTaskStatus.任务完成:
                    taskData.EndTime = DateTime.Now;
                    break;
                default:
                    break;
            }

            taskData.TaskStatus = status;
            bool result = callTaskManager.Update(taskData);
            if (result)
            {
                WriteTaskStatus(taskData);
            }
            return result;
        }

        private void CallTaskProc()//叫料任务处理
        {
            List<CallTask> taskDataList = callTaskManager.Query();

            if (taskDataList == null
                || taskDataList.Count == 0)
            {
                return;
            }

            for (int i = 0; i < taskDataList.Count; i++)
            {
                var taskData = taskDataList[i];
                switch (taskData.TaskStatus)
                {
                    case EnumTaskStatus.叫料:
                        UpdateTaskStatus(taskData, EnumTaskStatus.任务创建);
                        break;
                    case EnumTaskStatus.任务创建:
                        {
                            //查找待命点AGV
                            var infoAgv = GetStanByAgv(taskData.CurrentWarehouse);
                            if (infoAgv != null)
                            {
                                taskData.Carrier = infoAgv.AgvId;
                                taskData.StepStatus = EnumStepStatus.None;
                                taskData.StepMark = infoAgv.Mark;
                                taskData.StepRoute = taskData.Route;
                                taskData.StepLocation = taskData.CurrentWarehouse;

                                UpdateTaskStatus(taskData, EnumTaskStatus.任务启动);
                            }
                            else
                            {
                                WriteTaskInfo(taskData, $"缺待命AGV，{taskData.CurrentWarehouse}");
                            }
                        }
                        break;
                    case EnumTaskStatus.任务手动删除:
                        {
                            UpdateTaskStatus(taskData, EnumTaskStatus.任务手动删除处理);
                        }
                        break;
                    default:
                        break;
                }
            }

        }

        private void StationHasCarProcAllTask()
        {
            var taskList = callTaskManager.GetList(d => d.TaskStatus == EnumTaskStatus.任务启动);
            for (int i = 0; i < taskList.Count; i++)
            {
                var taskData = taskList[i];
                if (!DeviceControl.Instance.Communication.InfoAgvDictionary.ContainsKey(taskData.Carrier))//找到对应AGV的信息
                {
                    WriteTaskInfo(taskData, "没有AGV数据");
                    continue;
                }

                var agvInfo = DeviceControl.Instance.Communication.InfoAgvDictionary[taskData.Carrier];
                if (!agvInfo.DataValid)
                {
                    WriteTaskInfo(taskData, "AGV已掉线");
                    continue;
                }
                else
                {
                    if (taskData.Message == "AGV已掉线"
                        || taskData.Message == "没有AGV数据")
                    {
                        WriteTaskInfo(taskData, "AGV已在线");
                    }
                }

                if (agvInfo.AgvId != taskData.Carrier)
                {
                    WriteTaskInfo(taskData, "AGV编号不正确");
                    continue;
                }

                switch (taskData.StepStatus)
                {
                    case EnumStepStatus.None://步骤初始状态
                        {
                            if (agvInfo.Mark == taskData.StepMark
                                && agvInfo.InStation)
                            {
                                //AGV到指定地标停止点后，确认发车路线
                                if (StepInStation(taskData))
                                {
                                    taskData.StepStatus = EnumStepStatus.正在发车;
                                    taskData.StepLocation = taskData.CurrentWarehouse;

                                    callTaskManager.Update(taskData);

                                    WriteTaskInfo(taskData, $"准备发车前往位置 {taskData.StepLocation}，地标：{taskData.StepMark}，路线：{taskData.StepRoute}");
                                }
                            }
                            else
                            {
                                WriteTaskInfo(taskData, $"等待到达判断地标...{taskData.StepMark}");
                            }
                        }
                        break;
                    case EnumStepStatus.正在发车://正在发车状态
                        {
                            if (agvInfo.Mark != taskData.StepMark || agvInfo.StatusEnum == EnumInfoAgvStatus.运行)
                            {
                                //AGV已经跑到另外的地标，或状态运行，表示已经发车成功

                                WriteTaskInfo(taskData, $"已发车前往位置 {taskData.StepLocation} （AGV{agvInfo.AgvId}地标：{agvInfo.AgvId}，AGV状态：{agvInfo.StatusEnum}）");
                                taskData.StepStatus = EnumStepStatus.等待到达位置;
                                callTaskManager.Update(taskData);
                            }
                            else
                            {
                                WriteTaskInfo(taskData, $"正在发车前往位置 {taskData.StepLocation}");
                                ReleaseAgv(taskData.StepMark, taskData.StepRoute, taskData.TaskID);
                            }

                        }
                        break;
                    case EnumStepStatus.等待到达位置://已发车成功，等待达到库位
                        {
                            if (string.IsNullOrEmpty(taskData.StepLocation))
                            {
                                //如果没有下个要去的库位，任务完成
                                taskData.StepStatus = 0;
                                taskData.WarehouseIndex = 100;
                                UpdateTaskStatus(taskData, EnumTaskStatus.任务完成);
                                continue;
                            }

                            bool nextArrive = false;
                            int[] outRouteArray = taskData.StepLocation.GetLocationMember("出库路线").ToValueArray<int>();
                            int[] outMarkArray = taskData.StepLocation.GetLocationMember("出库地标").ToValueArray<int>();
                            if (outRouteArray.Contains(agvInfo.Route))
                            {
                                WriteTaskInfo(taskData, $"AGV{agvInfo.AgvId}已到{taskData.StepLocation}（出库路线：{agvInfo.Route}）");
                                nextArrive = true;
                            }
                            else
                            {
                                if (outMarkArray.Contains(agvInfo.Mark))
                                {
                                    WriteTaskInfo(taskData, $"AGV{agvInfo.AgvId}已到{taskData.StepLocation}（出库地标：{agvInfo.Mark}）");
                                    nextArrive = true;
                                }
                            }


                            if (nextArrive)
                            {
                                if(StepArriveLocation(taskData))
                                {
                                    //已经到达位置
                                    taskData.StepStatus = EnumStepStatus.None;
                                    taskData.StepRoute = 0;
                                    taskData.WarehouseIndex++;
                                    taskData.StepLocation = taskData.CurrentWarehouse;

                                    if (string.IsNullOrEmpty(taskData.CurrentWarehouse))
                                    {
                                        //判断任务是否完成
                                        UpdateTaskStatus(taskData, EnumTaskStatus.任务完成);
                                    }
                                    else
                                    {
                                        callTaskManager.Update(taskData);
                                    }
                                }

                            }
                            else
                            {
                                if (agvInfo.Mark == taskData.StepMark
                                    && agvInfo.InStation)
                                {
                                    WriteTaskInfo(taskData, $"重新发车前往位置{taskData.StepLocation} （AGV{agvInfo.AgvId}地标：{agvInfo.Mark}，AGV状态：{agvInfo.StatusEnum}）");
                                    ReleaseAgv(taskData.StepMark, taskData.StepRoute, taskData.TaskID);
                                }
                                else
                                {
                                    WriteTaskInfo(taskData, $"等待到达位置...{taskData.StepLocation} （出库路线：{string.Join(",", outRouteArray)} 出库地标：{string.Join(",", outMarkArray)}）");
                                }
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
        }

        private InfoAgv GetStanByAgv(string startLocation)
        {
            //获取已经分配任务的AGV编号集合
            int[] agvIdArray = callTaskManager
                .GetList(d => d.TaskStatus < EnumTaskStatus.任务完成 && d.Carrier > 0)
                .Select(d => d.Carrier)
                .ToArray();

            int[] standByArray = startLocation.GetLocationMember("待命点地标").ToValueArray<int>();

            var infoList = DeviceControl.Instance.Communication.InfoAgvDictionary.Values
                .Where(d => d.InStation && !agvIdArray.Contains(d.AgvId));

            if(standByArray.Length > 0)
            {
                for (int i = 0; i < standByArray.Length; i++)
                {
                    int mark = standByArray[i];

                    var agvInfo = infoList.FirstOrDefault(d => d.Mark == mark);
                    if (agvInfo != null)
                    {
                        return agvInfo;
                    }
                }

                return null;
            }
            else
            {
                return infoList.OrderBy(d => d.AgvId).FirstOrDefault();
            }
        }

        public virtual bool StepInStation(CallTask taskData)
        {
            return false;
        }

        public virtual bool StepArriveLocation(CallTask taskData)
        {
            return false;
        }

        private void TaskThread()
        {
            CLog.Instance.SystemLog.WriteDebug($"SimpleDispatch已启动");
            byte counter = 0;
            while (true)
            {
                try
                {
                    CallTaskProc();
                    StationHasCarProcAllTask();
                }
                catch (Exception ex)
                {
                    CLog.Instance.TaskLog.WriteException("SimpleDispatch", ex);
                    Thread.Sleep(5000);
                }

                if (counter == byte.MaxValue)
                {
                    callTaskManager.DeleteOldData();
                }

                counter++;
                Thread.Sleep(500);
            }
        }
    }
}
