using System;
using Aitex.Core.Common.DeviceData;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.Util;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.SubstrateTrackings;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.PMs;
using MECF.Framework.Common.MECF.Framework.Common.RecipeCenter.Recipe;
using SicModules.PMs.Routines;
using SicModules.PMs.Routines.Base;

namespace SicModules.PMs.RecipeExecutions
{
    public class CleanRecipe : PMBaseRoutine
    {
        public enum RoutineStep
        {
            SetServoUp,
            SetChamberPressure,
            EnableRotation,
            OpenH2Valve,
            EnableHeater,
            PcCalibartion,
            RunStepOne,
            Wait,
            CheckCondition,
            WaitTempReach,
        }

        enum RecipeRunningState
        {
            Error,
            RecipeCompleted,
            ExecStep,
            TimeWait,
            ConditionWait,
            StepCompleted,
            Paused,
        }

        private string _recipeName;

        private object _recipeLocker = new object();
        private bool _isPSUHeaterJumpMode;
        private bool _isSCRHeaterJumpMode;
        private bool _isMFCJumpMode;

        private int _currentStepNumber;

        private DeviceTimer _stepTimer = new DeviceTimer();
        private DeviceTimer _recipeTimer = new DeviceTimer();
        private RecipeRunningState _state = RecipeRunningState.ExecStep;

        private PMServoToPressure _pmServoToPressure;



        public CleanRecipe(ModuleName module, PMModule pm1) : base(module, pm1)
        {
            Module = module.ToString();
            Name = "CleanRecipe";
            _pmServoToPressure = new PMServoToPressure(module, pm1);

        }

        public void Init(string recipeName)
        {
            if (!recipeName.Contains("Sic\\Clean\\") && recipeName!="")
            {
                recipeName = "Sic\\Clean\\" + recipeName;
            }
            _recipeName = recipeName;
        }

        public override Result Start(params object[] objs)
        {
            Reset();

            if (!RecipeParser.Parse(_recipeName, Module, out var recipeHead, out var recipeSteps, out string reason))
            {
                Stop($"Load recipe {_recipeName} failed, {reason}");
                return Result.FAIL;
            }

            if (WaferManager.Instance.CheckHasWafer(PmDevice.Module, 0))
            {
                EV.PostWarningLog(Module, $"can not run clean recipe, Has wafer at {Module}");
                return Result.FAIL;
            }
            if (!PmDevice.Pump.IsOn || PmDevice.Pump.IsError)
            {
                EV.PostWarningLog(Module, $"can not run process, pump state is not correct");
                return Result.FAIL;
            }
            if (!PmDevice._ioThrottleValve.TVValveEnable)
            {
                EV.PostWarningLog(Module, $"can not run process, TV is not enable");
                return Result.FAIL;
            }

            if (PmDevice._ioThrottleValve.ControlModeFeedback != PressureCtrlMode.TVPressureCtrl)
            {
                EV.PostWarningLog(Module, $"can not run process, TV is not Pressure Ctrol Mode");
                return Result.FAIL;
            }

            if (!PmDevice.CheckIOValueByGroup(IoGroupName.I, true))
            {
                EV.PostAlarmLog(Module, $"can not run process,I valves is not open!");
                return Result.FAIL;
            }
            if (!PmDevice.CheckIOValueByGroup(IoGroupName.E, false))
            {
                EV.PostAlarmLog(Module, $"can not run process,E valves is not closed!");
                return Result.FAIL;
            }
            if (!PmDevice.CheckIOValueByGroup(IoGroupName.K, false))
            {
                EV.PostAlarmLog(Module, $"can not run process,K valves is not closed!");
                return Result.FAIL;
            }
            if (!PmDevice.CheckIOValueByGroup(IoGroupName.VentPump, true))
            {
                EV.PostAlarmLog(Module, $"can not run process,V72 is not open!");
                return Result.FAIL;
            }
            if (!PmDevice.PSU1.AllHeatEnable)
            {
                EV.PostAlarmLog(Module, $"can not run process,Heater is disable!");
                return Result.FAIL;
            }
            _currentStepNumber = 0;
            PmDevice.RecipeRunningInfo.RecipeName = _recipeName;
            PmDevice.RecipeRunningInfo.Head = recipeHead;
            PmDevice.RecipeRunningInfo.RecipeStepList = recipeSteps;
            PmDevice.RecipeRunningInfo.TotalTime = CalcRecipeTime();
            _state = RecipeRunningState.ExecStep;

            return Result.RUN;
        }

