using System.Linq;
using Aitex.Core.Common;
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 SicModules.LLs;
using SicModules.UnLoads;
using SicRT.Equipments.Systems;
using SicRT.Modules.Schedulers;

namespace SicRT.Scheduler
{
    public class SchedulerUnLoad : SchedulerModule
    {
        public override bool IsAvailable
        {
            get
            {
                return _unL.IsIdle && _unL.IsOnline && CheckTaskDone() && _unL.CheckSlitValveClosed();
            }
        }

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

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

        private UnLoadModuleBase _unL = null;

        private ModuleName _taskRobot;
        private int _taskSlot;
        private int _entityTaskToken = (int)FSM_MSG.NONE;
        private bool _separated = false;
        private bool _purged = false;
        private bool _coolingCompleted = false;
        private DeviceTimer _timerCooling = new DeviceTimer();

        public bool IsInPumping { get => _task == TaskType.Pump || _task == TaskType.Purge || _task == TaskType.PrepareTransfer; }

        public SchedulerUnLoad(ModuleName module) : base(module.ToString())
        {
            _module = module.ToString();
            _unL = Singleton<EquipmentManager>.Instance.Modules[module] as UnLoadModuleBase;
        }

        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 _unL.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.WaferRobot)
            {
                return _unL.CheckReadyForTransfer(robot, Hand.Blade1, slot, EnumTransferType.Pick, out _)
                       && WaferManager.Instance.CheckHasWafer(ModuleHelper.Converter(_module), slot);
            }
            else if (robot == ModuleName.TMRobot)
			{
                return _unL.CheckReadyForTransfer(robot, Hand.Blade1, slot, EnumTransferType.Pick, out _)
                       && WaferManager.Instance.CheckHasTray(ModuleHelper.Converter(_module), slot);
            }
            return false;
        }

        public override bool IsReadyForPlace(ModuleName robot, int slot)
        {
            return _unL.CheckReadyForTransfer(robot, Hand.Blade1, slot, EnumTransferType.Place, out _)
                   && WaferManager.Instance.CheckNoWafer(ModuleHelper.Converter(_module), slot)
                   && WaferManager.Instance.CheckNoTray(ModuleHelper.Converter(_module), slot);
        }


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

            _entityTaskToken = _unL.InvokeVent();

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

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

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

        }

        public override bool Cooling(bool coolingType, int coolingTime)
        {
            _entityTaskToken = _unL.InvokeCooling(coolingTime);
            if (_entityTaskToken != (int)FSM_MSG.NONE)
            {
                _task = TaskType.Cooling;
                LogTaskStart(_task, $"{Module} cooling {coolingTime} seconds");
            }
            _coolingCompleted = _entityTaskToken != (int)FSM_MSG.NONE;
            
            return _entityTaskToken != (int)FSM_MSG.NONE;
        }

        public bool Purge(params object[] objs)
        {
            _entityTaskToken = _unL.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 Monitor()
        {
            return true;
        }

        public bool GroupWaferTray()
        {
            _entityTaskToken = _unL.InvokeGroupWaferTray();
            if (_entityTaskToken != (int)FSM_MSG.NONE)
            {

                _task = TaskType.Group;
                LogTaskStart(_task, $"{Module} start group wafer and tray");
            }
            return _entityTaskToken != (int)FSM_MSG.NONE;
        }

        public bool SeparateWaferTray()
        {
            _entityTaskToken = _unL.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 void ResetPurgedAndSeparatedStatus()
        {
            _coolingCompleted = false;
            _separated = false;
            _purged = false;
        }

        public bool CheckCoolingCompleted()
        {
            return _coolingCompleted;
        }

        public override bool CheckWaferTraySeparated()
        {
            return _separated;
        }

        public bool CheckPurged()
        {
            return _purged;
        }

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

        public int? GetWaferPurgeCount(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.Contains(Module))
                return null;

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

            if (int.TryParse(wi.ProcessJob.Sequence.Steps[wi.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.Contains(Module))
                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 bool CheckTaskDone()
        {
            var taskSucceed = false;
            switch (_task)
            {
                case TaskType.None:
                    taskSucceed = true;
                    break;
                case TaskType.PrepareTransfer:
                    taskSucceed = _unL.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Cooling:
                    taskSucceed = _unL.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Vent:
                    taskSucceed = _unL.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Pump:
                    taskSucceed = _unL.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Group:
                    taskSucceed = _unL.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Purge:
                    taskSucceed = _unL.CheckAcked(_entityTaskToken);
                    break;
                case TaskType.Separate:
                    taskSucceed = _unL.CheckAcked(_entityTaskToken);
                    break;
                
            }

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

    }


}
