using System.Linq;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Fsm;
using Aitex.Core.Util;
using Aitex.Sorter.Common;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;
using SicRT.Equipments.Systems;
using SicRT.Modules.Schedulers;
using Aitex.Core.RT.Device.Devices;
using Aitex.Core.RT.Event;
using SicModules.LLs;

namespace SicRT.Scheduler
{
    public class SchedulerLoadLock : SchedulerModule
    {
        #region Variables

        /// <summary>
        /// 最后一次传盘动作是Pick还是Place。
        /// </summary>
        private TaskType _lastTransferAction;

        /// <summary>
        /// 最后一次传盘的槽位。
        /// </summary>
        private int _lastTransferSlot;


        #endregion

        public override bool IsAvailable
        {
            get
            {
                return _ll.IsIdle && _ll.IsOnline && CheckTaskDone() && _ll.CheckSlitValveClosed();
            }
        }

        public override bool IsOnline
        {
            get
            {
                return _ll.IsOnline;
            }
        }

        public override bool IsError
        {
            get
            {
                return _ll.IsError;
            }
        }

        private LoadLockModuleBase _ll = null;

        private ModuleName _taskRobot;
        private int _taskSlot;
        private int _entityTaskToken = (int)FSM_MSG.NONE;
        private bool _separated = false;
        private bool _purged = false;
        public bool IsInPumping { get => _task == TaskType.Pump || _task == TaskType.Purge || _task == TaskType.PrepareTransfer ; }

        public SchedulerLoadLock(ModuleName module) : base(module.ToString())
        {
            _module = module.ToString();
            _ll = Singleton<EquipmentManager>.Instance.Modules[module] as LoadLockModuleBase;
        }

        public override bool PrepareTransfer(ModuleName robot, EnumTransferType type, int slot)
        {
            _task = TaskType.PrepareTransfer;
            _taskRobot = robot;
            _taskSlot = slot;

            LogTaskStart(_task, $"{robot} {type} slot {slot + 1}");
            return _ll.PrepareTransfer(robot, Hand.Blade1, slot, type, out _);
        }

        internal bool CheckAtAtm()
        {
            SicLoadLock deviceLL = DEVICE.GetDevice<SicLoadLock>($"{_module}.{_module}");

            return deviceLL.CheckAtm();
        }
        internal bool CheckAtVacuum()
        {
            SicLoadLock deviceLL = DEVICE.GetDevice<SicLoadLock>($"{_module}.{_module}");

            return deviceLL.CheckVacuum();
        }
        internal void SetJobStatue()
        {
            SicLoadLock deviceLL = DEVICE.GetDevice<SicLoadLock>($"{_module}.{_module}");
            deviceLL.SetJobDoneStatus();
        }

        public override bool IsReadyForPick(ModuleName robot, int slot)
        {
            if (robot == ModuleName.TMRobot)
            {
                return _ll.CheckReadyForTransfer(robot, Hand.Blade1, slot, EnumTransferType.Pick, out _);
            }

            return false;
        }

        public override bool IsReadyForPlace(ModuleName robot, int slot)
        {
            if (robot == ModuleName.TMRobot)
            {
                return _ll.CheckReadyForTransfer(robot, Hand.Blade1, slot, EnumTransferType.Place, out _);
            }

            return false;
        }

        public override bool IsReadyForTransfer(ModuleName robot, int slot)
        {
            if (robot == ModuleName.WaferRobot)
            {
                return _ll.CheckReadyForTransfer(robot, Hand.Blade1, slot, EnumTransferType.Place, out _);
            }
            else if (robot == ModuleName.TMRobot || robot == ModuleName.TrayRobot)
            {
                return _ll.CheckReadyForTransfer(robot, Hand.Blade1, slot, EnumTransferType.Place, out _)
                       && WaferManager.Instance.CheckNoTray(ModuleHelper.Converter(_module), slot);
            }

            return false;
        }


        public bool Vent()
        {
            _task = TaskType.Vent;

            _entityTaskToken = _ll.InvokeVent();

            LogTaskStart(_task, $"{Module} vent to ATM");

            return _entityTaskToken != (int)FSM_MSG.NONE;
        }

        public bool Pump()
        {
            _entityTaskToken = _ll.InvokePump();
            if (_entityTaskToken != (int)FSM_MSG.NONE)
            {
                _task = TaskType.Pump;
                LogTaskStart(_task, $"{Module} pump to Vaccum");
                return true;
            }
            return false;

        }

        public bool Purge(params object[] objs)
        {
            _entityTaskToken = _ll.InvokePurge(objs);
            if (_entityTaskToken != (int)FSM_MSG.NONE)
            {
                _task = TaskType.Purge;
                LogTaskStart(_task, $"{Module} purge for new job");
                _purged = true;
                return true;
            }
            return false;
        }

        public bool GroupWaferTray()
        {
            _entityTaskToken = _ll.InvokeGroupWaferTray();
            if (_entityTaskToken != (int)FSM_MSG.NONE)
            {
                _task = TaskType.Group;
                LogTaskStart(_task, $"{Module} start group wafer and tray");
                return true;
            }
            return false;
        }

