using CommunityToolkit.Mvvm.Input;
using FLY.Thick.Base.IService;
using LiveCharts;
using LiveCharts.Configurations;
using LiveCharts.Wpf;
using Misc;
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Media;

namespace FLY.Thick.Base.UI
{
    public class PgScanCorrVmUt : INotifyPropertyChanged
    {

        #region 轴调节
        /// <summary>
        /// Y轴拖拉条 最大值
        /// </summary>
        public double YRangeSliderMax { get; set; } = 65535;

        /// <summary>
        /// Y轴拖拉条 最小值
        /// </summary>
        public double YRangeSliderMin { get; set; } = 0;
        #endregion


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

        public double XMin => 0;
        public double XMax => PosLength / PosOfGrid;


        /// <summary>
        /// Y轴 最大值
        /// </summary>
        public double YMax { get; set; } = 65535;

        /// <summary>
        /// Y轴 最小值
        /// </summary>
        public double YMin { get; set; }


        public SeriesCollection Series { get; } = new SeriesCollection();

        public class SeriesInfo : INotifyPropertyChanged
        {
            public string Name { get; set; }
            public Brush Color { get; set; }

            public ChartValues<double> Datas = new ChartValues<double>();

            public event PropertyChangedEventHandler PropertyChanged;
        }
        public SeriesInfo[] SeriesInfos { get; set; }

        CartesianMapper<XY> Mapper { get; set; }

        #endregion

        /// <summary>
        /// 机架总长，脉冲
        /// </summary>
        public int PosLength { get; set; } = 8000;

        /// <summary>
        /// 1个grid = N个pos
        /// </summary>
        public int PosOfGrid { get; set; } = 10;

        /// <summary>
        /// 比例
        /// </summary>
        public double Mmpp { get; set; } = 0.1;




        #region

        /// <summary>
        /// 使能修正
        /// </summary>
        public bool Enable { set; get; }

        /// <summary>
        /// 当前修正的组
        /// </summary>
        public int CurrGroupIndex { get; set; }

        /// <summary>
        /// 当前进度 0 - 100 
        /// </summary>
        public int Progress { get; set; }

        /// <summary>
        /// 数据更新时间
        /// </summary>
        public DateTime[] UpdateTimes { get; set; }

        /// <summary>
        /// 正在机架修正中
        /// </summary>
        public bool IsRunning { get; set; }

        /// <summary>
        /// 来回次数
        /// </summary>
        public int ScanCnt { get; set; }


        #endregion

        /// <summary>
        /// 当前被选择的组序号
        /// </summary>
        public int SelectedGroupIndex { get; set; }


        #region 平滑方式生成修正曲线

        /// <summary>
        /// 平均滤波平滑数,单位grid
        /// </summary>
        public int SmoothFactor { get; set; } = 20;
        #endregion

        #region 关键点方式生成修正曲线


        public KeyPointsSelectMode KpSelectMode { get; set; } = KeyPointsSelectMode.Null;

        #endregion

        /// <summary>
        /// 数据好了！！！！
        /// 当 flyad7 的poslen, posOfGrid 发生变化时，DataOK = false, 需要重新记录。
        /// </summary>
        public bool IsDataOK { get; set; } = false;

        public int AvgAd { get; set; }

        public RelayCommand SelectedGroup0Cmd { get; }
        public RelayCommand SelectedGroup1Cmd { get; }

        public RelayCommand StopCmd { get; }
        public RelayCommand StartCmd { get; }

        public RelayCommand ClearCmd { get; }

        public RelayCommand CreateCorrBySmoothCmd { get; }
        public RelayCommand CreateCorrByKeyPointCmd { get; }
        /// <summary>
        /// 添加关键点模式
        /// </summary>
        public RelayCommand AddKeyPointModeCmd { get; }
        public RelayCommand RemoveKeyPointModeCmd { get; }
        public RelayCommand MoveKeyPointModeCmd { get; }
        public RelayCommand CancelKeyPointModeCmd { get; }
        public RelayCommand SetCorrDataCmd { get; }


