using System;
using System.Collections.Generic;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Common;
using Aitex.Core.RT.RecipeCenter;
using Venus_RT.Devices;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.SubstrateTrackings;
using Venus_Core;
using System.Diagnostics;
using MECF.Framework.Common.DBCore;
using System.Threading.Tasks;
using Aitex.Core.RT.Event;

namespace Venus_RT.Modules.PMs
{
    class PMProcessRoutine : PMRoutineBase, IRoutine
    {
        private enum ProcessStep
        {
            PreparePressure,
            PrepareTemperature,
            RunChuckRecipe,
            RunProcessRecipe,
            RunDechuckRecipe,
            RunCleanRecipe,
            End,
        }
        public string CurrentRunningRecipe { get; set; }
        public string ProcessRecipeName { get; set; }
        public string ChuckRecipeName { get; set; }
        public string DechuckRecipeName { get; set; }
        public string CleanRecipeName { get; set; }
        public RecipeHead ProcessRecipeHead { get; set; }
        public DateTime RecipeStartTime { get; private set; }
        public DateTime RecipeEndTime { get; private set; }
        public string WaferId { get; set; }
        public string SlotID { get; set; }
        public string LotID { get; set; }
        public string RecipeId { get; set; }

        //public bool CurrentRecipeType { get; set; }
        //int Timeall;
        private Stopwatch Recipetime = new Stopwatch();
        private readonly PumpDownRoutine _pumpDownRoutine;
        private readonly ProcessHelper _processHelper;
        private bool _withWafer = true;
        //private bool _needPumpDown = false;
        public Recipe _currentRecipe = null;
        private int _currentStep = 0;
        private List<Recipe> Recipelist = new List<Recipe>();

        private double _tolerance;
        private double _OffsetTemp = 0.0f;

        private bool _bLoopMode = false;
        private int _loopStartStep = 0;
        private int _loopCounter = 0;
        private int _recipeRunningMode = 0;
        private Stopwatch _stepTime = new Stopwatch();
        public RecipeResult currentRecipeResult;
        public bool isMaualEndStep;
        private RecipeFACallback _faCallback;
        private JetChamber _jetChamber;
        private RecipeType _recipeType;
        private Recipe ProcessRecipe;
        private Recipe ChuckRecipe;
        private Recipe DechuckRecipe;
        private Recipe CleanRecipe;
        private bool needprocess;
        private bool needdechuck;
        private bool needchuck;
        private bool needclean;
        private double BaseTemperature
        {
            get
            {
                if (ProcessRecipeHead != null)
                {
                    if (!string.IsNullOrEmpty(ProcessRecipeHead.BaseTemperature))
                    {
                        double setpoint = Convert.ToDouble(ProcessRecipeHead.BaseTemperature);
                        if (setpoint > 0 && setpoint < 600)
                            return setpoint;
                    }
                }
                return 0;
            }
        }
        private double BasePressure
        {
            get
            {
                if (ProcessRecipeHead != null)
                {
                    if (!string.IsNullOrEmpty(ProcessRecipeHead.BasePressure))
                    {
                        double setpoint = Convert.ToDouble(ProcessRecipeHead.BasePressure);
                        if (setpoint > 0 && setpoint < 750000)
                            return setpoint;
                    }
                }
                return SC.GetValue<int>($"{Module}.Pump.PumpBasePressure");
            }
        }
        public double EstimatedTotalLeftTime
        {
            get;
            private set;
        }

        public PMProcessRoutine(JetPMBase chamber, PumpDownRoutine pdRoutine) : base(chamber)
        {
            Name = "Process";
            _pumpDownRoutine = pdRoutine;
            _processHelper = new ProcessHelper(chamber);
            _faCallback = new RecipeFACallback();

            _jetChamber = (JetChamber)SC.GetValue<int>($"{chamber.Module}.ChamberType");
        }

