using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Venus_RT.Devices;
using MECF.Framework.Common.Routine;
using System.Diagnostics;
using System.Collections.Generic;
using Venus_Core;
using System;
using Venus_Unity;
using MECF.Framework.Common.DBCore;
using System.Text;

namespace Venus_RT.Modules.PMs
{
    class GasBoxLeakCheckRoutine : PMRoutineBase, IRoutine
    {
        private enum LeakCheckStep
        {
            kPumpToBasePressure,
            kPumpingDelay,
            kLeakCheckDelay,
            kEnd,
        }
        public double LeakRate { get; private set; }

        private int _basePressure = 100;
        private int _leakcheckPumpTime = 180;
        private int _leakcheckHoldTime = 300;

        private double _startPressure = 0;
        private double _endPressure = 0;
        private double _leakRate = 30.0;
        private double _leakCheckBasePressure = 1;
        private List<int> _gasLineNums = new List<int>();

        Stopwatch _leakCheckTimer = new Stopwatch();

        bool isCheckVentLine;
        PMLeakCheckResult pMLeakCheckResult;
        Stopwatch _routineTimer = new Stopwatch();
        StringBuilder  gasLines=new StringBuilder();
        public string CurrentStep;
        PressureType _pressureType = PressureType.mTorr;
        public GasBoxLeakCheckRoutine(JetPMBase chamber) : base(chamber)
        {
            Name = "GasBox Leakcheck";
            if (chamber.ChamberType == JetChamber.Kepler2200A || chamber.ChamberType == JetChamber.Kepler2200B)
            {
                _pressureType = PressureType.Pa;
            }
        }

        public RState Start(params object[] objs)
        {
            if (CheckLid() &&
                CheckSlitDoor() &&
                CheckTurboPump())
            {
                CurrentStep = "Pump To BasePressure";
                Reset();

                _basePressure = SC.GetValue<int>($"{Module}.Pump.PumpBasePressure");
                //_leakcheckPumpTime = SC.GetValue<int>($"{Module}.Pump.LeakCheckPumpingTime");
                //_leakcheckHoldTime = SC.GetValue<int>($"{Module}.Pump.LeakCheckHoldTime");
                //_leakRate = SC.GetValue<double>($"{Module}.Pump.LeakRate");
                _leakcheckPumpTime = (int)(objs[0]);
                _leakcheckHoldTime = (int)(objs[1]);
                _leakRate = (double)(objs[2]);
                _leakCheckBasePressure = SC.GetValue<double>($"{Module}.Pump.LeakCheckBasePressure");

                // Extract line numbers which need do Leakcheck from config file
                _gasLineNums.Clear();
                //var lineNums = SC.GetStringValue($"{Module}.Pump.LeakCheckGasLineNums").Split(',');
                var lineNums = objs[3].ToString().Split(',');
                int nNum;
                int allGas=8;
                if (_chamber.ChamberType == JetChamber.Kepler2200A || _chamber.ChamberType == JetChamber.Kepler2200B)
                {
                    allGas = 6;
                }
                foreach(string num in lineNums)
                {
                    if(int.TryParse(num, out nNum))
                    {
                        if(nNum > 0 && nNum <= allGas && !_gasLineNums.Contains(nNum))
                        {
                            _gasLineNums.Add(nNum);
                        }
                    }
                }
                isCheckVentLine = (bool)objs[4];
                pMLeakCheckResult = new PMLeakCheckResult();

                pMLeakCheckResult.CheckMode = objs[5].ToString();

                if (_gasLineNums.Count == 0 && isCheckVentLine==false)
                {
                    Stop($"No Gasline need do LeakCheck, please check the config item{Module}.Pump.LeakCheckGasLineNums");
                    return RState.Failed;
                }

                gasLines.Clear();
                PreSetValves();
                pMLeakCheckResult.CheckDate = DateTime.Now.ToString("yyyyMMddHHmm");
                _routineTimer.Restart();
                Reset();
                return Runner.Start(Module, Name);
            }
            return RState.Failed;
        }

        public RState Monitor()
        {
            Runner.Wait(LeakCheckStep.kPumpToBasePressure,                                                     ()=> { return _chamber.ProcessPressure <= _basePressure; })
                .Run(LeakCheckStep.kPumpingDelay,          LeakCheckPumping,                                   PumpingDelay)
                .Run(LeakCheckStep.kLeakCheckDelay,        StartLeakCheck,                                     _leakcheckHoldTime * 1000)
                .End(LeakCheckStep.kEnd,                   CalcLeakCheckResult,                                _delay_50ms);

            return Runner.Status;
        }

        public void Abort()
        {
            CloseAllValves();
        }

