using MECF.Framework.Common.DataCenter;
using MECF.Framework.UI.Client.ClientBase;
using SciChart.Charting.Common.Helpers;
using SciChart.Charting.ViewportManagers;
using SciChart.Charting.Visuals.Annotations;
using SciChart.Charting.Visuals.Axes;
using SciChart.Charting.Visuals.RenderableSeries;
using SciChart.Data.Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows;
using Cali = Caliburn.Micro;
using MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory;
using System.Reflection;
using SciChart.Charting.Model.ChartSeries;
using System.IO;
using Aitex.Core.Util;
using Aitex.Core.RT.Log;

namespace SicUI.Models.PMs.Charting
{
    public class PMChartingV2ViewModel : SicModuleUIViewModelBase, ISupportMultipleSystem
    {
        private class QueryIndexer
        {
            public DateTime StartTime { get; set; }
            public DateTime EndTime { get; set; }
            public string Module { get; set; }
            public string ColumneName { get; set; }
            public string ProcessGuid { get; set; }
            public List<string> DateList { get; set; }
            public long currentTimeTicks { get; set; }
        }

        /// <summary>
        /// ViewModel绑定的View对象
        /// </summary>
        private PMChartingV2View view;

        /// <summary>
        /// 初始化界面
        /// </summary>
        public PMChartingV2ViewModel()
        {
            DisplayName = "Process History";

            var now = DateTime.Now;
            this.StartDateTime = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0, 0);
            this.EndDateTime = new DateTime(now.Year, now.Month, now.Day, 23, 59, 59, 999);

            SourcePM = new ObservableCollection<string>(new[] { "PM1", "PM2" });

            //sci按钮操作
            DataDetailVisbleCommand = new ActionCommand(SetDataDetailVisble);
            DefaultZoomCommand = new ActionCommand(Zoom);
            ShowLegendCommand = new ActionCommand(SetLegendAvalible);

            //获取所有Device
            GetPMNode();

            SelectedData = new ObservableCollection<IRenderableSeriesViewModel>();

            SelectedRecipes = new ObservableCollection<RecipeItemSic>();
            Recipes = new ObservableCollection<RecipeItemSic>();

            //x y always指zoom功能失效，总是自动调整大小
            //ChartAutoRange = AutoRange.Always; 

            VisibleRangeX = new DoubleRange(-1000, 10000);
            VisibleRangeY = new DoubleRange(-10, 500);
            VisibleRangeXLimit = new DoubleRange(-1000, 10000);
            VisibleRangeYLimit = new DoubleRange(-10, 500);

            _thread = new PeriodicJob(300, MonitorHistoryData, "History", true);
            //_threadReal = new PeriodicJob(TrendInterval, MonitorRealTimeData, "RealTime", true);
        }

        protected override void OnViewLoaded(object _view)
        {
            //获取绑定的View（wpf没有默认的日期时间控件，Winform日期控件无法通过绑定属性获取）
            base.OnViewLoaded(_view);
            this.view = (PMChartingV2View)_view;
            this.view.wfTimeFrom.Value = this.StartDateTime;
            this.view.wfTimeTo.Value = this.EndDateTime;

        }

        private PeriodicJob _thread;
        //private PeriodicJob _threadReal;
        //DeviceTimer dt = new DeviceTimer();
        
        //设置允许同时显示的最多曲线数
        private const int MAX_PARAMETERS = 20;

        /// <summary>
        /// sci图表的视图管理类
        /// </summary>
        private readonly IViewportManager _viewportManager = new DefaultViewportManager();
        public IViewportManager ViewportManager
        {
            get { return _viewportManager; }
        }

        #region Properties 

        /// <summary>
        /// 搜索条件:Recipe开始时间
        /// </summary>
        public DateTime StartDateTime { get; set; }

        /// <summary>
        /// 搜索条件:Recipe结束时间
        /// </summary>
        public DateTime EndDateTime { get; set; }

        /// <summary>
        /// 搜索条件:PM腔
        /// </summary>
        public string SelectedValuePM { get; set; }