        private bool AssignFuns(Recipe recipe)
        {
            foreach (var step in recipe.Steps)
            {
                if (_processHelper.LoadStepFuns(step) == false)

                    return false;

                foreach (ProcessUnitBase unit in step.LstUnit)
                {
                    if (_processHelper.LoadMethods(unit) == false)
                    {
                        Stop($"Cannot find the process routine for unit:{unit.GetType()}");
                        return false;
                    }
                }
            }
            return true;
        }
        public RState Start(params object[] objs)
        {
            needprocess = false;
            needchuck = false;
            needclean = false;
            needdechuck = false;
            Recipelist.Clear();
            string recipeName = (string)objs[0];
            if (objs.Length >= 2)
            {
                _recipeType = (RecipeType)Enum.Parse(typeof(RecipeType), objs[2].ToString());
                if (_recipeType == RecipeType.Clean)
                {
                    _withWafer = false;
                }
                else
                {
                    _withWafer = true;
                }
            }
            if (objs.Length >= 4)
            {
                LotID = objs[3].ToString();
            }
            else
            {
                LotID = "";
            }

            if (_withWafer && WaferManager.Instance.CheckNoWafer(Module, 0))
            {
                Stop($"can not run process, no wafer at {Module}");
                EV.PostAlarmLog(Module.ToString(), $"can not run process, no wafer at {Module}");
                return RState.Failed;
            }
            else if (!_withWafer && WaferManager.Instance.CheckHasWafer(Module, 0))
            {
                Stop($"can not run clean recipe{recipeName}, a wafer at {Module}");
                EV.PostAlarmLog(Module.ToString(), $"can not run clean recipe, a wafer at {Module}");
                return RState.Failed;
            }

            if (!_chamber.IsRFGInterlockOn)
            {
                Stop("射频电源 Interlock条件不满足");
                EV.PostAlarmLog(Module.ToString(), "射频电源 Interlock条件不满足");
                return RState.Failed;
            }

            if (!CheckSlitDoor() || !CheckDryPump() || !CheckTurboPump())
            {
                return RState.Failed;
            }
            currentRecipeResult = new RecipeResult();
            currentRecipeResult.RecipeName = recipeName;
            string recipeContent = RecipeFileManager.Instance.LoadRecipe(_chamber.Name, recipeName, false, objs[2].ToString());
            Recipe recipe = Recipe.Load(recipeContent);
            currentRecipeResult.RecipeStepCount = recipe.Steps.Count;
            if (recipe == null)
            {
                Stop($"Load Recipe:{recipeName} failed");
                EV.PostAlarmLog(Module.ToString(), $"Load Recipe:{recipeName} failed");
                return RState.Failed;
            }
            _recipeRunningMode = SC.GetValue<int>($"{Module}.RecipeRunningMode");
            _processHelper.m_RecipeHead = recipe.Header;
            switch (recipe.Header.Type)
            {
                case RecipeType.Process:

                    if (_recipeRunningMode == 1 && recipe.Header.ChuckRecipe != null && !string.IsNullOrEmpty(recipe.Header.ChuckRecipe))
                    {
                        string chuckcontent = RecipeFileManager.Instance.LoadRecipe(_chamber.Name, recipe.Header.ChuckRecipe, false, RecipeType.Chuck.ToString());
                        ChuckRecipe = Recipe.Load(chuckcontent);
                        if (ChuckRecipe != null)
                        {
                            ChuckRecipeName = recipe.Header.ChuckRecipe;
                            needchuck = true;
                            Recipelist.Add(ChuckRecipe);
                        }
                    }
                    needprocess = true;
                    ProcessRecipeHead = recipe.Header;
                    ProcessRecipe = recipe;
                    ProcessRecipeName = recipeName;
                    Recipelist.Add(recipe);



                    if (_recipeRunningMode == 1 && recipe.Header.DechuckRecipe != null && !string.IsNullOrEmpty(recipe.Header.DechuckRecipe))
                    {

                        string dechuckcontent = RecipeFileManager.Instance.LoadRecipe(_chamber.Name, recipe.Header.DechuckRecipe, false, RecipeType.DeChuck.ToString());
                        DechuckRecipe = Recipe.Load(dechuckcontent);
                        if (DechuckRecipe != null)
                        {
                            DechuckRecipeName = recipe.Header.DechuckRecipe;
                            needdechuck = true;
                            Recipelist.Add(DechuckRecipe);
                        }
                    }
                    break;
                case RecipeType.Chuck:
                    ChuckRecipeName = recipeName;
                    ChuckRecipe = recipe;
                    Recipelist.Add(ChuckRecipe);
                    needchuck = true;
                    break;
                case RecipeType.DeChuck:
                    DechuckRecipeName = recipeName;
                    Recipelist.Add(DechuckRecipe);
                    DechuckRecipe = recipe;
                    needdechuck = true;
                    break;
                case RecipeType.Clean:
                    CleanRecipe = recipe;
                    CleanRecipeName = recipeName;
                    Recipelist.Add(CleanRecipe);
                    needclean = true;
                    break;
            }
            foreach (Recipe rcp in Recipelist)
            {
                if (AssignFuns(rcp) == false)
                {
                    Stop($"Associate process alogrithm with recipe:{rcp.Header.Name} failed");
                    EV.PostAlarmLog(Module.ToString(), $"Associate process alogrithm with recipe:{rcp.Header.Name} failed");
                    return RState.Failed;
                }
            }
            _bLoopMode = false;
            _loopStartStep = 0;
            _loopCounter = 0;

            _processHelper.isLoop = false;
            _processHelper.loopsteps = 0;
            _processHelper.currentStepIndex = 0;

            if (_jetChamber == JetChamber.Venus)
            {
                _tolerance = SC.GetValue<double>($"System.MaxTemperatureToleranceToTarget");
                _OffsetTemp = SC.GetValue<double>($"{Module}.Chiller.ChillerTemperatureOffset");
            }
            _faCallback.RecipeStart(_chamber.Module.ToString(), recipeName);
            WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.InProcess);
            return Runner.Start(Module, Name);
        }
        public RState Monitor()
        {
            Runner
                  .Run(ProcessStep.PreparePressure, PreparePressure, IsPressureReady)
                  .Run(ProcessStep.PrepareTemperature, PrepareTemp, IsTempReady)
                  .RunIf(ProcessStep.RunChuckRecipe, needchuck, StartChuckRecipe, CheckRecipeDone, 5 * 60 * 60 * 1000)
                  .RunIf(ProcessStep.RunProcessRecipe, needprocess, StartProcessRecipe, CheckRecipeDone, 5 * 60 * 60 * 1000)
                  .RunIf(ProcessStep.RunDechuckRecipe, needdechuck, StartDechuckRecipe, CheckRecipeDone, 5 * 60 * 60 * 1000)
                  .RunIf(ProcessStep.RunCleanRecipe, needclean, StartCleanRecipe, CheckRecipeDone, 5 * 60 * 60 * 1000)
                  .End(ProcessStep.End, ProcessDone, _delay_1s);

            return Runner.Status;
        }

