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.Equipment;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Venus_Core;
using Venus_RT.Devices;
using Venus_RT.Devices.PreAligner;
using Venus_RT.Modules.VCE;
namespace Venus_RT.Modules.TM.VenusEntity
{
    public class SEMFPickRoutine : ModuleRoutineBase, IRoutine
    {
        private enum PickStep
        {
            seWaitModuleReady,
            sePrepareModule,
            sePAQuery,
            sePicking,
            seNotifyDone,
        }
        private HongHuTM _tm;
        private IPreAlign _vpa;
        private ITransferRobot _robot;
        private VceEntity _vceModule;
        private ModuleName _targetModule;
        private int _targetSlot;
        private int _pickingTimeout;
        public int currentStepNo;
        Hand _hand;
        /// 
        /// 完整pick动作仅可vce vpa取片
        /// 
        /// 
        /// 
        /// 
        public SEMFPickRoutine(HongHuTM tm, ITransferRobot robot, IPreAlign vpa) : base(ModuleName.SETM)
        {
            _tm = tm;
            _robot = robot;
            _vpa = vpa;
        }
        public RState Start(params object[] objs)
        {
            if (!_robot.IsHomed)
            {
                LOG.Write(eEvent.ERR_TM, Module, $"TM Robot is not homed, please home it first");
                return RState.Failed;
            }
            //MoveItem pickItem = new MoveItem() { SourceModule = , };
            var pickItem = (Queue)objs[0];
            _targetModule = pickItem.Peek().SourceModule;
            _targetSlot = pickItem.Peek().SourceSlot;
            _hand = pickItem.Peek().RobotHand;
            //如果目标是Vce 否则是vpa
            if (ModuleHelper.IsVCE(_targetModule) && ModuleHelper.IsInstalled(_targetModule))
            {
                _vceModule = Singleton.Instance.GetVCE(_targetModule);
                //如果vce有错误 报错
                if (_vceModule.IsError)
                {
                    LOG.Write(eEvent.ERR_TM, Module, $"Invalid target module : {_targetModule} is Error! Please solve Error first!");
                    return RState.Failed;
                }
                if (_targetSlot < 0)
                {
                    LOG.Write(eEvent.ERR_TM, Module, $"VCE target slot cannot be {_targetSlot}. Please check it first.");
                    return RState.Failed;
                }
                if (_tm.VCESlitDoorClosed)
                {
                    LOG.Write(eEvent.ERR_TM, Module, $"cannot pick cause vce slitdoor not open.");
                    return RState.Failed;
                }
                //如果VCE门是关闭的 说明还未进行pump 无法取片等
                //if (_tm.VCESlitDoorClosed)
                //{
                //    LOG.Write(eEvent.ERR_TM, Module, $"Invalid target module : {_targetModule} slitdoor not open! Please pump down vce and open it first!");
                //    return RState.Failed;
                //}
            }   
            //如果目标又不是VPA 报错
            else if (!ModuleHelper.IsVPA(_targetModule))
            {
                LOG.Write(eEvent.ERR_TM, Module, $"Invalid target module : {_targetModule} for pick action");
                return RState.Failed;
            }
            //检查目标手臂上没有wafer
            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;
            }
            //检查目标槽位上有wafer
            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;
            }
            //2023/10/13 朱永吉 atm mode的判断不允许自动pump vent 信号不满足手动pump vent
            //if (RouteManager.IsATMMode && _targetModule == ModuleName.VCE1)
            //{
            //    if (!_tm.IsVCEATM)
            //    {
            //        LOG.Write(eEvent.ERR_TM, Module, $"System in ATM Mode but VCE is not ATM!");
            //        return RState.Failed;
            //    }
            //
            //    if (!_tm.IsTMATM)
            //    {
            //        LOG.Write(eEvent.ERR_TM, Module, $"System in ATM Mode but TM is not ATM!");
            //        return RState.Failed;
            //    }
            //}
            //else
            //{
            //    if (_tm.IsVCEATM)
            //    {
            //        LOG.Write(eEvent.ERR_TM, Module, $"System not in ATM Mode but VCE is ATM!");
            //        return RState.Failed;
            //    }
            //
            //    if (_tm.IsTMATM)
            //    {
            //        LOG.Write(eEvent.ERR_TM, Module, $"System not in ATM Mode but TM is ATM!");
            //        return RState.Failed;
            //    }
            //}
            Reset();
            _pickingTimeout = SC.GetValue("SETM.PickTimeout") * 1000;
            return Runner.Start(Module, $"Pick from {_targetModule}");
        }
        public RState Monitor()
        {
            Runner.Wait(PickStep.seWaitModuleReady,         CheckModuleReady,       _delay_60s)
                  .Run(PickStep.sePrepareModule,            PrepareModule,          CheckModuleReady)
                  .RunIf(PickStep.sePAQuery,                _targetModule == ModuleName.VPA,              QueryOffset,        VPAIsIdle,  _pickingTimeout)
                  .Run (PickStep.sePicking,                 Picking,                WaitPickDone,       _pickingTimeout)
                  .End (PickStep.seNotifyDone,              NullFun,                500);
            return Runner.Status;
        }
        private bool PrepareModule()
        {
            switch (_targetModule)
            {
                case ModuleName.VCE1:
                    return _vceModule.CheckToPostMessage((int)VceMSG.Goto, _targetSlot);//移动到目标槽位
                case ModuleName.VPA:
                    return true;//10/17暂时为true 后可能要求旋转到0
                default:
                    return false;
            }
        }
        private bool WaitPickDone()
        {
            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 Picking failed, {_robot.Status}");
                return true;
            }
        }
        private bool CheckIsPA() => _targetModule == ModuleName.VPA;
        private bool QueryOffset()
        {
            return _vpa.QueryOffset();
        }
        private bool VPAIsIdle()
        {
            if (_vpa.Status == RState.Running)
            {
                return false;
            }
            else if (_vpa.Status == RState.End)
            {
                return true;
            }
            else
            {
                Runner.Stop($"VPA Query Offset failed, {_vpa.Status}");
                return true;
            }
        }
        private bool WaitRobotIsIdle()
        {
            if (_robot.Status == RState.Running)
            {
                return false;
            }
            else if (_robot.Status == RState.End)
            {
                return true;
            }
            else
            {
                Runner.Stop($"TM Robot QueryOffset failed, {_robot.Status}");
                return true;
            }
        }
        private bool Picking()
        {
            //到达目标点位 pick固定槽位点的wafer
            if (_targetModule == ModuleName.VPA && (_vpa.ROffset!=0 || _vpa.TOffset!=0))
            {
                int[] RT = calculateRT(_vpa.ROffset, _vpa.TOffset);
                LOG.Write(eEvent.INFO_TM_ROBOT, ModuleName.TMRobot, $"will pick from PA with R:{RT[1]} D:{RT[0]}");
                return _robot.PickWithOffset(_targetModule, 0, _hand, RT[1], RT[0]);
            }
            else
                return _robot.Pick(_targetModule, 0, _hand);
        }
        private int[] calculateRT(int OriginR,int OriginS)
        {
            int[] RT = new int[2];
            try
            {
                bool desflag = false;
                double angle = 0;
                if (OriginR / 10 < 90)
                    angle = OriginR / 10;
                if (OriginR / 10 < 270 && OriginR / 10 > 90)
                {
                    desflag = true;
                    angle = OriginR / 10 - 90;
                }
                if (OriginR / 10 > 270)
                    angle = 450 - OriginR / 10;
                double angleInRadians = angle * Math.PI / 180;
                //OriginS * 25.4 inch 转化为 mm
                double Robot2PA = OriginS * 25.4 / 10000;
                double Robot2Wafer = Math.Sqrt(Robot2PA * Robot2PA + 402.5 * 402.5 - 2 * Robot2PA * 402.5 * Math.Cos(angleInRadians));
                //距离(mm)
                double distance = Robot2Wafer - 402.5;
                //角度(度)
                double angleA = Math.Asin(Robot2PA * Math.Sin(angleInRadians) / Robot2Wafer) * 180 / Math.PI;
                if (desflag)
                    angleA = -angleA;
                RT[0] = (int)(angleA * 1000);
                RT[1] = (int)(distance * 1000);
            }
            catch 
            {
                LOG.Write(eEvent.ERR_TM_ROBOT,ModuleName.TMRobot,"错误纠偏计算");
                RT[0] = 0;
                RT[1] = 0;
            }
            return RT;
        }
        private bool CheckModuleReady()
        {
            switch (_targetModule)
            {
                case ModuleName.VCE1:
                    return _vceModule.IsIdle;
                case ModuleName.VPA:
                    return _vpa.Status == RState.End;
                default:
                    return false;
            }
        }
        public void Abort() 
        {
            _robot.Halt();
        }
    }
}