using System.Collections.Generic;
using Aitex.Core.Common;
using Aitex.Core.RT.Event;
using Aitex.Core.Util;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Schedulers;
using MECF.Framework.Common.SubstrateTrackings;

namespace SicRT.Modules.Schedulers
{
    public class SchedulerModule
    {
        protected enum TaskType
        {
            None,

            PrepareTransfer,

            Pick,

            Place,

            PickAndPlace,

            Preprocess,
            Process,
            PostProcess,

            OpenCover,
            CloseCover,

            Load,
            Unload,

            Align,

            TransferTarget,

            Cooling,
            WarmUp,

            Vent,
            Pump,
            Purge,
            Group,
            Separate,
            Map
        }

        #region Variables

        private readonly R_TRIG[] firstDetectWaferArriveTrigs = new R_TRIG[25];
        private readonly R_TRIG[] firstDetectWaferLeaveTrigs = new R_TRIG[25];
        private readonly R_TRIG[] firstDetectTrayArriveTrigs = new R_TRIG[25];
        private readonly R_TRIG[] firstDetectTrayLeaveTrigs = new R_TRIG[25];

        protected string _module;
        protected TaskType _task = TaskType.None;
        protected ModuleName _inProcessRobot;

        /// <summary>
        /// 检测调度器TransferTarget任务是否超时。
        /// </summary>
        private readonly DeviceTimer _timTransferTargetStatusTimeout = new();

        #endregion

        #region Constructors

        public SchedulerModule(string module)
        {
            _module = module;
            for (var i = 0; i < firstDetectWaferArriveTrigs.Length; i++)
            {
                firstDetectWaferArriveTrigs[i] = new R_TRIG();
            }
            for (var i = 0; i < firstDetectWaferLeaveTrigs.Length; i++)
            {
                firstDetectWaferLeaveTrigs[i] = new R_TRIG();
            }
            for (var i = 0; i < firstDetectTrayArriveTrigs.Length; i++)
            {
                firstDetectTrayArriveTrigs[i] = new R_TRIG();
            }
            for (var i = 0; i < firstDetectTrayLeaveTrigs.Length; i++)
            {
                firstDetectTrayLeaveTrigs[i] = new R_TRIG();
            }
        }

        #endregion

        #region Properties

        public ModuleName Module
        {
            get { return ModuleHelper.Converter(_module); }
        }
        public virtual bool IsAvailable { get; }

        public virtual bool IsOnline { get; }

        public virtual bool IsError { get; }

        public virtual bool IsReady { get; }

        public virtual bool IsService { get; }

        public virtual string State { get; }

        #endregion

        #region Methods

        /// <summary>
        /// 检查调度器是否空闲。
        /// </summary>
        /// <Remarks>
        /// 调度器空闲的条件除调度器无任务执行，还需要判断Module的状态是否为Idle或Error。
        /// 因为如果调度器执行过程中，Module发生错误，也应该将调度器标记为空闲，否则调度器可能卡死而导致Auto流程无法继续。
        /// 以下为调度器和Module可能出现冲突的状态，和判决方法：
        /// <para>1. 如果调度器无任务，但Module还未Idle，则说明上个Routine还未执行完毕，则认为Task还未完成。</para>
        /// <para>2. 如果调度器有任务，但Module已经Idle或Error，则说明Routine已执行完毕，但可能出错，则认为Task完成。</para>
        /// </Remarks>
        /// <param name="isTaskDone">调度器执行的任务是否结束。</param>
        /// <param name="fsmStopped">调度器关联的Module的状态机是否Idle或Alarm</param>
        /// <returns></returns>
        protected bool SuperCheckTaskDone(bool isTaskDone, bool fsmStopped)
        {
            // Transfer状态需特殊对待。该状态在调度器的CheckTaskDone()中未处理，因为机械手的异常可能导致被操作的调度器卡死在Transfer任务中。
            // 因此需要建立超时机制，如果调度器停留在Transfer状态时间过长，则可能是机械手发生异常，需要自动退出Transfer任务。
            if (_task == TaskType.TransferTarget)
            {
                if (_timTransferTargetStatusTimeout.IsTimeout())
                {
                    // 强制结束TransferTarget任务
                    _task = TaskType.None;
                    _timTransferTargetStatusTimeout.Stop();
                    isTaskDone = true;
                }
                else
                {
                    // 调度器仍然在Transfer任务中
                    return false;
                }
            }

            isTaskDone &= fsmStopped;

            if (isTaskDone)
            {
                if (_task != TaskType.None)
                {
                    LogTaskDone(_task, "");
                    _task = TaskType.None;
                }

                return true;
            }

            if (fsmStopped)
            {
                LogTaskDone(_task, "Task Failed");
                _task = TaskType.None;
                return true;
            }

            return false;
        }


