#define _FAKE_DATA

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using Aitex.Core.Common.DeviceData.IoDevice;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.DBCore;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using Sicentury.Core.Collections;
#if FAKE_DATA
using System.Threading;
using System.Threading.Tasks;
#endif


namespace MECF.Framework.RT.Core.Managers.PDS
{
    public class ProcessDataStatManager
    {
        #region Variables

        /// <summary>
        /// 工艺数据统计列表中显示的最大行数
        /// </summary>
        private const int DISPLAYED_ROWS_MAX = 10;

        private readonly object _syncObject = new();

        /// <summary>
        /// 后台统计工艺数据的线程
        /// </summary>
        private readonly PeriodicJob _tStatistic;

#if FAKE_DATA

        private readonly Random _randomFlow;

#endif

        #endregion

        #region Constructors

        public ProcessDataStatManager(string module)
        {
            Debug.Assert(!string.IsNullOrEmpty(module), "the module is not assigned");

            Module = module;
            GasFlowCountCollection = new ObservableQueue<ProcessDataStatPerRun>(DISPLAYED_ROWS_MAX);
            GasFlowCountCollection.CollectionChanged += GasFlowCountCollectionOnCollectionChanged;

            // 加载历史记录。
            ReadLastFlowCounts();

            DATA.Subscribe($"{Module}.ProcessDataStat.RealtimeList", ()=> ProcessRunDataList);

            _tStatistic = new PeriodicJob(1000, OnTimer, "MonitorProcDataStatPerRun", false);

#if FAKE_DATA

            _randomFlow = new Random();

            //for (var i = 0; i < 10; i++)
            //{
            //    var counter = new GasFlowPerRun();
            //    counter.H2.AddFlow(_randomFlow.NextDouble());
            //    counter.Ar.AddFlow(_randomFlow.NextDouble());
            //    counter.PN2.AddFlow(_randomFlow.NextDouble());
            //    counter.HCL.AddFlow(_randomFlow.NextDouble());
            //    counter.SiH4.AddFlow(_randomFlow.NextDouble());
            //    counter.C3H8.AddFlow(_randomFlow.NextDouble());
            //    counter.TCS.AddFlow(_randomFlow.NextDouble());
            //    counter.TMA.AddFlow(_randomFlow.NextDouble());
            //    counter.StatisticsEnd = DateTime.Now;

            //    GasFlowCountCollection.Enqueue(counter);

            //    CurrentDataStat = counter;
            //}

            // Add new Flow Counter every 5s
            Task.Run(() =>
            {
                while (true)
                {
                    Thread.Sleep(5000);
                    if (CurrentDataStat != null)
                    {
                        // 结束当前的统计，随后开启新统计
                        CurrentDataStat.StatisticsEnd = DateTime.Now;
                        SaveFlowCount(CurrentDataStat);
                    }

                    var counter = new GasFlowPerRun();
                    GasFlowCountCollection.Enqueue(counter);
                    CurrentDataStat = counter;
                }
            });

#endif

        }

        #endregion

        #region Properties

        public string Module { get; private set; }

        public ObservableQueue<ProcessDataStatPerRun> GasFlowCountCollection { get; }

        public ProcessDataStatPerRun CurrentDataStat { get; private set; }

        public List<AITProcessRunData> ProcessRunDataList
        {
            get
            {
                var list = new List<AITProcessRunData>();
                lock (_syncObject)
                {
                    list.AddRange(GasFlowCountCollection.OrderBy(x => x.Index)
                    .ToList()
                    .Select(item => new AITProcessRunData
                    {
                        Uid = item.StatisticsUid,
                        Index = item.Index,
                        Module = item.Module,
                        RecipeName = item.RecipeName.Replace("Sic\\Process\\", ""),
                        WaferId = item.WaferId,
                        ProcessBegin = item.StatisticsStart,
                        ProcessEnd = item.StatisticsEnd,
                        H2 = item.H2.Total,
                        Ar = item.Ar.Total,
                        PN2 = item.PN2.Total,
                        HCL = item.HCL.Total,
                        SiH4 = item.SiH4.Total,
                        C2H4 = item.C2H4.Total,
                        TCS = item.TCS.Total,
                        TMA = item.TMA.Total,
                        HeaterPowerConsumption = item.HeaterPowerConsumption.Total
                    }));
                }

                return list;
            }
        }

        #endregion

        #region Methods

        private bool OnTimer()
        {
            Monitor();
            return true;
        }