        private bool PreparePressure()
        {
            //2023/09/02 tps remove
            //if (_chamber.ChamberPressure < 5 && _chamber.ProcessPressure < BasePressure)
            //{
            //    _needPumpDown = false;
            //    return true;
            //}

            //_needPumpDown = true;
            return _pumpDownRoutine.Start(BasePressure) == RState.Running;
        }

        private bool IsPressureReady()
        {
            //if (_needPumpDown == false)
            //    return true;

            var status = _pumpDownRoutine.Monitor();
            if (status == RState.End)
            {
                return true;
            }
            else if (status == RState.Failed || status == RState.Timeout)
            {
                Runner.Stop($"Pump down to {BasePressure} failed.");
                EV.PostAlarmLog(Module.ToString(), $"Pump down to {BasePressure} failed.");
                return true;
            }

            return false;
        }

        private bool PrepareTemp()
        {
            if (_jetChamber == JetChamber.Venus)
            {
                return SetCoolantTemp(BaseTemperature, _OffsetTemp);
            }
            else
            {
                return true;
            }
        }

        private bool IsTempReady()
        {
            if (_jetChamber == JetChamber.Venus)
            {
                return CheckCoolantTemp(BaseTemperature, _tolerance);
            }
            else
            {
                return true;
            }
        }