        protected void LogTaskStart(TaskType cmd, string message)
        {
            EV.PostInfoLog("Scheduler", $"Task start:{_module},{cmd} {message}");

        }
        protected void LogTaskDone(TaskType cmd, string message)
        {
            EV.PostInfoLog("Scheduler", $"Task done:{_module},{cmd} {message}");
        }
        public virtual void ResetTask()
        {
            _task = TaskType.None;
            _timTransferTargetStatusTimeout.Stop();
        }

        public bool WaitTransfer(ModuleName robot)
        {
            _task = TaskType.TransferTarget;
            _inProcessRobot = robot;
            _timTransferTargetStatusTimeout.Start(30000);
            LogTaskStart(_task, $"Note {robot} in transfer");
            return true;
        }

        public bool IsWaitTransfer(ModuleName robot)
        {
            return _task == TaskType.TransferTarget && _inProcessRobot == robot;
        }

        public virtual bool StopWaitTransfer(ModuleName robot)
        {
            LogTaskDone(_task, $"Note {robot} transfer complete");
            _timTransferTargetStatusTimeout.Stop();
            _inProcessRobot = ModuleName.System;

            _task = TaskType.None;
            return true;
        }

        public WaferInfoRt GetWaferInfo(int slot)
        {
            return WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
        }

        public bool CheckWaferStatus(int slot, WaferStatus waferStatus)
        {
            return WaferManager.Instance.CheckWafer(ModuleHelper.Converter(_module), slot, waferStatus);
        }

        public bool HasWafer(int slot)
        {
            return WaferManager.Instance.CheckHasWafer(ModuleHelper.Converter(_module), slot);
        }

        public bool NoWafer(int slot)
        {
            return WaferManager.Instance.CheckNoWafer(ModuleHelper.Converter(_module), slot);
        }

        public bool HasTray(int slot)
        {
            return WaferManager.Instance.CheckHasTray(ModuleHelper.Converter(_module), slot);
        }

        public bool NoTray(int slot)
        {
            return WaferManager.Instance.CheckNoTray(ModuleHelper.Converter(_module), slot);
        }

        public bool FirstDetectWaferArrive(int slot)
        {
            firstDetectWaferArriveTrigs[slot].CLK = HasWafer(slot);
            return firstDetectWaferArriveTrigs[slot].Q;
        }

        public bool FirstDetectWaferLeave(int slot)
        {
            firstDetectWaferLeaveTrigs[slot].CLK = NoWafer(slot);
            return firstDetectWaferLeaveTrigs[slot].Q;
        }

        public bool FirstDetectTrayArrive(int slot)
        {
            firstDetectTrayArriveTrigs[slot].CLK = HasTray(slot);
            return firstDetectTrayArriveTrigs[slot].Q;
        }

        public bool FirstDetectTrayLeave(int slot)
        {
            firstDetectTrayLeaveTrigs[slot].CLK = NoTray(slot);
            return firstDetectTrayLeaveTrigs[slot].Q;
        }

        public bool HasTrayAndExceedProcessCount(int slot)
        {
            var wi = WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
            return wi.TrayStatus == TrayStatus.Normal && wi.TrayProcessCount <=0;
        }