        public bool SeparateWaferTray()
        {
            _entityTaskToken = _ll.InvokeSeparateWaferTray();
            if (_entityTaskToken != (int)FSM_MSG.NONE)
            {
                _task = TaskType.Separate;
                LogTaskStart(_task, $"{Module} start separate wafer and tray");
            }
            _separated = _entityTaskToken != (int)FSM_MSG.NONE;
            return _entityTaskToken != (int)FSM_MSG.NONE;
        }


        public int? GetWaferPurgeCount(int slot)
        {
            if (!WaferManager.Instance.CheckHasWafer(Module, slot))
                return null;

            var wafer = WaferManager.Instance.GetWafer(Module, slot);

            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
                return null;

            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count)
                return null;

            if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Any(m => m == ModuleName.LoadLock || m == ModuleName.Load))
                return null;

            if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter.ContainsKey("PurgeCount"))
                return null;

            if (int.TryParse(wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepParameter["PurgeCount"].ToString(), out int purgeCount))
            {
                return purgeCount;
            }

            return null;
        }

        public int? GetWaferPumpDelayTime(int slot)
        {
            if (!WaferManager.Instance.CheckHasWafer(Module, slot))
                return null;

            var wi = WaferManager.Instance.GetWafer(Module, slot);

            if (wi.ProcessJob?.Sequence == null)
                return null;

            if (wi.NextSequenceStep >= wi.ProcessJob.Sequence.Steps.Count)
                return null;

            if (!wi.ProcessJob.Sequence.Steps[wi.NextSequenceStep].StepModules.Any(m => m == ModuleName.LoadLock || m == ModuleName.Load))
                return null;

            if (!wi.ProcessJob.Sequence.Steps[wi.NextSequenceStep].StepParameter.ContainsKey("PumpDelayTime"))
                return null;

            if (int.TryParse(wi.ProcessJob.Sequence.Steps[wi.NextSequenceStep].StepParameter["PumpDelayTime"].ToString(), out int pumpDelayTime))
            {
                return pumpDelayTime;
            }

            return null;
        }

        public override bool CheckWaferNextStepIsThis(ModuleName module, int slot)
        {
            if (!WaferManager.Instance.CheckHasWafer(module, slot))
                return false;

            var wi = WaferManager.Instance.GetWafer(module, slot);

            if (wi.ProcessJob?.Sequence == null)
                return false;

            if (wi.NextSequenceStep >= wi.ProcessJob.Sequence.Steps.Count)
                return false;

            if (!wi.ProcessJob.Sequence.Steps[wi.NextSequenceStep].StepModules.Any(m => m == ModuleName.LoadLock || m == ModuleName.Load))
                return false;

            return true;
        }

        public override bool CheckWaferTrayGrouped()
        {
            return !_ll.CheckWaferClamped() && WaferManager.Instance.CheckHasWafer(Module, 0);
        }

        public override bool CheckWaferTraySeparated()
        {
            return _separated;
        }

        public override bool CheckSlitValveClosed()
        {
            return _ll.CheckSlitValveClosed();
        }

        public override bool CheckTrayPlaced()
        {
            return _ll.CheckTrayPlaced();
        }

        public bool WaitTransfer(ModuleName robot, bool isPick, int slot)
        {
            _lastTransferAction = isPick ? TaskType.Pick : TaskType.Place;
            _lastTransferSlot = slot;
            return base.WaitTransfer(robot);
        }


        /*public override bool StopWaitTransfer(ModuleName robot)
        {
            
            var ret = base.StopWaitTransfer(robot);
            if (ret)
            {
                // 传盘结束后，如果上个动作是Place，Wafer回到Cassette，则响蜂鸣器进行提示。
                if (_lastTransferAction == TaskType.Place
                    && WaferManager.Instance.CheckHasWafer(ModuleName.LoadLock.ToString(), 0))
                {
                    EV.PostMessage(Module.ToString(), EventEnum.PJ_DONE, "LoadLock", "0");
                }
            }

            return ret;
        }*/

        public override void ResetTask()
        {
            base.ResetTask();
            _lastTransferAction = TaskType.None;
            _lastTransferSlot = -1;
        }

        public bool CheckTaskDone()
        {
            var taskSucceed = false;
            switch (_task)
            {
                case TaskType.None:
                    taskSucceed = true;
                    break;
                case TaskType.PrepareTransfer:
                    taskSucceed = _ll.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Cooling:
                    taskSucceed = _ll.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Vent:
                    taskSucceed = _ll.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Pump:
                    taskSucceed = _ll.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Purge:
                    taskSucceed = _ll.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Group:
                    taskSucceed = _ll.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Separate:
                    taskSucceed = _ll.CheckAcked(_entityTaskToken);
                    break;

            }

            return SuperCheckTaskDone(taskSucceed, _ll.IsIdle | _ll.IsError);
        }

        internal float GetTemperature()
        {
            IoTempMeter deviceLoadTemp = DEVICE.GetDevice<IoTempMeter>($"Buffer.BufferTemp");
            return deviceLoadTemp.FeedBack;
        }

        public bool CheckPurged()
        {
            return _purged;
        }

        public void ResetPurged()
        {
            _purged = false;
        }
    }


}
