using BPA.Message.Enum;
using BPASmartClient.Device;
using BPASmartClient.EventBus;
using BPASmartClient.GSIceCream;
using BPASmartClient.Helper;
using BPASmartClient.Lebai;
using BPASmartClient.LebaiRobot;
using BPASmartClient.Message;
using BPASmartClient.Model;
using BPASmartClient.Model.冰淇淋.Enum;
using BPASmartClient.Model.单片机;
using BPASmartClient.Model.单片机.Enum;
using BPASmartClient.Peripheral;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static BPASmartClient.EventBus.EventBus;

namespace BPASmartClient.MorkT
{
    public class Control_MorkT : BaseDevice
    {
        public override global::BPA.Message.Enum.DeviceClientType DeviceType { get { return BPA.Message.Enum.DeviceClientType.MORKT; } }

        GLV_MorkT morkT = new GLV_MorkT();

        public override void DoMain()
        {
            IsHealth = true;
            ServerInit();
            DataParse();
            EventBus.EventBus.GetInstance().Subscribe<DRCoffee_CoffeEndCookEvent>(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack)
            {
                if (morkT.MakeCoffeeOrder != null)
                    morkT.MakeCoffeeOrder.OrderStatus = 1;
            });

            ActionManage.GetInstance.Register(new Action<object>((o) =>
            {
                switch (o)
                {
                    case "机器人启动":
                        LebaiHelper.GetInstance().StartRobot();
                        break;
                    case "启动示教":
                        LebaiHelper.GetInstance().StartTeachMode();
                        break;
                    case "停止示教":
                        LebaiHelper.GetInstance().EndtTeachMode();
                        break;
                    case "机器人急停":
                        LebaiHelper.GetInstance().EStopRobot();
                        break;
                    default:
                        break;
                }
            }),"调试控制-机器人控制");
         
            MessageLog.GetInstance.Show("MORKT 设备初始化完成");

        }

        public override void ResetProgram()
        {
            morkT = null;
            morkT = new GLV_MorkT();
        }

        public override void MainTask()
        {
            MakeCoffeeProcess();
            if(!LebaiHelper.GetInstance().GetInput())//取餐口有空余位置
            {
                MakeIceCreamProcess();
                MakeCoffeeComplete();
            }
        }

        public override void ReadData()
        {
            morkT.lebai = LebaiHelper.GetInstance().GetValueAsync();
            LebaiHelper.GetInstance().GetRobotModeStatus();
        }



        public override void Stop()
        {
        }


        private void ServerInit()
        {
            //物料信息
            EventBus.EventBus.GetInstance().Subscribe<MaterialDeliveryEvent>(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack)
            {
                if (@event == null) return;
                if (@event is MaterialDeliveryEvent material)
                {
                    orderMaterialDelivery = material.orderMaterialDelivery;
                }
            });