        public override Result Monitor()
        {
            try
            {
                SetConfinementRingUpAndWait((int)RoutineStep.SetServoUp, 30);

                ExecuteRoutine((int)RoutineStep.SetChamberPressure, _pmServoToPressure);

                EnableRotation((int)RoutineStep.EnableRotation, 5);

                OpenH2Valve((int)RoutineStep.OpenH2Valve, PmDevice, 2);

                EnableHeater((int)RoutineStep.EnableHeater, PmDevice, 5);

                MonitorRecipeRunInfo();

                lock (_recipeLocker)
                {
                    try
                    {
                        switch (_state)
                        {
                            case RecipeRunningState.ExecStep:

                                if (_currentStepNumber == 0)
                                {
                                    _recipeTimer.Start(int.MaxValue);
                                }

                                _stepTimer.Start(PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime * 1000);

                                Notify($"Running step {_currentStepNumber + 1} : {PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepName}");


                                //执行工艺程序命令
                                foreach (var recipeCmd in PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands.Keys)
                                {
                                    if (recipeCmd == "SusHeaterSetMode")
                                    {
                                        if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd] == "Jump")
                                            _isPSUHeaterJumpMode = true;
                                        else
                                            _isPSUHeaterJumpMode = false;

                                        continue;
                                    }
                                    if (recipeCmd == "WWHeaterSetMode")
                                    {
                                        if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd] == "Jump")
                                            _isSCRHeaterJumpMode = true;
                                        else
                                            _isSCRHeaterJumpMode = false;

                                        continue;
                                    }
                                    if (recipeCmd == "FlowSetMode")
                                    {
                                        if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd] == "Jump")
                                            _isMFCJumpMode = true;
                                        else
                                            _isMFCJumpMode = false;

                                        continue;
                                    }

                                    if (IsCmdSkip(recipeCmd)) // 不是注册的方法，需要跳过
                                        continue;