        /// <summary>
        /// 搜索条件:PM腔
        /// </summary>
        public ObservableCollection<string> SourcePM { get; set; }
        /// <summary>
        /// 搜索条件:Recipe
        /// </summary>
        public string RecipeName { get; set; }

        /// <summary>
        /// 查询曲线用点位组，每次有曲线变动时入队，生成曲线后出队
        /// </summary>
        ConcurrentBag<QueryIndexer> _lstTokenTimeData = new ConcurrentBag<QueryIndexer>();

        public ObservableCollection<DataDetail> QueryDataDetail { get; set; }

        /// <summary>
        /// 用户选中的曲线组，前台treeview和chart调用
        /// </summary>
        public ObservableCollection<IRenderableSeriesViewModel> SelectedData { get; set; }

        /// <summary>
        /// 根据条件搜索的recipe
        /// </summary>
        public ObservableCollection<RecipeItemSic> Recipes { get; set; }

        /// <summary>
        /// 用户选中查阅的recipe
        /// </summary>
        public ObservableCollection<RecipeItemSic> SelectedRecipes { get; set; }


        private List<PMNodeInfo> Nodes = new List<PMNodeInfo>();
        /// <summary>
        /// 获取设备需要监控的Device点
        /// </summary>
        private ObservableCollection<PMNodeInfo> _configNodes = new ObservableCollection<PMNodeInfo>();
        public ObservableCollection<PMNodeInfo> ConfigNodes
        {
            get { return _configNodes; }
            set { _configNodes = value; NotifyOfPropertyChange("ConfigNodes"); }
        }

        private double _maxYValue = 0, _minYValue = 0;

        private IRange _visibleRangeXLimit;
        public IRange VisibleRangeXLimit
        {
            get { return _visibleRangeXLimit;}
            set { _visibleRangeXLimit = value; NotifyOfPropertyChange(nameof(VisibleRangeXLimit)); }
        }

        private IRange _visibleRangeYLimit;
        public IRange VisibleRangeYLimit
        {
            get { return _visibleRangeYLimit; }
            set { _visibleRangeYLimit = value; NotifyOfPropertyChange(nameof(VisibleRangeYLimit)); }
        }

        private IRange _visibleRangeX;
        public IRange VisibleRangeX
        {
            get { return _visibleRangeX; }
            set { _visibleRangeX = value; NotifyOfPropertyChange(nameof(VisibleRangeX)); }
        }
        private IRange _visibleRangeY;
        public IRange VisibleRangeY
        {
            get { return _visibleRangeY; }
            set { _visibleRangeY = value; NotifyOfPropertyChange(nameof(VisibleRangeY)); }
        }

        private AutoRange _chartAutoRange = AutoRange.Never;
        public AutoRange ChartAutoRange
        {
            get { return _chartAutoRange; }
            set
            {
                _chartAutoRange = value;
                NotifyOfPropertyChange(nameof(ChartAutoRange));
            }
        }

        private Visibility _dataDetailVisbility = Visibility.Collapsed;
        public Visibility DataDetailVisbility
        {
            get { return _dataDetailVisbility; }
            set
            {
                _dataDetailVisbility = value;
                NotifyOfPropertyChange(nameof(DataDetailVisbility));
            }
        }

        private bool _showLegendInfo;
        public bool ShowLegendInfo
        {
            get { return _showLegendInfo; }
            set
            {
                _showLegendInfo = value;
                NotifyOfPropertyChange(nameof(ShowLegendInfo));
            }
        }

