using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using Aitex.Sorter.Common;
using MECF.Framework.Common.DBCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.TMs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using Venus_Core;
using Venus_RT.Devices;
using Venus_RT.Devices.IODevices;
using Venus_RT.Devices.TM;
using Venus_RT.Modules.PMs;

namespace Venus_RT.Modules.TM.VenusEntity
{
    public class SEMFPMPickRoutine : ModuleRoutineBase, IRoutine
    {
        private enum PickStep
        {
            WaitPMReady,
            OpenMFSlitDoor,
            PMPrepare,
            ArmExtend,
            QueryAWC,
            DropDownWafer,
            PickDelay,
            PickDelay1,
            PickDelay2,
            ArmRetract,
            SavePickeData,
            NotifyDone,
            CloseSlitDoor,
            EndDelay
        }

        private readonly TMBase _tm;
        private readonly ITransferRobot _robot;
        private int _pickdelay = 0;
        private ModuleName _targetModule;
        private Hand _hand;
        private int _targetSlot;
        private PMEntity _pmModule;
        private int _ExtendTimeout = 120 * 1000;
        private int _RetractTimeout = 120 * 1000;
        private int _controlPressureSetPoint = 90;
        private int _controlFlowSetPoint = 10;
        //private DateTime _starttime;
        private bool _queryAwc;
        private bool havelinerdoor;

        public SEMFPMPickRoutine(TMBase honghutm, ITransferRobot robot, ModuleName module) : base(module)
        {
            _tm = honghutm;
            _robot = robot;
            _queryAwc = false;
        }

        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);
            LOG.Write(eEvent.INFO_TM_ROBOT, ModuleName.TMRobot, $"{wafer.WaferOrigin} will be move from {_targetModule} {_targetSlot + 1} to TM Robot {_hand}");

            _ExtendTimeout = SC.GetValue<int>($"{Module}.ExtendTimeout") * 1000;
            _RetractTimeout = SC.GetValue<int>($"{Module}.RetractTimeout") * 1000;
            _pickdelay = SC.GetValue<int>($"{_targetModule}.PickDelayTime");
            Reset();
            return Runner.Start(Module, $"Pick from {_targetModule}");
        }

        public RState Monitor()
        {
                  Runner.Wait(PickStep.WaitPMReady,   PMPrepare, _delay_60s)
                        .Run(PickStep.OpenMFSlitDoor, OpenSlitDoor, CheckSlitDoorOpen)
                        .Run(PickStep.PMPrepare, ModulePrepare, IsModulePrepareReady, _delay_60s)
                        .Delay(PickStep.PickDelay, _pickdelay)
                        .Run(PickStep.ArmExtend, ArmExtend, WaitRobotExtendDone, _ExtendTimeout)
                        .Run(PickStep.QueryAWC, QueryAWC, WaitRobotQueryDone, _delay_1s)
                        .Run(PickStep.DropDownWafer, NotifyPMPickWafer, WaitPMWaferDropDown)
                        .Delay(PickStep.PickDelay1, _pickdelay)
                        .Run(PickStep.ArmRetract, ArmRetract, WaitRobotRetractDone, _RetractTimeout)
                        .Run(PickStep.SavePickeData, RecordAWCData, NullFun)
                        .Run(PickStep.CloseSlitDoor, PMDoorClose, WaitPMDoorClose)
                        .Run(PickStep.NotifyDone, NotifyPMDone, _delay_50ms)
                        .Delay(PickStep.PickDelay2, _delay_50ms)
                        .End(PickStep.EndDelay, NullFun, _delay_50ms);


            return Runner.Status;
        }
        private bool PMPrepare()
        {
            return IsPressureReady(_targetModule) && _pmModule.IsIdle;
        }
        private bool IsPressureReady(ModuleName _targetModule)
        {
            if (Singleton<RouteManager>.Instance.GetPM(_targetModule).IsOnline)
            {
                double PMPressure = _pmModule.ChamberPressure;
                double ControlPressure = SC.GetValue<int>($"{_targetModule}.ControlPressureSetPoint");
                double range = SC.GetValue<int>($"{_targetModule}.ControlPressureOffset");
                if ((PMPressure >= (ControlPressure - range)) && (PMPressure <= (ControlPressure + range)))
                {
                    return true;
                }
                else return false;
            }
            else return true;
        }
        private bool OpenSlitDoor()
        {
            return _tm.TurnSlitDoor(_targetModule,true);
        }

        private bool CheckSlitDoorOpen()
        {
            return _tm.CheckSlitValveOpen(_targetModule);
        }

        private bool ModulePrepare()
        {
            _pmModule.PostMsg(PMEntity.MSG.PreparePick);
            return true;
        }

        private bool IsModulePrepareReady()
        {
            return _pmModule.Status == PMEntity.PMStatus.Ready_For_Pick;
        }

        private bool ArmExtend()
        {
            if (!_pmModule.IsSlitDoorOpen)
            {
                LOG.Write(eEvent.ERR_TM, Module, $"Cannot pick as {_targetModule} Door is not Open");
                return false;
            }
            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}");
                Singleton<RouteManager>.Instance.GetPM(_targetModule).PostMsg(PMEntity.MSG.Error);
                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}");
                Singleton<RouteManager>.Instance.GetPM(_targetModule).PostMsg(PMEntity.MSG.Error);
                return true;
            }
        }

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


            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}");
                Singleton<RouteManager>.Instance.GetPM(_targetModule).PostMsg(PMEntity.MSG.Error);
                return true;
            }
        }

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

        private bool PMDoorClose()
        {
            LOG.Write(eEvent.WARN_TM, Module, $"PMPick Close Door Again");
            return _tm.TurnSlitDoor(_targetModule, false);
        }

        private bool WaitPMDoorClose()
        {
            if (_tm.CheckSlitValveClose(_targetModule))
            {
                LOG.Write(eEvent.WARN_TM, Module, $"PMPick Check Door Close");
                return true;
            }
            else
            {
                LOG.Write(eEvent.WARN_TM, Module, $"PMPick Check not Close Door");
                return false;
            }
        }

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