using System;
using System.Collections.Generic;
using Aitex.Core.Common;
using Aitex.Core.RT.Device;
using Aitex.Core.RT.Device.Devices;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.OperationCenter;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.SubstrateTrackings;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.PMs;
using SicModules.PMs.Routines.Base;

namespace SicModules.PMs.Routines.Recipe
{
    public class PrePMMacroRoutine : PMBaseRoutine
    {
        public enum RoutineStep
        {
            SetServoUp,
            SetChamberPressure,

            EnableRotation,

            OpenH2Valve,

            EnableHeater,

            PcCalibartion,

            RunStepOne,

            Wait,

            CheckCondition,

        }

        private string _recipeName;
        private bool _isCleanRecipe;
        private bool _withWafer;

        private Guid _guidProcess;

        private bool _isDryRun;
        private bool _isPSUHeaterJumpMode;
        private bool _isSCRHeaterJumpMode;
        private bool _isMFCJumpMode;
        private int _delayTimeRamp;

        private double _targetPressure;

        private IoInterLock _pmInterLock;

        private PMServoToPressure _pmServoToPressure;
        private PMPcCalibrationRoutine _pmPcCalibrationRoutine;

        public PrePMMacroRoutine(ModuleName module, PMModule pm1) : base(module, pm1)
        {
            Module = module.ToString();
            Name = "PrePMMacro";

            _pmInterLock = DEVICE.GetDevice<IoInterLock>($"{Module}.PMInterLock");
            _pmServoToPressure = new PMServoToPressure(module, pm1);
            _pmPcCalibrationRoutine = new PMPcCalibrationRoutine(module, pm1);
        }

        public void Init(string recipeName, bool isClean, bool withWafer)
        {
            _recipeName = recipeName;
            _isCleanRecipe = isClean;
            _withWafer = withWafer;
        }

        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 (!_withWafer && WaferManager.Instance.CheckHasWafer(PmDevice.Module, 0))
            {
                EV.PostWarningLog(Module, $"can not run waferless process, Has wafer at {Module}");
                return Result.FAIL;
            }

            if (_withWafer && !WaferManager.Instance.CheckHasWafer(PmDevice.Module, 0))
            {
                EV.PostWarningLog(Module, $"can not run process, no 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;
            }

            //Recipe Routine先打开加热
            PmDevice.SetHeatEnable(true);


            //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;
            //}

            if (!_pmInterLock.SetPMPreProcessRunning(true, out reason))
            {
                EV.PostAlarmLog(Module, $"can not run preProcess, {reason}");
                return Result.FAIL;
            }

            _isDryRun = SC.GetValue<bool>($"PM.{Module}.DryRun.IsDryRun");
            _delayTimeRamp = SC.GetValue<int>($"PM.{Module}.PreProcess.RampDelayTime");

            _targetPressure = SC.GetValue<double>($"PM.{Module}.PreProcess.ChamberPressure");
            _pmServoToPressure.Init(_targetPressure);

            _guidProcess = Guid.NewGuid();

            PmDevice.RecipeRunningInfo.RecipeName = _recipeName;
            PmDevice.RecipeRunningInfo.Head = recipeHead;
            PmDevice.RecipeRunningInfo.RecipeStepList = recipeSteps;

            Notify($"Start");

            return Result.RUN;
        }

        public override Result Monitor()
        {
            try
            {
// 
//                 ExecuteRoutine((int)RoutineStep.SetChamberPressure, _pmServoToPressure);
// 
//                 EnableRotation((int)RoutineStep.EnableRotation, 5);
// 
//                 OpenH2Valve((int)RoutineStep.OpenH2Valve, PMDevice, 2);
// 
//                 EnableHeater((int)RoutineStep.EnableHeater, PMDevice, 5);

                //ExecuteRoutine((int)RoutineStep.PcCalibartion, _pmPcCalibrationRoutine);


                //NoteInProcess((int)Routine.NoteInProcess,0);


                //if (_isSlitDoorOpened)
                //ExecuteRoutine((int)Routine.CloseSlitValve, _closeSlitValveRoutine);

                //关闭所有阀门
                // CloseAllValves((int)Routine.CloseAllVavle, 10);

                //if (!_isATMMode)
                //{
                //    // ExecuteRoutine((int)Routine.Pump, _pumptRoutine);

                //    //SetThrottlePressureControlMode((int)Routine.SetThrottlePressureControlMode, _throttleValve);
                //}

                //End((int)Routine.End, "Preprocess finished");

                //NoteProcessComplete((int)Routine.NoteProcessComplete, 0);
            }
            catch (RoutineBreakException)
            {
                return Result.RUN;
            }
            catch (RoutineFaildException)
            {
                //NoteProcessFailed((int)Routine.NoteProcessFailed);
                return Result.FAIL;
            }
            catch (Exception ex)
            {
                LOG.Write(ex, String.Format("Preprocess Monitor has exception"));
                throw (ex);
            }

            _pmInterLock.SetPMPreProcessRunning(false, out string reason);
            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 void RunStepOne(int id, PMModuleBase pm, int delayTime)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                Notify($"Run {pm.Name} recipe step one");

                string reason = string.Empty;

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

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

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

                        continue;
                    }