        private Queue<Color> colorQueue = new Queue<Color>(new Color[]{Color.Red,Color.Orange,Color.Green,Color.Blue,Color.Purple,Color.Aqua,Color.Bisque,Color.Brown,Color.BurlyWood,Color.CadetBlue,
            Color.CornflowerBlue,Color.DarkBlue,Color.DarkCyan,Color.DarkGray,Color.DarkGreen,Color.DarkKhaki,Color.DarkMagenta,Color.DarkOliveGreen, Color.DarkOrange,
            Color.DarkSeaGreen,Color.DarkSlateBlue,Color.DarkSlateGray,Color.DarkViolet,Color.DeepPink,Color.DeepSkyBlue,Color.DimGray, Color.DodgerBlue,Color.ForestGreen, Color.Gold,
            Color.Gray,Color.GreenYellow,Color.HotPink,Color.Indigo,Color.Khaki,
            Color.LimeGreen,Color.MediumOrchid,Color.MediumPurple,Color.MediumSeaGreen,Color.MediumSlateBlue,Color.MediumSpringGreen,
            Color.MediumTurquoise,Color.Moccasin,Color.NavajoWhite,Color.Olive,Color.OliveDrab,Color.OrangeRed,Color.Orchid,Color.PaleGoldenrod,Color.PaleGreen,
            Color.PeachPuff,Color.Peru,Color.Plum,Color.PowderBlue,Color.RosyBrown,Color.RoyalBlue,Color.SaddleBrown,Color.Salmon,Color.SeaGreen, Color.Sienna,
            Color.SkyBlue,Color.SlateBlue,Color.SlateGray,Color.SpringGreen,Color.Teal,Color.Aquamarine,Color.Tomato,Color.Turquoise,Color.Violet,Color.Wheat, Color.YellowGreen});
        
        #endregion Properties