        public RState StartNewStep()
        {
            ProcessDataRecorder.StepStart(RecipeId, _currentRecipe.Steps[_currentStep].StepNo, $"{Module}:{_currentRecipe.Header.Name}:{_currentRecipe.Steps[_currentStep].Description}", _currentRecipe.Steps[_currentStep].Time);
            _stepTime.Restart();
            var state = _currentRecipe.Steps[_currentStep].Start();
            if (state != RState.Running)
                return state;


            //if (_bLoopMode == true)
            //{
            //}
            if (_currentRecipe.Steps[_currentStep].CycleStart)
            {
                if (!_bLoopMode)
                {
                    _bLoopMode = true;
                    _loopStartStep = _currentStep;
                    _loopCounter = _currentRecipe.Steps[_currentStep].CycleNumber - 1;

                    currentRecipeResult.RecipeAllCounters = _currentRecipe.Steps[_currentStep].CycleNumber;
                    currentRecipeResult.RecipeCurrentCounter = _loopCounter == 0 ? 0 : 1;

                    _processHelper.isLoop = true;
                    _processHelper.loopsteps = _currentRecipe.Steps[_currentStep].CycleNumber;
                }
                else
                {
                    _processHelper.currentStepIndex += 1;
                }
            }


            return RState.Running;
        }
        private bool startRecipe(Recipe _recipe)
        {
            _currentRecipe = _recipe;
            if (_currentRecipe != null)
            {
                _currentStep = 0;
                CurrentRunningRecipe = _currentRecipe.Header.Name;
                RecipeId = Guid.NewGuid().ToString();
                RecipeStartTime = DateTime.Now;
                Recipetime.Restart();
                Notify($"Recipe:{CurrentRunningRecipe} start");
                _chamber.EPDRecipeStart(CurrentRunningRecipe);
                return StartNewStep() == RState.Running;
            }
            else { return false; }
        }
        private bool StartProcessRecipe()
        {
            return startRecipe(ProcessRecipe);
        }
        private bool StartChuckRecipe()
        {
            return startRecipe(ChuckRecipe);
        }
        private bool StartDechuckRecipe()
        {
            return startRecipe(DechuckRecipe);
        }
        private bool StartCleanRecipe()
        {
            return startRecipe(CleanRecipe);
        }
        private bool CheckRecipeDone()
        {
            var step = _currentRecipe.Steps[_currentStep];
            currentRecipeResult.RecipeStepCount = _currentRecipe.Steps.Count;
            currentRecipeResult.RecipeName = _currentRecipe.Header.Name;
            currentRecipeResult.RecipeType = _currentRecipe.Header.Type.ToString();
            currentRecipeResult.RecipeStepNumber = step.StepNo;
            currentRecipeResult.RecipeStepType = step.Type.ToString();
            currentRecipeResult.RecipeStepDescription = string.IsNullOrEmpty(step.Description) ? "" : step.Description;
            currentRecipeResult.RecipeStepSetTime = step.Time;
            currentRecipeResult.RecipeType = _currentRecipe.Header.Type.ToString();
            currentRecipeResult.RecipeStepDuringTime = new System.TimeSpan(0, 0, System.Convert.ToInt32(_stepTime.ElapsedMilliseconds / 1000));
            var result = step.Run();
            if (result == RState.Failed)
            {
                RecipeDone("Fail");
                UpdateWaferStatus(false);
                Runner.Stop($"Recipe:{CurrentRunningRecipe}, Step:{_currentStep + 1} Failed");
                EV.PostAlarmLog(Module.ToString(), $"Recipe:{CurrentRunningRecipe}, Step:{_currentStep + 1} Failed");
                return true;
            }
            else if (result == RState.End || isMaualEndStep == true)
            {
                if (_currentRecipe.Steps.Count > _currentStep + 1 && _currentRecipe.Steps[_currentStep + 1].Type != StepType.OverEtch)
                {
                    _currentRecipe.Steps[_currentStep].End();
                }
                if (_currentRecipe.Steps[_currentStep].CycleEnd)
                {
                    if (_loopCounter > 0)
                    {
                        _loopCounter--;
                        currentRecipeResult.RecipeCurrentCounter += 1;

                        _currentStep = _loopStartStep;
                        return StartNewStep() != RState.Running;
                    }
                    else
                    {
                        _bLoopMode = false;
                        _loopStartStep = 0;
                        //_processHelper.loopStep(false, 0, 0);

                        _processHelper.isLoop = false;
                        _processHelper.loopsteps = 0;
                        _processHelper.currentStepIndex = 0;
                    }
                }

                if (_currentStep < _currentRecipe.Steps.Count - 1 || isMaualEndStep == true)
                {
                    result = RState.End;
                    isMaualEndStep = false;
                    _currentStep++;
                    return StartNewStep() != RState.Running;
                }
                else
                {
                    Notify($"Recipe:{CurrentRunningRecipe} finished");
                    //FaEvent.FaPostInfo(Module.ToString(), $"Recipe:{CurrentRunningRecipe} finished");
                    UpdateWaferStatus();
                    //if (_currentRecipe.Header.Type == RecipeType.Process)
                    //{

                    //    processRecipe = (Recipe)SerializeHelper.Instance.Clone(_currentRecipe);
                    //}
                    _chamber.EPDRecipeStop();
                    RecipeDone("Success");
                    return true;
                }
            }
            return false;
        }