                    if (IsCmdSkip(recipeCmd))
                        continue;

                    if (!OP.CanDoOperation($"{Module}.{recipeCmd}", out reason, PmDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd]))
                    {
                        Stop($"Can not execute {recipeCmd}, {reason}");
                        return false;
                    }
                    else
                    {
                        int time = delayTime * 1000;
                        if (recipeCmd.StartsWith("TC1") && _isPSUHeaterJumpMode)
                        {
                            time = 1;
                        }
                        if (recipeCmd.StartsWith("TC2") && _isSCRHeaterJumpMode)
                        {
                            time = 1;
                        }
                        if (recipeCmd.StartsWith("Mfc") && recipeCmd.EndsWith(".Ramp") && _isMFCJumpMode)
                        {
                            time = 1;
                        }

                        //if (recipeCmd == "Pressure5.Ramp")
                        //{
                        //    double pc5Pressure = Convert.ToDouble(PMDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd]) + _pc5Offset;
                        //    OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, pc5Pressure.ToString());
                        //}
                        //else if (recipeCmd == "Pressure6.Ramp")
                        //{
                        //    double pc6Pressure = Convert.ToDouble(PMDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd]) + _pc6Offset;
                        //    OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, pc6Pressure.ToString());
                        //}
                        //else if (recipeCmd == "Pressure7.Ramp")
                        //{
                        //    double pc7Pressure = Convert.ToDouble(PMDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd]) + _pc7Offset;
                        //    OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, pc7Pressure.ToString());
                        //}
                        //else
                        {
                            OP.DoOperation($"{Module}.{recipeCmd}", out string reason1, time, PmDevice.RecipeRunningInfo.RecipeStepList[0].RecipeCommands[recipeCmd]);
                        }
                    }
                }

                return true;
            });

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else
                {
                    throw (new RoutineBreakException());
                }
            }
        }

        public void Wait(int id, string stepName, int delayTime)
        {
            Tuple<bool, Result> ret = Delay(id, () =>
            {
                Notify($"Wait for {delayTime} seconds");

                _stepSpan = new TimeSpan(0, 0, 0, (int)delayTime);
                _stepStartTime = DateTime.Now;
                _stepName = stepName;

                return true;
            }, delayTime * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    throw (new RoutineFaildException());
                }
                else
                {
                    throw (new RoutineBreakException());
                }
            }
        }

        protected void CheckCondition(int id, PMModuleBase pm, Dictionary<string, string> recipeCommands)
        {
            //Tuple<bool, Result> ret = Execute(id, () =>
            //{
            //    Notify($"Run {pm.Name} check condition");

            //    if (!pm.CheckPreProcessCondition(recipeCommands, out string reason))
            //    {
            //        Stop(reason);
            //        return false;
            //    }

            //    return true;
            //});

            //if (ret.Item1)
            //{
            //    if (ret.Item2 == Result.FAIL)
            //    {
            //        throw (new RoutineFaildException());
            //    }
            //    else
            //    {
            //        throw (new RoutineBreakException());
            //    }
            //}
            string reason = String.Empty;
            Tuple<bool, Result> ret = Wait(id, () =>
            {
                if (!pm.CheckPreProcessCondition(recipeCommands, out reason))
                {
                    return false;
                }

                return true;
            }, 60 * 1000);

            if (ret.Item1)
            {
                if (ret.Item2 == Result.FAIL)
                {
                    Stop(reason);
                    throw (new RoutineFaildException());
                }
                else if (ret.Item2 == Result.TIMEOUT)
                {
                    Stop(reason);
                    throw (new RoutineFaildException());
                }
                else
                {
                    throw (new RoutineBreakException());
                }
            }
        }

        protected void NoteInProcess(int id, int slot)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                Notify($"Update process information, process in {ModuleName.PM1} start");

                ModuleName mod = ModuleName.PM1;

                WaferManager.Instance.UpdateWaferProcessStatus(mod, slot, WaferProcessStatus.InProcess);

                //_pm.OnProcessStart(_guidProcess.ToString(), _recipeName, false);

                return true;
            });

            if (ret.Item1)
            {
                throw (new RoutineBreakException());
            }
        }


        protected void NoteProcessComplete(int id, int slot)
        {
            Tuple<bool, Result> ret = Execute(id, () =>
            {
                Notify($"Update process information, process in {ModuleName.PM1} completed");

                ModuleName mod = ModuleName.PM1;

                WaferManager.Instance.UpdateWaferProcessStatus(mod, slot, WaferProcessStatus.Completed);

                return true;
            });

            if (ret.Item1)
            {
                throw (new RoutineBreakException());
            }
        }

        public void Exit()
        {

        }

        public override void Abort()
        {
            _pmInterLock.SetPMPreProcessRunning(false, out string reason);
            PmDevice.AbortRunProcess(out reason);

            //_pm.StopAllGasFlow(out string reason);
            //_pm.SetPowerOnOff(false, out reason);
            //_pm.SetPower(0, false);
            //_pm.CloseValvesForPumping(out reason);

            //_executor.RecipeRunningInfo.Step = 0;
            //_executor.RecipeRunningInfo.ElapsedTime = 0;
        }

    }
}
