using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Sorter.Common;
using Aitex.Core.Common;
using Venus_RT.Devices;
using MECF.Framework.Common.Routine;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.SubstrateTrackings;
using Venus_Core;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using Venus_RT.Modules.PMs;
using MECF.Framework.Common.Schedulers;
using System.Collections.Generic;
using System;
using MECF.Framework.Common.DBCore;

namespace Venus_RT.Modules.TM
{
    class MFPMPickRoutine : ModuleRoutineBase, IRoutine
    {
        private enum PickStep
        {
            WaitPMReady,
            PMPrepare,           
            ArmExtend,
            QueryAWC,
            DropDownWafer,
            PickDelay,
            ArmRetract,
            SavePickeData,
            NotifyDone,
        }
        private enum PickStepWithHeater
        {
            WaitPMReady,
            WaitPressreDifference,
            PMPrepare,
            Picking,   
            QueryAWC,
            SavePickeData,
            NotifyDone,
        }
        private readonly JetTM _JetTM;
        private readonly ITransferRobot _robot;

        private int _pickingTimeout = 120 * 1000;
        private int _pickDelayTime = 0;
        private ModuleName _targetModule;
        private PMEntity  _pmModule;
        private int _targetSlot;
        private Hand _hand;

        private DateTime _starttime;
        private bool _queryAwc;

        double maxPressureDifference ;

        public MFPMPickRoutine(JetTM tm, ITransferRobot robot) : base(ModuleName.TMRobot)
        {
            _JetTM = tm;
            _robot = robot;
            Name = "Pick from PM";

            if (SC.GetValue<int>($"TM.QueryAWCOption") == 1 || SC.GetValue<int>($"TM.QueryAWCOption") == 3)
                _queryAwc = true;
            else
                _queryAwc = false;

            maxPressureDifference=SC.GetValue<double>("System.PMTMMaxPressureDifference");
        }
        public RState Start(params object[] objs)
        {
            _starttime = DateTime.Now;
            if (!_robot.IsHomed)
            {
                LOG.Write(eEvent.ERR_TM, Module, $"TM Robot is not homed, please home it first");
                return RState.Failed;
            }

            var pickItem = (Queue<MoveItem>)objs[0];
            _targetModule = pickItem.Peek().SourceModule;
            _targetSlot = pickItem.Peek().SourceSlot;
            _hand = pickItem.Peek().RobotHand;

            if (ModuleHelper.IsPm(_targetModule) && ModuleHelper.IsInstalled(_targetModule))
            {
                _pmModule = Singleton<RouteManager>.Instance.GetPM(_targetModule);
            }
            else
            {
                LOG.Write(eEvent.ERR_TM, Module, $"Invalid target module : {_targetModule} for picking action");
                return RState.Failed;
            }

            if (WaferManager.Instance.CheckHasWafer(ModuleName.TMRobot, (int)_hand))
            {
                LOG.Write(eEvent.ERR_TM, Module, $"Cannot pick as TM Robot Arm: {_hand} already has a wafer");
                return RState.Failed;
            }

            if (WaferManager.Instance.CheckNoWafer(_targetModule, _targetSlot))
            {
                LOG.Write(eEvent.ERR_TM, Module, $"Cannot pick as {_targetModule} Slot {_targetSlot + 1} has no wafer");
                return RState.Failed;
            }

            var wafer = WaferManager.Instance.GetWafer(_targetModule, _targetSlot);
            if(wafer.ChuckState == EnumWaferChuckStatus.Chucked)
            {
                LOG.Write(eEvent.ERR_TM, Module, $"Cannot pick the wafer in {_targetModule }as the wafer is chucked");
                return RState.Failed;
            }
            LOG.Write(eEvent.INFO_TM_ROBOT, ModuleName.TMRobot, $"{wafer.WaferOrigin} will be move from {_targetModule} {_targetSlot + 1} to TM Robot {_hand}");

            Reset();
            _pickingTimeout = SC.GetValue<int>("TM.PickTimeout") * 1000;
            _pickDelayTime = SC.GetValue<int>($"{_targetModule}.PickDelayTime");

            return Runner.Start(Module, $"Pick from {_targetModule}");
        }