        private void GasFlowCountCollectionOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            // 列表发生变化时重新排序。
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                var i = 1;
                GasFlowCountCollection.ToList().OrderBy(x => x.StatisticsStart).ToList().ForEach(x =>
                {
                    x.Index = i;
                    i++;
                });
            }
        }
        
        /// <summary>
        /// 将统计值保存到数据库。
        /// </summary>
        /// <param name="runData"></param>
        private void SaveFlowCount(ProcessDataStatPerRun runData)
        {
            try
            {
                var sql = $"INSERT INTO process_data_stat_per_run " +
                          $"(process_guid, module_name, recipe_name, wafer_guid, process_begin_time, process_end_time, h2, ar, pn2, hcl, sih4, c2h4, tcs, tma, heater_power_consumption) " +
                          $"VALUES " +
                          $"('{runData.StatisticsUid:D}', '{Module}', '{runData.RecipeName}', '{runData.WaferId:D}', " +
                          $"'{runData.StatisticsStart:yyyy/MM/dd HH:mm:ss.fff}', '{runData.StatisticsEnd:yyyy/MM/dd HH:mm:ss.fff}', " +
                          $"{runData.H2.Total}, {runData.Ar.Total}, {runData.PN2.Total}, {runData.HCL.Total}, {runData.SiH4.Total}, {runData.C2H4.Total}, {runData.TCS.Total}, {runData.TMA.Total}, {runData.HeaterPowerConsumption.Total})";

                DB.ExecuteNonQuery(sql);
            }
            catch (Exception ex)
            {
                LOG.Error($"Unable to save total gas flow to database, {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 从数据库加载指定的记录。
        /// </summary>
        /// <param name="limit"></param>
        private void ReadLastFlowCounts(int limit = DISPLAYED_ROWS_MAX)
        {
            try
            {
                var sql =
                    $"SELECT * FROM process_data_stat_per_run where module_name = '{Module}' " +
                    $" ORDER BY process_begin_time DESC LIMIT {limit}";
                var dt = DB.ExecuteDataTable(sql);
                if (dt is { Rows.Count: > 0 })
                {
                    for (var i = 0; i < dt.Rows.Count; i++)
                    {
                        try
                        {
                            var row = dt.Rows[i];
                            var uid = Guid.Parse(row["process_guid"].ToString());
                            var recipeName = row["recipe_name"].ToString();
                            var waferUid = row["wafer_guid"].ToString();
                            var beginTime = DateTime.Parse(row["process_begin_time"].ToString());
                            var endTime = DateTime.Parse(row["process_end_time"].ToString());
                            var h2 = double.Parse(row["h2"].ToString());
                            var ar = double.Parse(row["ar"].ToString());
                            var pn2 = double.Parse(row["pn2"].ToString());
                            var hcl = double.Parse(row["hcl"].ToString());
                            var sih4 = double.Parse(row["sih4"].ToString());
                            var cxhx = double.Parse(row["c2h4"].ToString());
                            var tcs = double.Parse(row["tcs"].ToString());
                            var tma = double.Parse(row["tma"].ToString());
                            var heaterPowerConsumption = double.Parse(row["heater_power_consumption"].ToString());
                            var run = new ProcessDataStatPerRun(i + 1, uid, Module, recipeName, waferUid, beginTime, endTime, h2, ar, pn2,
                                hcl, sih4, cxhx, tcs, tma, heaterPowerConsumption);

                            GasFlowCountCollection.Enqueue(run);
                        }
                        catch (Exception ex)
                        {
                            LOG.Error($"Unable to load process data statistic history at row {i}, {ex.Message}", ex);
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                LOG.Error($"Unable to load process data statistic history, {ex.Message}", ex);
            }
        }


        public void Monitor()
        {
            lock (_syncObject)
            {
                if (CurrentDataStat != null && CurrentDataStat.StatisticsEnd.HasValue == false)
                {
#if FAKE_DATA
                    CurrentDataStat.H2.AddFlow(_randomFlow.NextDouble());
                    CurrentDataStat.Ar.AddFlow(_randomFlow.NextDouble());
                    CurrentDataStat.PN2.AddFlow(_randomFlow.NextDouble());
                    CurrentDataStat.HCL.AddFlow(_randomFlow.NextDouble());
                    CurrentDataStat.SiH4.AddFlow(_randomFlow.NextDouble());
                    CurrentDataStat.CxHx.AddFlow(_randomFlow.NextDouble());
                    CurrentDataStat.TCS.AddFlow(_randomFlow.NextDouble());
                    CurrentDataStat.TMA.AddFlow(_randomFlow.NextDouble());
#else

                    CurrentDataStat.Accumulate();

#endif
                }
            }
        }

        /// <summary>
        /// 启动统计。
        /// </summary>
        public void Begin(string recipeName)
        {
            lock (_syncObject)
            {
                CurrentDataStat = new ProcessDataStatPerRun(Module);
                CurrentDataStat.RecipeName = recipeName;
                GasFlowCountCollection.Enqueue(CurrentDataStat);

                // 启动数据采集线程
                _tStatistic.Start();
            }
        }

        /// <summary>
        /// 结束上次统计。
        /// </summary>
        public void End()
        {
            lock (_syncObject)
            {
                _tStatistic.Pause();

                // Process结束
                if (CurrentDataStat != null)
                {
                    CurrentDataStat.StatisticsEnd = DateTime.Now;

                    // 写数据库
                    SaveFlowCount(CurrentDataStat);

                    CurrentDataStat = null;

                }
            }
        }

        #endregion
    }
}
