using CommunityToolkit.Mvvm.Input;
using FLY.Thick.Base.Common;
using FLY.Thick.Base.IService;
using LiveCharts;
using LiveCharts.Wpf;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Media;

namespace FLY.Thick.Base.UI
{
    class PgGridVm : IPgGridVm
    {
        public event PropertyChangedEventHandler PropertyChanged;

        #region IPgGridVm Property
        /// <summary>
        /// 调试速度 单位:脉冲/秒
        /// </summary>
        public UInt32 VJog { get; set; }
        /// <summary>
        /// 调试速度 单位:m/min
        /// </summary>
        public double VJogMm => VJog * Mmpp * Speed1Scale / 1000 * 60;

        /// <summary>
        /// 目标位置 单位:脉冲
        /// </summary>
        public int TargetPos { get; set; }
        /// <summary>
        /// 目标位置 单位:mm
        /// </summary>
        public double TargetMm => TargetPos * Mmpp;
        /// <summary>
        /// AD值模式
        /// </summary>
        public bool IsADMode { get; set; }

        /// <summary>
        /// 最多6条曲线
        /// </summary>
        public ObservableCollection<SeriesInfo> SeriesInfos { get; } = new ObservableCollection<SeriesInfo>();

        #region 曲线
        public Func<double, string> XFormatter { get; private set; }
        public Func<double, string> YFormatter { get; private set; }

        public double XUpper { get; set; } = 1024;
        public double XLower { get; set; } = 0;

        public double YUpper { get; set; } = double.NaN;
        public double YLower { get; set; } = double.NaN;

        public double XMax { get; private set; } = 1024;
        public double XMin { get; private set; } = 0;

        public double YMax { get; private set; } = double.NaN;
        public double YMin { get; private set; } = double.NaN;

        public double SectionValue => MeasureValuePos / PosOfGrid;
        public double SectionWidth => MeasureWidthPos / PosOfGrid;
        public SeriesCollection Series { get; } = new SeriesCollection();
        #endregion

        #region 测量
        /// <summary>
        /// 测量开始位置 单位:脉冲
        /// </summary>
        public int MeasureValuePos { get; set; }
        /// <summary>
        /// 测量开始位置 单位:mm
        /// </summary>
        public double MeasureValueMm => MeasureValuePos * Mmpp;
        /// <summary>
        /// 测量宽度 单位:脉冲
        /// </summary>
        public int MeasureWidthPos { get; set; }
        /// <summary>
        /// 测量宽度 单位:mm
        /// </summary>
        public double MeasureWidthMm => MeasureWidthPos * Mmpp;
        #endregion

        #endregion

        #region IPgGridVm Command
        public RelayCommand RunToCmd { get; private set; }
        public RelayCommand GetFDataCmd { get; private set; }
        public RelayCommand GetBDataCmd { get; private set; }
        public RelayCommand ClearCmd { get; private set; }
        public RelayCommand MeasureCmd { get; private set; }

        public RelayCommand SaveCmd { get; private set; }

        public RelayCommand<SeriesInfo> SelectCmd { get; private set; }
        #endregion

        public int PosOfGrid { get; set; } = 10;
        public double Mmpp { get; set; } = 0.1;
        public double Speed1Scale { get; set; } = 4;
        ITDGageService gageService;
        IFlyADService flyAdService;
        IInitParamService initParam;
        public PgGridVm()
        {
            #region 与数据无关界面参数

            XFormatter = (x) =>
            {
                int index = (int)x;
                int pos = index * PosOfGrid;
                int mm = (int)(pos * Mmpp);
                return $"{pos}\n{mm}mm";
            };
            YFormatter = (y) =>
            {
                if (IsADMode)
                {
                    return $"{y}";
                }
                else
                {
                    return $"{y:F1}";
                }
            };

            for (int i = 0; i < 6; i++)
            {
                SeriesInfo info = new SeriesInfo()
                {
                    Title = $"{i}",
                    Fill = FLY.ControlLibrary.Themes.Styles.GetForeground(i),
                };
                LineSeries lineSeries = new LineSeries
                {
                    StrokeThickness = 2,
                    Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                    PointGeometry = null
                };
                lineSeries.SetBinding(LineSeries.StrokeProperty, "Fill");
                lineSeries.DataContext = info;
                Series.Add(lineSeries);
                info.Series = lineSeries;
                SeriesInfos.Add(info);
            }

            SeriesInfos[0].IsSelected = true;
            UpdateADMode();
            #endregion

            InitCmd();

            this.PropertyChanged += PgGridVm_PropertyChanged;
        }