        public PgScanCorrVmUt()
        {
            #region 与数据无关界面参数

            XFormatter = (x) =>
            {
                //x 是 grid
                int pos = (int)(x * PosOfGrid);
                int mm = (int)(pos * Mmpp);
                return $"{pos}\n{mm}mm";
            };
            YFormatter = (y) =>
            {
                return $"{y:F0}";
            };
            //Mapper = Mappers.Xy<XY>()
            //    .X((value, index) => value.X)
            //    .Y(value => value.Y);

            SeriesInfos = new SeriesInfo[] {
                new SeriesInfo(){Name = "正向原始", Color = FLY.ControlLibrary.Themes.Styles.GetForeground(0)},
                new SeriesInfo(){Name = "反向原始", Color = FLY.ControlLibrary.Themes.Styles.GetForeground(1)},
                new SeriesInfo(){Name = "正向滤波", Color = FLY.ControlLibrary.Themes.Styles.GetForeground(0, true)},
                new SeriesInfo(){Name = "反向滤波", Color = FLY.ControlLibrary.Themes.Styles.GetForeground(1, true)},
            };

            for (int i = 0; i < SeriesInfos.Count(); i++)
            {
                var seriesInfo = SeriesInfos[i];
                var lineSeries = new LineSeries
                {
                    Values = seriesInfo.Datas,
                    StrokeThickness = 2,
                    Fill = new SolidColorBrush(System.Windows.Media.Colors.Transparent),
                    Stroke = seriesInfo.Color,
                    PointGeometry = null,
                    Configuration = Mapper
                };
                Series.Add(lineSeries);
            }

            #endregion

            PosLength = 24000;
            PosOfGrid = 24;
            Mmpp = 0.1135;
            int gridLen = PosLength / PosOfGrid;
            Random random = new Random();
            int[] orgDatas0 = new int[gridLen];
            int[] orgDatas1 = new int[gridLen];
            int avgAd = 50300;
            int tolerance = 500;
            for (int i = 0; i < gridLen; i++)
            {
                int ad = (int)(Math.Sin(1.0 * i / (gridLen / 3) * Math.PI) * tolerance) + avgAd;
                orgDatas0[i] = ad + (random.Next(10) - 5);
                orgDatas1[i] = ad + (random.Next(10) - 5);
            }

            int[] corrDatas0 = Smooth(orgDatas0);
            int[] corrDatas1 = Smooth(orgDatas1);
            int avg = avgAd;

            GetScanCorrGroupResponse response = new GetScanCorrGroupResponse();
            response.Avg = avg;
            response.OrgDatas = new int[][] { orgDatas0, orgDatas1 };
            response.CorrDatas = new int[][] { corrDatas0, corrDatas1 };

            UpdateTimes = new DateTime[2];
            scanCorrService_GetScanCorrGroup(0, response);

        }
        int[] Smooth(int[] orgDatas, int smoothFactor = 50)
        {

            var filters = new int[orgDatas.Count()];
            for (int i = 0; i < orgDatas.Count(); i++)
            {
                int sum = 0;
                int cnt = 0;
                for (int j = 0; j < smoothFactor; j++)
                {
                    int index = i - smoothFactor / 2;
                    if (index < 0)
                        continue;
                    else if (index >= orgDatas.Count())
                        break;

                    if (Misc.MyBase.ISVALIDATA(orgDatas[index]))
                    {
                        sum += orgDatas[index];
                        cnt++;
                    }
                }
                if (cnt > 0)
                    filters[i] = sum / cnt;
                else
                    filters[i] = Misc.MyBase.NULL_VALUE;
            }
            return filters;
        }

        void scanCorrService_GetScanCorrGroup(object asyncContext, object retData)
        {

            var reponse = retData as GetScanCorrGroupResponse;
            int groupIndex = reponse.GroupIndex;
            UpdateTimes[groupIndex] = reponse.UpdateTime;
            AvgAd = reponse.Avg;
            IsDataOK = reponse.IsDataOK;

            SeriesInfos[0].Datas.Clear();
            SeriesInfos[1].Datas.Clear();
            SeriesInfos[2].Datas.Clear();
            SeriesInfos[3].Datas.Clear();

            if (reponse.OrgDatas == null || reponse.OrgDatas.Count() != 2)
                return;

            SeriesInfos[0].Datas.AddRange(reponse.OrgDatas[0].Select(ad => Misc.MyBase.ISVALIDATA(ad) ? ad : double.NaN));
            SeriesInfos[1].Datas.AddRange(reponse.OrgDatas[1].Select(ad => Misc.MyBase.ISVALIDATA(ad) ? ad : double.NaN));

            int max = (int)SeriesInfos[0].Datas.Max();
            int min = (int)SeriesInfos[0].Datas.Min();
            //设置Y轴范围
            YMax = max;
            YMin = min;

            if (reponse.CorrDatas == null || reponse.CorrDatas.Count() != 2)
                return;

            SeriesInfos[2].Datas.AddRange(reponse.CorrDatas[0].Select(ad => Misc.MyBase.ISVALIDATA(ad) ? ad : double.NaN));
            SeriesInfos[3].Datas.AddRange(reponse.CorrDatas[1].Select(ad => Misc.MyBase.ISVALIDATA(ad) ? ad : double.NaN));

        }




        #region INotifyPropertyChanged 成员

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

    }
}