        private bool LeakCheckPumping()
        {
            CurrentStep = "Check Pump";
            foreach (var num in _gasLineNums)
            {             
                var _MfcN2Scale = SC.GetValue<int>($"{Module}.MfcGas{num}.MfcN2Scale");
                var _MfcScaleFactor = SC.GetValue<Double>($"{Module}.MfcGas{num}.MfcScaleFactor");
                var _GasFlow = _MfcN2Scale * _MfcScaleFactor;
                _chamber.FlowGas(num-1, _GasFlow);
                gasLines.Append($"Gas{num},");
            }
            if (_gasLineNums.Contains(1))
            {
                _chamber.OpenValve(ValveType.PV11, true);
            }
            if (_gasLineNums.Contains(2))
            {
                _chamber.OpenValve(ValveType.PV21, true);
            }
            if (_gasLineNums.Contains(3))
            {
                _chamber.OpenValve(ValveType.PV31, true);
            }
            if (_gasLineNums.Contains(4))
            {
                _chamber.OpenValve(ValveType.PV41, true);
            }
            //2023/04/25添加vent line漏气检测
            if (isCheckVentLine == true)
            {
                _chamber.OpenValve(ValveType.PVN21, true);
                _chamber.OpenValve(ValveType.PVN22, true);
                _chamber.OpenValve(ValveType.N2, true);
                gasLines.Append("VentLine");
            }
            _leakCheckTimer.Restart();
            return true;
        }

        private bool PumpingDelay()
        {
            if (_leakCheckTimer.ElapsedMilliseconds >= _leakcheckPumpTime * 1000)
            {
                if (_chamber.ProcessPressure <= _leakCheckBasePressure)
                    return true;
                else
                {
                    Runner.Stop($"GasBox Leakcheck失败, 工艺压力 [{_chamber.ProcessPressure}]{_pressureType}, 高于LeakCheck Base Pressure: [{_leakCheckBasePressure}] {_pressureType}");
                }
            }

            return false;
        }

        private bool StartLeakCheck()
        {
            CurrentStep = "Leak Check";
            _startPressure = _chamber.ProcessPressure;
            pMLeakCheckResult.StartPressure = _startPressure;
            Notify($"PM 压力开始值 {_startPressure} {_pressureType}");

            _chamber.TurnPendulumValve(false);
            return true;
        }

        private bool CalcLeakCheckResult()
        {
            _endPressure = _chamber.ProcessPressure;
            pMLeakCheckResult.EndPressure = _endPressure;
            LeakRate = (_endPressure - _startPressure) * 60.0 / _leakcheckHoldTime;
            pMLeakCheckResult.LeakRate = LeakRate;
            if (LeakRate < _leakRate)
            {
                Notify($"GasBox Leakcheck完成, 压力结束值: {_startPressure} {_pressureType}, 漏率:{LeakRate} {_pressureType}/min");
                pMLeakCheckResult.Result = "Success";
            }
            else
            {
                Stop($"GasBox Leakcheck失败, 腔体漏率 [{LeakRate}] {_pressureType}/min, 高于 [{_leakRate}] {_pressureType}/min");
                pMLeakCheckResult.Result = "Fail";
            }
            LeakCheckDataRecorder.Add(_leakcheckHoldTime, Math.Round(_startPressure, 1), Math.Round(_endPressure, 1), LeakRate, pMLeakCheckResult.Result, pMLeakCheckResult.CheckMode, _chamber.Name, gasLines.ToString());

            _chamber.StopAllGases();
            _chamber.TurnPendulumValve(true);

            _chamber.OpenValve(ValveType.PV11, false);
            _chamber.OpenValve(ValveType.PV21, false);
            _chamber.OpenValve(ValveType.PV31, false);
            _chamber.OpenValve(ValveType.PV41, false);
            pMLeakCheckResult.LeakCheckTime = (int)_routineTimer.ElapsedMilliseconds / 1000;
            //SerializeHelper.Instance.WriteToJsonFile<PMLeakCheckResult>(pMLeakCheckResult, $"LeakCheck/PM/{DateTime.Now.ToString("yyyyMMddHHmm")}.json");

            return true;
        }

        private void PreSetValves()
        {
            _chamber.OpenValve(ValveType.FastPump, false);
            if(_chamber.ChamberType!=JetChamber.VenusDE) 
            {
                _chamber.OpenValve(ValveType.SoftPump, false);  
            }
            _chamber.OpenValve(ValveType.SoftPump, false);
            _chamber.OpenValve(ValveType.TurboPumpPumping, true);
            _chamber.OpenValve(ValveType.Guage, true);
            _chamber.OpenValve(ValveType.GasFinal, true);

            _chamber.TurnPendulumValve(true);

            _chamber.StopAllGases();
            _chamber.OpenValve(ValveType.PV11, false);
            _chamber.OpenValve(ValveType.PV21, false);
            _chamber.OpenValve(ValveType.PV31, false);
            _chamber.OpenValve(ValveType.PV41, false);
        }
    }
}