        public void Init(
            IInitParamService initParam,
            ITDGageService gageService,
            IFlyADService flyADService
            )
        {
            this.initParam = initParam;
            this.gageService = gageService;
            this.flyAdService = flyADService;
            Misc.BindingOperations.SetBinding(this.initParam, nameof(initParam.Encoder1_mmpp), this, nameof(Mmpp));
            Misc.BindingOperations.SetBinding(this.initParam, nameof(initParam.PosOfGrid), this, nameof(PosOfGrid));

            Misc.BindingOperations.SetBinding(this.initParam, nameof(initParam.Speed1Scale), this, nameof(Speed1Scale));

            Misc.BindingOperations.SetBinding(this.initParam, nameof(initParam.VJOG), this, nameof(VJog));


        }
        private void PgGridVm_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(IsADMode))
            {
                UpdateADMode();
                UpdateRange(true);
            }
        }

        void InitCmd()
        {
            RunToCmd = new RelayCommand(() =>
            {
                if (VJog != initParam.VJOG)
                {
                    initParam.VJOG = VJog;
                    initParam.Apply();
                }
                gageService.StartP2(STARTP2_MODE.RUNTO, TargetPos);
            });

            GetFDataCmd = new RelayCommand(() =>
            {
                flyAdService.GetGrid(Misc.DIRECTION.FORWARD, GetGridCB, null);
            });

            GetBDataCmd = new RelayCommand(() =>
            {
                flyAdService.GetGrid(Misc.DIRECTION.BACKWARD, GetGridCB, null);
            });

            ClearCmd = new RelayCommand(() =>
            {
                var series = SeriesInfos.First(s => s.IsSelected);
                series.Clear();
            });

            MeasureCmd = new RelayCommand(() =>
            {
                UpdateMeasure();
            });

            SaveCmd = new RelayCommand(() =>
            {
                Save();
            });
            SelectCmd = new RelayCommand<SeriesInfo>((info) =>
            {
                if (info.IsSelected)
                    return;
                foreach (var i in SeriesInfos)
                    i.IsSelected = (i == info);
            });
        }
        void GetGridCB(object asyncState, object retData)
        {
            GridInfo gridinfo = retData as GridInfo;
            var series = SeriesInfos.First(s => s.IsSelected);
            series.IsBackw = gridinfo.direction == Misc.DIRECTION.BACKWARD;
            series.ADs.Clear();
            series.Thicks.Clear();
            var ads = gridinfo.data.Select(ad =>
            {
                if (Misc.MyBase.ISVALIDATA(ad))
                {
                    return ad;
                }
                else
                {
                    return double.NaN;
                }
            });
            series.ADs.AddRange(ads);
            series.Thicks.AddRange(gridinfo.thick);
            UpdateRange();
        }


        void UpdateADMode()
        {
            if (IsADMode)
            {
                foreach (var info in SeriesInfos)
                    info.Series.SetBinding(LineSeries.ValuesProperty, nameof(SeriesInfo.ADs));
            }
            else
            {
                foreach (var info in SeriesInfos)
                    info.Series.SetBinding(LineSeries.ValuesProperty, nameof(SeriesInfo.Thicks));
            }
        }
        void UpdateMeasure()
        {
            int begin_grid = MeasureValuePos / PosOfGrid;
            int end_grid = (MeasureValuePos + MeasureWidthPos) / PosOfGrid;

            foreach (var info in SeriesInfos)
            {
                if (IsADMode)
                {
                    double sum = 0;
                    int cnt = 0;
                    for (int i = begin_grid; i <= end_grid && i < info.ADs.Count() && i >= 0; i++)
                    {
                        sum += info.ADs[i];
                        cnt++;
                    }
                    if (cnt == 0)
                        info.Avg = double.NaN;
                    else
                        info.Avg = sum / cnt;
                }
                else
                {
                    double sum = 0;
                    int cnt = 0;
                    for (int i = begin_grid; i <= end_grid && i < info.Thicks.Count() && i >= 0; i++)
                    {
                        sum += info.Thicks[i];
                        cnt++;
                    }
                    if (cnt == 0)
                        info.Avg = double.NaN;
                    else
                        info.Avg = sum / cnt;
                }
            }
        }

        void UpdateRange()
        {
            UpdateRange(false);
        }
        void UpdateRange(bool isReset)
        {
            List<double> vlist = new List<double>();
            foreach (var info in SeriesInfos)
            {
                IEnumerable<double> values = (IsADMode) ? info.ADs : info.Thicks;

                if (values.Count() == 0)
                    continue;

                var values2 = values.Where(v => !double.IsNaN(v));
                if (values2.Count() == 0)
                    continue;

                vlist.AddRange(values2);
            }
            if (vlist.Count() == 0)
            {
                //没有任何数据
                return;
            }
            else
            {
                bool isYMaxAuto = (YMax == YUpper) || double.IsNaN(YUpper);
                bool isYMinAuto = (YMin == YLower) || double.IsNaN(YLower);

                if (IsADMode)
                {
                    YMax = 65535;
                    YMin = 0;
                }
                else
                {
                    double max = vlist.Max();
                    double min = vlist.Min();
                    double range = max - min;
                    if (range < 10)
                        range = 10;

                    YMax = Math.Round(max + range / 10);
                    YMin = Math.Round(min - range / 10);

                }

                if (isReset)
                {
                    YUpper = YMax;
                    YLower = YMin;
                }
                else
                {
                    if (isYMaxAuto)
                        YUpper = YMax;
                    if (isYMinAuto)
                        YLower = YMin;
                }
            }
        }

        void Save()
        {
            string strDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

            string filename = $"Grid数据_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "xlsx files (*.xlsx)|*.xlsx";
            sfd.InitialDirectory = strDesktopPath;
            sfd.FileName = filename;
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                PgGridOutput ouput = new PgGridOutput();
                ouput.Init(this);
                ouput.SaveToXlsx(sfd.FileName);
            }

            ////完成
            //FLY.ControlLibrary.Window_Tip.Show("成功", "保存到路径 " + filepath, TimeSpan.FromSeconds(2));
            //return;
        }

    }
}