        public void RecipeDone(string result)
        {
            Recipetime.Stop();
            WaferInfo waferInfo = WaferManager.Instance.GetWafer(ModuleHelper.Converter(Module.ToString()), 0);
            if (!waferInfo.IsEmpty)
            {
                WaferId = waferInfo.InnerId.ToString();
                SlotID = waferInfo.OriginSlot.ToString();
                //LotID = waferInfo.ProcessJob == null || string.IsNullOrEmpty(waferInfo.ProcessJob.ControlJobName) ? "" : waferInfo.ProcessJob.ControlJobName;
            }
            RecipeEndTime = RecipeStartTime + Recipetime.Elapsed;
            switch (_currentRecipe.Header.Type)
            {
                case RecipeType.Clean:
                    ProcessDataRecorder.RecordPrecess(RecipeId, RecipeStartTime, RecipeEndTime, _currentRecipe.Header.Name, result, "", _chamber.Name, "", "", _currentRecipe.Header.Type.ToString());
                    break;
                case RecipeType.Chuck:
                case RecipeType.DeChuck:
                case RecipeType.Process:
                    ProcessDataRecorder.RecordPrecess(RecipeId, RecipeStartTime, RecipeEndTime, _currentRecipe.Header.Name, result, WaferId, _chamber.Name, LotID, SlotID, _currentRecipe.Header.Type.ToString());
                    break;
            }
        }
        private bool ProcessDone()
        {
            _currentRecipe.Steps[_currentStep].End();

            RecipeFileManager.Instance.SaveAsRecipe2(Module.ToString(), _currentRecipe.Header.Type.ToString(), _currentRecipe.Header.Name, RecipeUnity.RecipeToString(_currentRecipe));
            _stepTime.Stop();
            WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Idle);
            WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Completed);
            CloseAllValves(500);
            _chamber.GeneratorSetpower(0);
            _chamber.GeneratorBiasSetpower(0);
            _chamber.GeneratorBiasPowerOn(false);
            _chamber.GeneratorPowerOn(false);
            _chamber.OpenValve(ValveType.TurboPumpPumping, true);
            _chamber.OpenValve(ValveType.TurboPumpPurge, true);
            _chamber.OpenValve(ValveType.Guage, true);
            _chamber.SetPVPostion(1000);
            if (_jetChamber == JetChamber.Venus && _chamber.IsHVOn == true)
            {
                _chamber.OnOffSetESCHV(false);
            }
            return true;
        }

        private void UpdateWaferStatus(bool bDone = true)
        {
            if (bDone == false)
            {
                WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Failed);
                if (_currentRecipe.Header.Type == RecipeType.Chuck)
                {
                    // set wafer chucked flag even if the chuck recipe failed.
                    WaferManager.Instance.UpdateWaferChuckStatus(Module, 0, EnumWaferChuckStatus.Chucked);
                }
            }
            switch (_currentRecipe.Header.Type)
            {
                case RecipeType.Process:
                    break;
                case RecipeType.Chuck:
                    WaferManager.Instance.UpdateWaferChuckStatus(Module, 0, EnumWaferChuckStatus.Chucked);
                    break;
                case RecipeType.DeChuck:
                    WaferManager.Instance.UpdateWaferProcessStatus(Module, 0, EnumWaferProcessStatus.Completed);
                    WaferManager.Instance.UpdateWaferChuckStatus(Module, 0, EnumWaferChuckStatus.Dechucked);
                    break;
            }
        }

        public async void Abort()
        {
            if (_currentRecipe != null)
            {
                RecipeDone("Abort");
            }
            _chamber.GeneratorBiasPowerOn(false);
            _chamber.GeneratorPowerOn(false);
            CloseAllValves();
            _chamber.OpenValve(ValveType.TurboPumpPumping, true);
            _chamber.OpenValve(ValveType.TurboPumpPurge, true);
            if (_chamber.ChamberType == JetChamber.Venus)
            {
                await Task.Delay(3000);
                _chamber.OnOffSetESCHV(false);
            }
        }
    }
}