        public RState Monitor()
        {
            switch (_pmModule.ChamberType)
            {
                case JetChamber.Venus:
                case JetChamber.Kepler2300:
          Runner.Wait(PickStep.WaitPMReady,          () => _pmModule.IsIdle, _delay_60s)
                .Run(PickStep.PMPrepare,             ModulePrepare,      IsModulePrepareReady)
                .Run(PickStep.ArmExtend,             ArmExtend,          WaitRobotExtendDone)
                .Run(PickStep.QueryAWC,              QueryAWC,           WaitRobotQueryDone,    _delay_1s)
                .Run(PickStep.DropDownWafer,         NotifyPMPickWafer,  WaitPMWaferDropDown)
                .Delay(PickStep.PickDelay, _pickDelayTime)
                .Run(PickStep.ArmRetract,            ArmRetract,         WaitRobotRetractDone)
                .Run(PickStep.SavePickeData,         RecordAWCData,      NullFun)
                .End(PickStep.NotifyDone,            NotifyPMDone,                               _delay_50ms);
                break;

                case JetChamber.Kepler2200A:
                case JetChamber.Kepler2200B:
         Runner.Wait(PickStepWithHeater.WaitPMReady,           () => _pmModule.IsIdle, _delay_60s)
               .Wait(PickStepWithHeater.WaitPressreDifference,   TMPMPressureIsOK, _delay_60s)
               .Run(PickStepWithHeater.PMPrepare,              ModulePrepare,      IsModulePrepareReady)
               .Run(PickStepWithHeater.Picking,                Picking,            WaitPickDone)
               .Run(PickStepWithHeater.QueryAWC,               QueryAWC,           WaitRobotQueryDone)
               .Run(PickStepWithHeater.SavePickeData,          RecordAWCData,      NullFun)
               .End(PickStepWithHeater.NotifyDone,             NotifyPMDone,                                 _delay_1s);
                break;
            }
            

            return Runner.Status;
        }

        private bool TMPMPressureIsOK()
        {
            if (Math.Abs((_pmModule.ChamberPressure - _JetTM.ChamberPressure)) < maxPressureDifference)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        private bool ModulePrepare()
        {
            _pmModule.PostMsg(PMEntity.MSG.PreparePick);
            return true;
        }

        private bool IsModulePrepareReady()
        {
            return _pmModule.Status == PMEntity.PMStatus.Ready_For_Pick && _pmModule.IsSlitDoorOpen;
        }
        private bool Picking()
        {
            return _robot.Pick(_targetModule, _targetSlot, _hand);
        }

        private bool WaitPickDone()
        {
            if (_robot.Status == RState.Running)
            {
                return false;
            }
            else if (_robot.Status == RState.End)
            {
                //WaferManager.Instance.WaferMoved(ModuleName.TM, (int)_hand, _targetModule, _targetSlot);
                WaferManager.Instance.WaferMoved(_targetModule, _targetSlot, ModuleName.TMRobot, (int)_hand);

                return true;
            }
            else
            {
                Runner.Stop($"TM Robot Picking failed, {_robot.Status}");
                return true;
            }
        }
        private bool ArmExtend()
        {
            return _robot.PickExtend(_targetModule, _targetSlot, _hand);
        }
        private bool ArmRetract()
        {
            return _robot.PickRetract(_targetModule, _targetSlot, _hand);
        }

        private bool WaitRobotExtendDone()
        {
            if (_robot.Status == RState.Running)
            {
                return false;
            }
            else if (_robot.Status == RState.End)
            {
                WaferManager.Instance.WaferMoved(_targetModule, _targetSlot, ModuleName.TMRobot, (int)_hand);
                return true;
            }
            else
            {
                Runner.Stop($"TM Robot Pick Extend failed, {_robot.Status}");
                return true;
            }
        }

        private bool QueryAWC()
        {
            if (!_queryAwc)
                return true;
            else
                return _robot.QueryAwc(); ;
        }

        private bool WaitRobotQueryDone()
        {
            if (!_queryAwc)
                return true;

            if (_robot.Status == RState.Running)
            {
                return false;
            }
            else if (_robot.Status == RState.End)
            {
                return true;
            }
            else
            {
                Runner.Stop($"TM Robot Query Awc failed, {_robot.Status}");
                return true;
            }
        }

        private bool RecordAWCData()
        {
            if (!_queryAwc)
                return true;

            //已经move后的数据
            string _origin_module = $"LP{WaferManager.Instance.GetWafer(_targetModule, _targetSlot).OriginStation}";
            int _origin_slot = WaferManager.Instance.GetWafer(_targetModule, _targetSlot).OriginSlot;
            //查询完毕 插入数据
            OffsetDataRecorder.RecordOffsetData(
                Guid.NewGuid().ToString(),
                _targetModule, _targetSlot,
                ModuleName.TMRobot, 0,
                _origin_module, _origin_slot,
                _hand, RobotArmPan.None,
                _robot.Offset_X, _robot.Offset_Y, _robot.Offset_D,
                _starttime, DateTime.Now);
            return true;
        }

        private bool NotifyPMPickWafer()
        {
            _pmModule.PostMsg(PMEntity.MSG.DropDownWafer);
            return true;
        }

        private bool WaitPMWaferDropDown()
        {
            return _pmModule.Status == PMEntity.PMStatus.Exchange_Ready;
        }

        private bool WaitRobotRetractDone()
        {
            if (_robot.Status == RState.Running)
            {
                return false;
            }
            else if (_robot.Status == RState.End)
            {
                return true;
            }
            else
            {
                Runner.Stop($"TM Robot Pick Retract failed, {_robot.Status}");
                return true;
            }
        }

        private bool NotifyPMDone()
        {
            _pmModule.PostMsg(PMEntity.MSG.PickReady);
            return true;
        }

        public void Abort()
        {
            _robot.Halt();
        }
    }
}