        #region 界面按钮

        
        /// <summary>
        /// 重新搜索Recipe
        /// </summary>
        public void SearchRecipe()
        {
            this.StartDateTime = this.view.wfTimeFrom.Value;
            this.EndDateTime = this.view.wfTimeTo.Value;

            if (StartDateTime > EndDateTime)
            {
                MessageBox.Show("Time range invalid, start time should be early than end time");
                return;
            }

            Recipes.Clear();
            RemoveAllLine();

            try
            {
                string sql = $"SELECT * FROM \"process_data\" where \"process_data\".\"process_begin_time\" >='{StartDateTime:yyyyMMdd HHmmss}' and  \"process_data\".\"process_end_time\" <='{EndDateTime:yyyyMMdd HHmmss}'";
                if (!string.IsNullOrEmpty(SelectedValuePM))
                {
                    string[] pms = SelectedValuePM.Split(',');
                    if (pms.Length > 0)
                    {
                        sql += " and (FALSE ";
                        foreach (var pm in pms)
                        {
                            sql += $" OR  \"process_data\".\"process_in\"='{pm}' ";
                        }
                        sql += " ) ";
                    }
                }

                if (!string.IsNullOrEmpty(RecipeName))
                {
                    sql += string.Format(" and lower( \"process_data\".\"recipe_name\") like '%{0}%'", RecipeName.ToLower());
                }

                sql += " order by \"process_data\".\"process_begin_time\" ASC;";

                DataTable dbData = QueryDataClient.Instance.Service.QueryData(sql);

                Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                {
                    if (dbData == null || dbData.Rows.Count == 0)
                        return;

                    double maxXValue = 0;

                    for (int i = 0; i < dbData.Rows.Count; i++)
                    {
                        RecipeItemSic item = new RecipeItemSic();

                        item.Recipe = dbData.Rows[i]["recipe_name"].ToString();
                        item.Chamber = dbData.Rows[i]["process_in"].ToString();
                        item.Status = dbData.Rows[i]["process_status"].ToString();
                        //item.ProcessGuid = dbData.Rows[i]["guid"].ToString();
                        item.ProcessGuid = "Recipe"+i.ToString().PadLeft(3,'0');

                        if (!dbData.Rows[i]["process_begin_time"].Equals(DBNull.Value))
                            item.StartTime = ((DateTime)dbData.Rows[i]["process_begin_time"]).ToString("yyyy/MM/dd HH:mm:ss.fff");
                        if (!dbData.Rows[i]["process_end_time"].Equals(DBNull.Value))
                            item.EndTime = ((DateTime)dbData.Rows[i]["process_end_time"]).ToString("yyyy/MM/dd HH:mm:ss.fff");

                        long curTickCount = (DateTime.Parse(item.EndTime).Ticks - DateTime.Parse(item.StartTime).Ticks) / 10000000;
                        if (maxXValue < curTickCount)
                        {
                            maxXValue = curTickCount;
                        }
                        //正确设置范围，否则曲线不显示
                        VisibleRangeX = new DoubleRange(-0.2*maxXValue, maxXValue * 1.2);
                        VisibleRangeXLimit = new DoubleRange(-0.2 * maxXValue, maxXValue * 1.2);//X轴拉伸1.2倍

                        Recipes.Add(item);
                    }
                }));
            }
            catch (Exception e)
            {
                LOG.Write(e);
            }
        }

        /// <summary>
        /// 选择Recipe
        /// </summary>
        public void CheckRecipe(RecipeItemSic recipe)
        {
            if (recipe.Selected)   //选中配方
            {
                SelectedRecipes.Add(recipe);
                //刷新曲线
                //GetXRange();
                foreach (PMNodeInfo node in ConfigNodes)
                {
                    if (node.Selected)
                    {
                        ParameterCheck(node);
                    }
                }
            }
            else        //取消配方
            {
                RecipeItemSic item = SelectedRecipes.FirstOrDefault(t => t.Recipe == recipe.Recipe);
                if (item != null)
                    SelectedRecipes.Remove(item);
                RemoveRecipeRelated(recipe);    //移除配方相关曲线
            }
            
  
        }

        /// <summary>
        /// 移除配方相关曲线
        /// </summary>
        /// <param name="recipe"></param>
        private void RemoveRecipeRelated(RecipeItemSic recipe)
        {
            lock (_lockSelection)   //递减法移除列表内项，不会删错
            {
                for (int i = SelectedData.Count - 1; i >= 0; i--)
                {
                    if ((SelectedData[i] as ChartDataLineXV2).ProcessGuid.Contains(recipe.ProcessGuid))
                    {
                        SelectedData.RemoveAt(i);
                    }
                }
            }
        }

        /// <summary>
        /// 清除所有选择的节点
        /// </summary>
        public void RemoveAllLine()
        {
            this.SelectedData.Clear();
            foreach (PMNodeInfo node in ConfigNodes)
            {
                node.Selected = false;
            }
        }

        #endregion 界面按钮

        private void SelectedDataChanged()
        {
            foreach (var item in SelectedData)
            {
                if (item.Stroke.Equals(System.Windows.Media.Color.FromArgb(255, 0, 0, 255)))
                {
                    Color drawingColor = colorQueue.Peek();
                    item.Stroke = System.Windows.Media.Color.FromRgb(drawingColor.R, drawingColor.G, drawingColor.B);
                    colorQueue.Enqueue(colorQueue.Dequeue());
                }
            }
        }

        /// <summary>
        /// 加载PM的Device名称
        /// </summary>
        private void GetPMNode()
        {
            Nodes.Clear();
            ConfigNodes.Clear();
            List<string> dataList = (List<string>)QueryDataClient.Instance.Service.GetConfig("System.NumericDataList");
            dataList.Sort();
            List<string> lstNode = new List<string>();
            foreach (string dataName in dataList)
            {
                string[] nodeName = dataName.Split('.');
                if (nodeName.Length > 1 && nodeName[0].IndexOf("PM") == 0)
                {
                    string nodeStr = dataName.Substring(dataName.IndexOf('.') + 1);
                    if (!lstNode.Contains(nodeStr)) //不显示重复项
                    {
                        lstNode.Add(nodeStr);
                        Nodes.Add(new PMNodeInfo() { NodeStr = nodeStr });
                        ConfigNodes.Add(new PMNodeInfo() { NodeStr = nodeStr });
                    }
                }
            }
        }

        public void Find(string keyword)
        {
            ConfigNodes.Clear();
            //遍历所有node,隐藏不符合条件项
            foreach (var node in Nodes)
            {
                node.ApplyCriteria(keyword);
                if (node.IsMatch)
                {
                    ConfigNodes.Add(node);
                }
            }
        }
        private void SetDataDetailVisble()
        {
            if (DataDetailVisbility == Visibility.Collapsed)
            {
                DataDetailVisbility = Visibility.Visible;
            }
            else
            {
                DataDetailVisbility = Visibility.Collapsed;
            }
        }

        #region 获取HistoryData

        private object _lockSelection = new object();

        protected bool MonitorHistoryData()
        {
            try
            {
                if (_lstTokenTimeData.Count > 0)
                {
                    lock (_lockSelection)
                    {
                        foreach (var item in _lstTokenTimeData)
                        {
                            DateTime timeFrom = item.StartTime;
                            DateTime timeTo = item.EndTime;

                            GetHistoryData(item.DateList, timeFrom, timeTo, item.Module, item.ColumneName, item.ProcessGuid);
                            _lstTokenTimeData.TryTake(out _);
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                LOG.Error(ex.Message);
            }
            return true;
        }

        private void GetHistoryData(List<string> lstDayStr, DateTime from, DateTime to, string module, string colName, string processGuid)
        {
            Dictionary<string, List<DataDetail>> historyData = new Dictionary<string, List<DataDetail>>();
            List<DataDetail> lstDataDetail = new List<DataDetail>();

            //db获取对应字段数据
            foreach (string cDate in lstDayStr)
            {
                string sql = String.Format("select time AS InternalTimeStamp,\"{0}\"", colName);
                sql += string.Format(" from \"{0}\" where time > {1} and time <= {2} order by time asc",
                    cDate + "." + module, from.Ticks, to.Ticks);

                DataTable dataTable = QueryDataClient.Instance.Service.QueryData(sql);
                if (dataTable == null || dataTable.Rows.Count == 0 || dataTable.Columns.Count < 2)
                {
                    return;
                }

                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    DataDetail data = new DataDetail();
                    long ticks = (long)dataTable.Rows[i][0] - from.Ticks;
                    data.xValue = ticks / 10000000;
                    if (dataTable.Rows[i][1] is DBNull || dataTable.Rows[i][1] is null)
                    {
                        data.yValue = 0;
                    }
                    else if (dataTable.Rows[i][1] is bool)
                    {
                        data.yValue = (bool)dataTable.Rows[i][1] ? 1 : 0;
                    }
                    else
                    {
                        data.yValue = float.Parse(dataTable.Rows[i][1].ToString());
                    }
                    if (data.yValue > _maxYValue)
                    {
                        _maxYValue = data.yValue;
                    }
                    if (data.yValue < _minYValue)
                    {
                        _minYValue = data.yValue;
                    }
                    lstDataDetail.Add(data);
                }
            }
            //正确设置范围，否则曲线不显示
            VisibleRangeY = new DoubleRange(_minYValue - _maxYValue * 0.5, _maxYValue * 2.1);
            VisibleRangeYLimit = new DoubleRange(_minYValue - _maxYValue * 0.5, _maxYValue * 2.1);//Y轴拉伸1.2倍

            //所有数据内存
            historyData.Add(processGuid, lstDataDetail);

            //数据绑定到曲线中
            Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                try
                {
                    foreach (var item in SelectedData)
                    {
                        var seriesItem = item as ChartDataLineXV2;

                        if (seriesItem == null)
                            continue;
                        foreach (var data in historyData)
                        {
                            if (data.Key != seriesItem.ProcessGuid)
                                continue;

                            seriesItem.Capacity += data.Value.Count;

                            foreach (var detailDataItem in data.Value)
                            {
                                seriesItem.Append(detailDataItem.xValue, detailDataItem.yValue);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    LOG.Write(ex);
                }
            }));
        }
        #endregion

        
        /// <summary>
        /// 更新Data变化
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public bool ParameterCheck(PMNodeInfo node)
        {
            if (SelectedRecipes.Count == 0)
            {
                return false;
            }

            if (node.Selected)
            {
                foreach (RecipeItemSic itemSic in SelectedRecipes)
                {
                    string nodeStr = itemSic.Chamber + "." + node.NodeStr;                          //字段名称
                    string nodeStr_1 = itemSic.LotID;                                               //显示名称
                    string nodeWithGuid = node.NodeStr + "_" + itemSic.ProcessGuid;                 //字段名+ Guid (唯一ID)
                    DateTime dtStartTime = DateTime.Parse(itemSic.StartTime);
                    DateTime dtEndTime = DateTime.Parse(itemSic.EndTime);

                    lock (_lockSelection)
                    {
                        bool isExist = SelectedData.FirstOrDefault(x => (x as ChartDataLineXV2).ProcessGuid == nodeWithGuid) != null;
                        if (!isExist)
                        {
                            if (SelectedData.Count < MAX_PARAMETERS)
                            {
                                var line = new ChartDataLineXV2(nodeWithGuid); 
                                line.Time=itemSic.StartTime+"-"+itemSic.EndTime;
                                line.RecipeName = new DirectoryInfo(itemSic.Recipe).Name;
                                if (itemSic.Chamber.StartsWith("PM1"))
                                    line.Module = "PM1";
                                else if (itemSic.Chamber.StartsWith("PM2"))
                                    line.Module = "PM2";
                                else
                                    line.Module = "System";
                                line.ProcessGuid = nodeWithGuid;
                                line.RecName = nodeStr_1;
                                line.Tag = node;
                                SelectedData.Add(line);
                                SelectedDataChanged();
                                QueryIndexer indexer = _lstTokenTimeData.FirstOrDefault(x => x.ProcessGuid == line.ProcessGuid);

                                if (indexer == null)
                                {
                                    indexer = new QueryIndexer()
                                    {
                                        Module = line.Module,
                                        StartTime = dtStartTime,
                                        EndTime = dtEndTime,
                                        ProcessGuid = line.ProcessGuid,
                                        ColumneName = nodeStr,
                                        DateList = GetDateList(dtStartTime, dtEndTime)
                                    };

                                    _lstTokenTimeData.Add(indexer);
                                }
                            }
                            else
                            {
                                return false;
                            }
                        }
                    }
                }
            }
            else
            {
                lock (_lockSelection)
                {
                    for (int i = SelectedData.Count - 1; i >= 0; i--)
                    {
                        if ((SelectedData[i] as ChartDataLineXV2).DataName.Contains(node.NodeStr))
                        {
                            SelectedData.RemoveAt(i);
                        }
                    }
                }
            }
            return true;
        }

        public void SelectColor(ChartDataLineXV2 cp)
        {
            if (cp == null)
                return;

            var dlg = new System.Windows.Forms.ColorDialog();
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                cp.Stroke = new System.Windows.Media.Color() { A = dlg.Color.A, B = dlg.Color.B, G = dlg.Color.G, R = dlg.Color.R };
            }
        }

        /// <summary>
        /// 获取开始时间和结束时间之间的所有日期
        /// </summary>
        /// <param name="timeStart"></param>
        /// <param name="timeEnd"></param>
        /// <returns></returns>
        private List<string> GetDateList(DateTime timeStart, DateTime timeEnd)
        {
            List<string> lstTime = new List<string>();
            string dtEndStr = timeEnd.ToString("yyyyMMdd");
            int timeSpan = (int)(timeEnd - timeStart).TotalDays + 1;
            for (int i = 0; i <= timeSpan; i++)
            {
                string dt = timeStart.AddDays(i).ToString("yyyyMMdd");
                lstTime.Add(dt);
                if (dt == dtEndStr)
                {
                    break;
                }
            }

            return lstTime;
        }

        /// <summary>
        /// 获取所有的列名
        /// </summary>
        private List<string> GetColumnList(string modleName)
        {
            List<string> _seletedItemName = new List<string>();
            foreach (PMNodeInfo node in ConfigNodes)
            {
                if (node.Selected)
                {
                    _seletedItemName.Add("\"" + modleName + "." + node.NodeStr + "\"");
                }
            }
            return _seletedItemName;
        }

        public ActionCommand DefaultZoomCommand { get; private set; }
        public ActionCommand ShowLegendCommand { get; private set; }
        public ActionCommand DataDetailVisbleCommand { get; private set; }
        public ActionCommand ShowAlarmCommand { get; private set; }


        private void SetLegendAvalible()
        {
            ShowLegendInfo = !ShowLegendInfo;
        }

        private void Zoom()
        {
            ViewportManager.AnimateZoomExtents(TimeSpan.FromMilliseconds(500));
        }

    }
}