                                    if (!OP.CanDoOperation($"{Module}.{recipeCmd}", out string reason, PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd]))
                                    {
                                        EV.PostAlarmLog(Module, $"Can not execute {recipeCmd}, {reason}");
                                        return Result.FAIL;
                                    }
                                    else
                                    {
                                        int time = (int)PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime * 1000;

                                        if (recipeCmd.StartsWith("TC1") && _isPSUHeaterJumpMode)
                                        {
                                            time = 1;
                                        }

                                        if (recipeCmd.StartsWith("TC2") && _isSCRHeaterJumpMode)
                                        {
                                            time = 1;
                                        }

                                        if (recipeCmd.StartsWith("Mfc") && recipeCmd.EndsWith(".Ramp") && !PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsDummyStep)
                                        {
                                            if (_isMFCJumpMode)
                                            {
                                                time = 1;
                                            }
                                        }

                                        if ((recipeCmd == "TV.SetPressure"
                                            || recipeCmd == "PMServo.SetActualSpeed"
                                            || recipeCmd.StartsWith("Pressure") && recipeCmd.EndsWith(".Ramp")
                                            || recipeCmd.StartsWith("Mfc") && recipeCmd.EndsWith(".Ramp"))
                                            && !PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].IsDummyStep)
                                        {
                                            if (_currentStepNumber >= 1)
                                            {
                                                int previousStepNumber = _currentStepNumber - 1;

                                                if (PmDevice.RecipeRunningInfo.RecipeStepList[previousStepNumber].IsDummyStep)
                                                    previousStepNumber = _currentStepNumber - 2;

                                                if (PmDevice.RecipeRunningInfo.RecipeStepList[previousStepNumber].RecipeCommands.ContainsKey(recipeCmd))
                                                {
                                                    string previousValue = PmDevice.RecipeRunningInfo.RecipeStepList[previousStepNumber].RecipeCommands[recipeCmd];
                                                    string currentValue = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd];
                                                    if (previousValue == currentValue)
                                                    {
                                                        time = 1;
                                                    }
                                                }
                                            }
                                        }

                                        OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].RecipeCommands[recipeCmd]);                                        
                                    }
                                }

                                if (PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].EndBy == EnumEndByCondition.ByTime)
                                    _state = RecipeRunningState.TimeWait;
                                else
                                    _state = RecipeRunningState.ConditionWait;
                                break;

                            case RecipeRunningState.TimeWait:
                                if (_stepTimer.IsTimeout())
                                {
                                    _state = RecipeRunningState.StepCompleted;
                                }
                                break;
                            case RecipeRunningState.ConditionWait:
                                {
                                    if (_stepTimer.IsTimeout())
                                    {
                                        _state = RecipeRunningState.StepCompleted;
                                    }
                                }
                                break;
                            case RecipeRunningState.StepCompleted:
                                _currentStepNumber++;
                                if (_currentStepNumber >= PmDevice.RecipeRunningInfo.RecipeStepList.Count)
                                {
                                    _currentStepNumber = PmDevice.RecipeRunningInfo.RecipeStepList.Count - 1;
                                    _state = RecipeRunningState.RecipeCompleted;
                                }
                                else
                                {
                                    _state = RecipeRunningState.ExecStep;
                                }
                                break;
                            case RecipeRunningState.RecipeCompleted:
                                {
                                    _recipeTimer.Stop();
                                    Notify("Finished");
                                    return Result.DONE;
                                }
                        }

                        return Result.RUN;
                    }
                    catch (Exception ex)
                    {
                        LOG.Write(ex);
                        return Result.FAIL;
                    }
                }
            }
            catch (RoutineBreakException)
            {
                return Result.RUN;
            }
            catch (RoutineFaildException)
            {
                return Result.FAIL;
            }
            catch (Exception ex)
            {
                LOG.Write(ex, String.Format("CleanRecipe has exception"));
                throw (ex);
            }

            Notify("Finished");

            return Result.DONE;
        }

        protected void EnableHeater(int id, PMModuleBase pm, int timeout)
        {
            Tuple<bool, Result> ret = ExecuteAndWait(id, () =>
            {
                Notify($"Set {pm.Name} Heater Enable");

                if (!pm.EnableHeater(true, out string reason))
                {
                    Stop($"Set {pm.Name} Heater Enable failed, {reason}");
                    return false;
                }

                return true;
            }, () =>
            {
                return pm.CheckHeaterEnable();
            }, timeout * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                if (ret.Item2 == Result.TIMEOUT)
                {
                    Stop($"Set {pm.Name} Heater Enable timeout, over {timeout} seconds");
                    throw (new RoutineFaildException());
                }
                else
                {
                    throw (new RoutineBreakException());
                }
            }
        }

        protected int CalcRecipeTime()
        {
            double total = 0;
            for (int i = 0; i < PmDevice.RecipeRunningInfo.RecipeStepList.Count; i++)
            {
                if (!PmDevice.RecipeRunningInfo.RecipeStepList[i].IsDummyStep) // 不统计虚拟Step的时间
                {
                    total += PmDevice.RecipeRunningInfo.RecipeStepList[i].StepTime;
                }
            }

            return (int)total;
        }

        private void MonitorRecipeRunInfo()
        {
            try
            {
                PmDevice.RecipeRunningInfo.StepNumber = _currentStepNumber + 1;
                PmDevice.RecipeRunningInfo.StepName = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepName;
                PmDevice.RecipeRunningInfo.StepTime = PmDevice.RecipeRunningInfo.RecipeStepList[_currentStepNumber].StepTime;                
                PmDevice.RecipeRunningInfo.TotalElapseTime = _recipeTimer.GetElapseTime() / 1000;

            }
            catch (Exception ex)
            {

            }
        }

    }
}