            //配方数据信息
            EventBus.EventBus.GetInstance().Subscribe<RecipeBomEvent>(DeviceId, delegate (IEvent @event, EventCallBackHandle callBack)
            {
                if (@event == null) return;
                if (@event is RecipeBomEvent recipe)
                {
                    recipeBoms = recipe.recipeBoms;
                }
            });
        }

        /// <summary>
        /// 数据解析
        /// </summary>
        private void DataParse()
        {
            EventBus.EventBus.GetInstance().Subscribe<DoOrderEvent>(DeviceId, delegate (IEvent @event, EventCallBackHandle callBackHandle)
            {
                if (@event == null) return;
                if (@event is DoOrderEvent order)
                {
                    if (order.MorkOrder.GoodBatchings == null) return;
                    OrderCount++;
                    DeviceProcessLogShow($"接收到{OrderCount}次订单");
                    //构建所有商品物料信息
                    morkT.batchings = PolymerBatching.BuildAll();
                    //商品类型
                    GOODS_TYPE currentGoodsType = GOODS_TYPE.NEITHER;
                    string loc_Goods = string.Empty;
                    foreach (var item in order.MorkOrder.GoodBatchings)
                    {
                        var res = orderMaterialDelivery?.BatchingInfo?.FirstOrDefault(p => p.BatchingId == item.BatchingId);
                        if (res != null)
                        {
                            //验证商品是咖啡还是冰淇淋
                            if (ValidateGoodsByBatching(res.BatchingLoc) != GOODS_TYPE.NEITHER)
                            {
                                //获取当前物料所属商品类型
                                currentGoodsType = ValidateGoodsByBatching(res.BatchingLoc);
                            }

                            //获取主料和容器位置
                            if (morkT.batchings[res.BatchingLoc].BatchingClass == BATCHING_CLASS.MAIN_MATERIAL) loc_Goods = res.BatchingLoc;

                            switch (currentGoodsType)
                            {
                                case GOODS_TYPE.COFFEE:
                                    if (morkT.morkOrderPushesCoffee.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null)
                                    {
                                        morkT.morkOrderPushesCoffee.Enqueue(new OrderLocInfo()
                                        {
                                            SuborderId = order.MorkOrder.SuborderId,
                                            BatchingId = res.BatchingId,
                                            Loc = loc_Goods,
                                            GoodsName = order.MorkOrder.GoodsName,
                                            SortNum = order.MorkOrder.SortNum
                                        }) ;
                                    }
                                    break;
                                case GOODS_TYPE.ICECREAM:
                                    if (morkT.morkOrderPushesIceCream.FirstOrDefault(p => p.SuborderId == order.MorkOrder.SuborderId) == null)
                                    {
                                        morkT.morkOrderPushesIceCream.Enqueue(new OrderLocInfo()
                                        {
                                            SuborderId = order.MorkOrder.SuborderId,
                                            BatchingId = res.BatchingId,
                                            Loc = loc_Goods,
                                            GoodsName = order.MorkOrder.GoodsName,
                                            SortNum = order.MorkOrder.SortNum
                                        });
                                    }
                                    break;
                                case GOODS_TYPE.NEITHER:
                                    DeviceProcessLogShow("未知的商品类型");
                                    break;
                            }
                        }
                    }

                }
            });
        }

        /// <summary>
        /// 验证当前是做咖啡还是做冰淇淋
        /// </summary>
        /// <param name="batchingLoc">物料位置</param>
        private GOODS_TYPE ValidateGoodsByBatching(string batchingLoc)
        {
            if (morkT.batchings.ContainsKey(batchingLoc))
                return morkT.batchings[batchingLoc].GoodsType;
            return GOODS_TYPE.NEITHER;
        }
      

       

        private void OrderChange(string subid, ORDER_STATUS oRDER_STATUS)
        {
            EventBus.EventBus.GetInstance().Publish(new OrderStatusChangedEvent() { Status = oRDER_STATUS, SubOrderId = subid, deviceClientType = DeviceType });
        }

        private void Wait(int value = 101)
        {
            while (!(morkT.lebai.Ok && morkT.lebai.Value == value))
            {
                Thread.Sleep(5);
            }
        }

        /// <summary>
        /// 是否可以开始制作咖啡
        /// </summary>
        /// <returns></returns>
        private bool CoffeeCanMake()
        {
            bool canMake = (IsHealth && morkT.morkOrderPushesCoffee.Count > 0 && !morkT.IsCoffeeMake) ? true : false;
            return canMake;

        }

        /// <summary>
        /// 制作咖啡流程
        /// </summary>
        private void MakeCoffeeProcess()
        {
            if (CoffeeCanMake())
            {
                if (morkT.morkOrderPushesCoffee.TryDequeue(out OrderLocInfo orderLoc))
                {
                    DeviceProcessLogShow($"开始制作 [咖啡] 订单[{orderLoc.SortNum}]");
                    GetAndCheeckCoffe(orderLoc);
                    LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_接咖啡后回原点);//把咖啡杯放到咖啡机机的位置后回原点
                    Wait();
                    LebaiHelper.GetInstance().SetValue(1);
                    new DRCoffee_MakeCoffeeEvent() { DrinkCode = (Model.咖啡机.Enum.DrCoffeeDrinksCode)int.Parse(orderLoc.Loc) }.Publish();  //接咖啡控制
                    DeviceProcessLogShow($"发送咖啡机制作{orderLoc.Loc}!");
                    morkT.IsCoffeeMake = true; morkT.MakeCoffeeOrder = orderLoc;
                }

            }


        }
        /// <summary>
        /// 咖啡机制作完咖啡，取走并放到取餐口，最后回原点
        /// </summary>
        private void MakeCoffeeComplete()
        {
            if (morkT.IsCoffeeMake && IsHealth)
            {
                if (morkT.MakeCoffeeOrder != null && morkT.MakeCoffeeOrder.OrderStatus == 1)
                {
                    DeviceProcessLogShow($"将咖啡移动到取餐位 [咖啡] 订单[{morkT.MakeCoffeeOrder.SortNum}]");
                    DoCoffeeQC(morkT.MakeCoffeeOrder);
                    morkT.MakeCoffeeOrder = null;
                    morkT.IsCoffeeMake = false;
                }
            }
        }


        /// <summary>
        /// 将咖啡杯从咖啡机 取走到 取餐口
        /// </summary>
        private void DoCoffeeQC(OrderLocInfo order)
        {
            LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_取咖啡出餐);
            Wait();
            LebaiHelper.GetInstance().SetValue(1);
            //订单状态改变：完成
            OrderChange(order.SuborderId, ORDER_STATUS.COMPLETED_COOK);
            DeviceProcessLogShow($"{order.GoodsName}等待取餐");
            //WaitTakeMealOrder.Enqueue(order);

        }

        /// <summary>
        /// 取咖啡杯&&咖啡杯检测 若检测失败机器人回原点
        /// </summary>
        /// <param name="order"></param>
        private void GetAndCheeckCoffe(OrderLocInfo order)
        {
            LebaiHelper.GetInstance().SetValue(0);
            OrderChange(order.SuborderId, ORDER_STATUS.COOKING);
            LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_取咖啡杯);
            Wait();
            new SCChip_TakeCupEvent() { Cup = IC_CUP.CUP_COFFEE }.Publish();//落碗控制
            Thread.Sleep(500);
            DeviceProcessLogShow("尝试取咖啡杯!");
            LebaiHelper.GetInstance().SetValue(1);
            int count = 2;
        p:
            LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_咖啡杯检测);
            Wait();
            LebaiHelper.GetInstance().SetValue(1);

            if (!LebaiHelper.GetInstance().GetInput())
            {
                if (count >= 3)
                {
                    //退出循环回到初始位置
                    DeviceProcessLogShow($"执行{count}次取咖啡杯,仍为成功,订单默认废弃,机器人回到初始位置!");
                    LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_咖啡杯回原点);
                    Wait();
                    LebaiHelper.GetInstance().SetValue(1);
                    return;
                }
                DeviceProcessLogShow("执行二次取咖啡杯");
                LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_二次取咖啡杯);
                Wait();
                new SCChip_TakeCupEvent() { Cup = IC_CUP.CUP_COFFEE }.Publish();//落碗控制
                LebaiHelper.GetInstance().SetValue(1);
                count++;
                goto p;
            }
            DeviceProcessLogShow("取咖啡杯完成");
        }

        /// <summary>
        /// 冰淇淋是否可以开始制作
        /// </summary>
        /// <returns></returns>
        private bool IceCreamCanMake()
        {
            bool canMake = (IsHealth && morkT.morkOrderPushesIceCream.Count > 0) ? true : false;
            return canMake;
        }

        /// <summary>
        /// 制作冰淇淋流程
        /// </summary>
        private void MakeIceCreamProcess()
        {
            if (IceCreamCanMake())
            {
                if(Status.status.ContainsKey("CurrentMode"))
                {
                    if ((MORKI_MODE)Status.status["CurrentMode"] != MORKI_MODE.制冷模式) new GSIceCream_ModeSetEvent() { Mode = MORKI_MODE.制冷模式 }.Publish();
                }

                if(Status.status.ContainsKey("CBX"))
                {
                    if ((short)Status.status["CBX"] >= 86 && morkT.morkOrderPushesIceCream.Count > 0)//成型比大于86才可以制作
                    {
                        if (LebaiHelper.GetInstance().GetInput(3))
                        {
                            if (morkT.IceIsOK) DeviceProcessLogShow("请检查冰淇淋出料口有无遮挡");
                            morkT.IceIsOK = false;
                        }
                        else if (morkT.morkOrderPushesIceCream.TryDequeue(out OrderLocInfo order))
                        {
                            morkT.IceIsOK = true;
                            DeviceProcessLogShow($"开始制作 [冰淇淋] 订单[{order.SortNum}]");
                            DoIceCream(order);
                        }
                    }
                }
                
            }
        }


        /// <summary>
        /// 做冰淇淋
        /// </summary>
        private void DoIceCream(OrderLocInfo order)
        {
            GetIceCreamCup();
            CheckICeCreaCup();
            GetIceCream(order);
            PutIceCream(order);
        }

        /// <summary>
        /// 取冰淇淋杯
        /// </summary>
        private void GetIceCreamCup()
        {
            LebaiHelper.GetInstance().SetValue(0);
            LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_取冰淇淋杯);
            Wait();
            new SCChip_TakeCupEvent() { Cup = IC_CUP.CUP_ICECREAM }.Publish();//落碗控制
            Thread.Sleep(500);
            DeviceProcessLogShow("尝试取冰淇淋杯!");

        }

        /// <summary>
        /// 冰淇淋杯检测，失败后机器人回到原点
        /// </summary>
        private void CheckICeCreaCup()
        {
            int count = 2;
            LebaiHelper.GetInstance().SetValue(1);
        p:
            LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_冰淇淋杯检测);
            Wait();
            LebaiHelper.GetInstance().SetValue(1);
            if (!LebaiHelper.GetInstance().GetInput())
            {
                if (count >= 3)
                {
                    //退出循环回到初始位置
                    DeviceProcessLogShow($"执行{count}次取冰淇淋杯,仍未成功,订单默认废弃,机器人回到初始位置!");
                    LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_冰淇淋杯回原点);
                    Wait();
                    LebaiHelper.GetInstance().SetValue(1);
                    return;
                }
                DeviceProcessLogShow($"执行{count}次取冰淇淋杯!");
                LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_二次取冰淇淋杯);
                new SCChip_TakeCupEvent() { Cup = IC_CUP.CUP_ICECREAM }.Publish();//落碗控制
                Wait();
                LebaiHelper.GetInstance().SetValue(1);
                count++;
                goto p;
            }
            DeviceProcessLogShow("冰淇淋杯检测完成");
        }

        /// <summary>
        /// 机器人取接冰淇淋
        /// </summary>
        /// <param name="order"></param>
        private void GetIceCream(OrderLocInfo order)
        {
            //制冷模式
            new GSIceCream_ModeSetEvent() { Mode = MORKI_MODE.制冷模式 }.Publish();
            LebaiHelper.GetInstance().SetValue(0);
            OrderChange(order.SuborderId, ORDER_STATUS.COOKING);
            LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_接1号冰淇淋);
            Wait();
            bool doItResult = true;
            //出料
            new GSIceCream_DischargeEvent().Publish(delegate (object[] args)
            {
                doItResult = (bool)args[0];
            });
            if (doItResult)
            {
                IceCreamCookCheck();
            }
            else
            {
                int count_1 = 0;

                while ((short)Status.status["CBX"] <= 86)
                {
                    Thread.Sleep(5);
                    count_1++;
                    if (count_1 >= 2000)
                        break;
                }
                IceCreamCookCheck();
            }
            LebaiHelper.GetInstance().SetValue(1);
        }

        /// <summary>
        /// 把冰淇淋放到取餐位后回原点
        /// </summary>
        /// <param name="order"></param>
        private void PutIceCream(OrderLocInfo order)
        {
            while (LebaiHelper.GetInstance().GetInput())
            {
                Thread.Sleep(500);
            }
            LebaiHelper.GetInstance().Scene(LebaiHelper.SENCE_放冰淇淋位置);
            Wait();
            LebaiHelper.GetInstance().SetValue(1);
            //订单状态改变：完成
            OrderChange(order.SuborderId, ORDER_STATUS.COMPLETED_COOK);
            DeviceProcessLogShow($"{order.GoodsName}等待取餐");
            //WaitTakeMealOrder.Enqueue(order);

        }

        /// <summary>
        /// 冰淇淋机器制作冰淇淋
        /// </summary>
        public void IceCreamCookCheck()
        {
            int retry = 3;
            DateTime beginTime = DateTime.Now;
            while (!LebaiHelper.GetInstance().GetInput(3))
            {
                if (retry <= 0 && DateTime.Now.Subtract(beginTime).TotalSeconds >= 10)
                {
                    DeviceProcessLogShow("超时未出料，重试次数用尽");
                    break;
                }
                if (DateTime.Now.Subtract(beginTime).TotalSeconds > 5)
                {
                    DeviceProcessLogShow("超时未出料，重新发送打料指令");
                    new GSIceCream_ModeSetEvent() { Mode = MORKI_MODE.打料 }.Publish();
                    beginTime = DateTime.Now;
                    retry--;
                }
                Thread.Sleep(10);
            }
            DeviceProcessLogShow("开始等待6s");
            Thread.Sleep(5000);

        }
    }
}