        public bool HasTrayAndNotExceedProcessCount(int slot)
        {
            var wi = WaferManager.Instance.GetWafer(ModuleHelper.Converter(_module), slot);
            return wi.TrayStatus == TrayStatus.Normal && wi.TrayProcessCount >0;
        }

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

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

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

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

            if (!wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules.Contains(Module))
                return false;

            return true;
        }

        /// <summary>
        /// 判断下一步的模块是否有Wafer
        /// </summary>
        /// <param name="slot"></param>
        /// <returns></returns>
        public virtual bool CheckWaferNextStepModuleNoWafer(int slot)
        {
            if (!WaferManager.Instance.CheckHasWafer(Module, slot))
                return false;

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

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

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

            List<ModuleName> lstModuleName = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules;
            if (lstModuleName.Count > 0)
            {
                for (int i = 0; i < lstModuleName.Count; i++)
                {
                    if (WaferManager.Instance.CheckNoWafer(lstModuleName[i], 0))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public virtual bool CheckWaferNextStepBufferNoTray(int slot)
        {
            if (!WaferManager.Instance.CheckHasWafer(Module, slot))
                return false;

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

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

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

            List<ModuleName> lstModuleName = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules;
            if (lstModuleName.Count > 0)
            {
                for (int j = 0; j < lstModuleName.Count; j++)
                {
                    if (CheckWaferNeedProcess(slot, ModuleName.PM1))
                    {
                        if (WaferManager.Instance.CheckNoTray(ModuleName.Buffer, 2))
                        {
                            return true;
                        }
                    }
                    else if (CheckWaferNeedProcess(slot, ModuleName.PM2))
                    {
                        if (WaferManager.Instance.CheckNoTray(ModuleName.Buffer, 1))
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        public virtual bool CheckWaferNextStepModuleNoTray(int slot)
        {
            if (!WaferManager.Instance.CheckHasWafer(Module, slot))
                return false;

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

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

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

            List<ModuleName> lstModuleName = wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules;
            if (lstModuleName.Count > 0)
            {
                for (int j = 0; j < lstModuleName.Count; j++)
                {
                    if (lstModuleName[j] == ModuleName.Buffer)
                    {
                        if (CheckWaferNeedProcess(slot, ModuleName.PM1))
                        {
                            if (WaferManager.Instance.CheckNoTray(ModuleName.Buffer, 2))
                            {
                                return true;
                            }
                        }
                        else if (CheckWaferNeedProcess(slot, ModuleName.PM2))
                        {
                            if (WaferManager.Instance.CheckNoTray(ModuleName.Buffer, 1))
                            {
                                return true;
                            }
                        }
                    }
                    else if (WaferManager.Instance.CheckNoTray(lstModuleName[j], 0))
                    {
                        return true;
                    }
                }
            }
            return false;
        }


        /// <summary>
        /// 判断Wafer的步骤是否都完成了
        /// </summary>
        /// <param name="waferModule"></param>
        /// <param name="waferSlot"></param>
        /// <returns></returns>
        public virtual bool CheckWaferSequenceStepDone(int slot)
        {
            var wafer = WaferManager.Instance.GetWafer(Module, slot);

            if (wafer.IsWaferEmpty)
            {
                return false;
            }
            if (wafer.ProcessJob == null || wafer.ProcessJob.Sequence == null)
            {
                return true;
            }

            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count && wafer.ProcessJob.Sequence.Steps.Count > 0)
            {
                return true;
            }

            return false;
        }

        public virtual bool CheckWaferNeedProcess(int waferSlot, ModuleName processIn = ModuleName.System)
        {
            var wafer = WaferManager.Instance.GetWafer(Module, waferSlot);

            if (wafer.IsWaferEmpty)
                return false;

            if (wafer.WaferStatus == WaferStatus.Dummy && wafer.ProcessState == WaferProcessStatus.Wait)
            {
                if (ModuleHelper.IsPm(processIn))
                {
                    return (CheckNeedRunClean(out bool withWafer, out _) && withWafer);
                }
                return true;
            }

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

            if (wafer.NextSequenceStep >= wafer.ProcessJob.Sequence.Steps.Count || wafer.ProcessJob.Sequence.Steps[wafer.NextSequenceStep].StepModules == null)
                return false;

            if (processIn != ModuleName.System)
            {
                for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)
                {
                    foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[i].StepModules)
                    {
                        if (ModuleHelper.IsPm(stepModule)&& stepModule==processIn)
                        {
                            return true;
                        }
                    }
                }
                return false;
            }

            bool hasPm = false;
            for (int i = wafer.NextSequenceStep; i < wafer.ProcessJob.Sequence.Steps.Count; i++)
            {
                foreach (var stepModule in wafer.ProcessJob.Sequence.Steps[i].StepModules)
                {
                    if (ModuleHelper.IsPm(stepModule))
                    {
                        hasPm = true;
                        break;
                    }
                }

                if (hasPm)
                    break;
            }

            if (!hasPm)
                return false;

            return true;
        }

        public virtual bool CheckNeedRunClean(out bool withWafer, out string recipeName)
        {
            recipeName = string.Empty;
            withWafer = false;

            //SequenceInfo seq = GetCurrentSequenceInfo();
            //int waferProcessed = StatsDataManager.Instance.GetValue($"{Module}.WaferProcessedSincePreviousClean");

            //if (seq == null)
            //    return false;


            //foreach (var stepInfo in seq.Steps)
            //{
            //    if (!stepInfo.StepModules.Contains(Module))
            //        continue;

            //    if (stepInfo.StepParameter.ContainsKey("CleanIntervalWaferless")
            //        && int.TryParse((string)stepInfo.StepParameter["CleanIntervalWaferless"], out int interval)
            //        && stepInfo.StepParameter.ContainsKey("CleanRecipeWaferless")
            //        && !string.IsNullOrEmpty((string)stepInfo.StepParameter["CleanRecipeWaferless"]))
            //    {
            //        if (interval > 0 && waferProcessed >= interval)
            //        {
            //            recipeName = (string)stepInfo.StepParameter["CleanRecipeWaferless"];
            //            withWafer = false;
            //            return true;
            //        }
            //    }

            //    if (stepInfo.StepParameter.ContainsKey("CleanIntervalWafer")
            //        && int.TryParse((string)stepInfo.StepParameter["CleanIntervalWafer"], out interval)
            //        && stepInfo.StepParameter.ContainsKey("CleanRecipeWafer")
            //        && !string.IsNullOrEmpty((string)stepInfo.StepParameter["CleanRecipeWafer"]))
            //    {
            //        if (interval > 0 && waferProcessed >= interval)
            //        {
            //            recipeName = (string)stepInfo.StepParameter["CleanRecipeWafer"];
            //            withWafer = true;
            //            return true;
            //        }
            //    }
            //}

            return false;
        }

        public virtual bool IsReadyForPick(ModuleName robot, int slot)
        {
            return true;
        }

        public virtual bool IsReadyForPlace(ModuleName robot, int slot)
        {
            return true;
        }

        public virtual bool IsReadyForTransfer(ModuleName robot, int slot)
        {
            return true;
        }

        

        public virtual bool PrepareTransfer(ModuleName robot, EnumTransferType type, int slot)
        {
            return true;
        }

        public virtual bool PostTransfer(ModuleName robot, EnumTransferType type, int slot)
        {
            return true;
        }

        public virtual bool Process(string recipeName, bool isCleanRecipe, bool withDummyWafer)
        {
            return true;
        }

        public virtual bool Cooling(bool coolingType, int coolingTime)
        {
            return true;
        }

        public virtual bool Aligning()
        {
            return true;
        }

        public virtual bool WarmUp(int warmUpTime)
        {
            return true;
        }


        public virtual bool CheckWaferTraySeparated()
        {
            return true;
        }

        public virtual bool CheckWaferTrayGrouped()
        {
            return true;
        }

        public virtual bool CheckSlitValveClosed() //检查闸板阀是否关闭
        {
            return true;
        }

        public virtual bool CheckTrayPlaced()
        {
            return true;
        }

        #endregion
    }

}
