using CommunityToolkit.Mvvm.Input;
using LiveCharts.Wpf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace FLY.Thick.Base.UI
{
    /// <summary>
    /// 范围调整器
    /// </summary>
    public class XYRangeSlider : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 拖拉条 最大值
        /// </summary>
        public double SliderMax { get; set; } = 1000;

        /// <summary>
        /// 拖拉条 最小值
        /// </summary>
        public double SliderMin { get; set; } = 0;

        /// <summary>
        /// 拖拉条 当前上值
        /// </summary>
        public double SliderUpperValue { get; set; } = 1000;

        /// <summary>
        /// 拖拉条 当前下值
        /// </summary>
        public double SliderLowerValue { get; set; } = 0;

        /// <summary>
        /// 导出到 chart轴的Max
        /// </summary>
        public double Max { get; private set; } = 1000;

        /// <summary>
        /// 导出到 chart轴的Min
        /// </summary>
        public double Min { get; private set; } = 0;

        /// <summary>
        /// 轴最小范围
        /// </summary>
        public double MinRange { get; set; } = 100;

        #region 
        public XYRangeSlider()
        {

        }
        public void Init()
        {
            SetLowerUpper(SliderMin, SliderMax);
            this.PropertyChanged -= YRangeSliderUpperMaxMin_PropertyChanged;
            this.PropertyChanged += YRangeSliderUpperMaxMin_PropertyChanged;
        }
        void update()
        {
            if (Math.Abs(SliderUpperValue - SliderLowerValue) < MinRange)
            {
                //异常，不能小于100
                int avg = (int)((SliderUpperValue + SliderLowerValue) / 2);
                SliderUpperValue = avg + MinRange / 2;
                SliderLowerValue = avg - MinRange / 2;
            }
            Max = SliderUpperValue;
            Min = SliderLowerValue;
        }
        public void SetLowerUpper(double lower, double upper)
        {
            this.PropertyChanged -= YRangeSliderUpperLowerValue_PropertyChanged;
            SliderLowerValue = lower;
            SliderUpperValue = upper;
            update();
            this.PropertyChanged += YRangeSliderUpperLowerValue_PropertyChanged;
        }

        public void SetFullView()
        {
            SetLowerUpper(SliderMin, SliderMax);
        }

        private void YRangeSliderUpperLowerValue_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(SliderUpperValue))
            {
                update();
            }
            else if (e.PropertyName == nameof(SliderLowerValue))
            {
                update();
            }
        }
        private void YRangeSliderUpperMaxMin_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(SliderMax))
            {
                if (SliderUpperValue > SliderMax)
                {
                    SliderUpperValue = SliderMax;
                }
            }
            if (e.PropertyName == nameof(SliderMin))
            {
                if (SliderLowerValue < SliderMin)
                {
                    SliderLowerValue = SliderMin;
                }
            }
        }
        #endregion

    }

    public class CartesianChartZoomInHelper : INotifyPropertyChanged
    {
        public const int NULL_VALUE = -999999;

        public event PropertyChangedEventHandler PropertyChanged;

        #region 选择范围
        /// <summary>
        /// Y轴调节
        /// </summary>
        public XYRangeSlider YRangeSlider { get; private set; }

        /// <summary>
        /// X轴调节
        /// </summary>
        public XYRangeSlider XRangeSlider { get; private set; }

        /// <summary>
        /// X轴 选择范围 开始点
        /// </summary>
        public int SelectedXBegin { get; set; } = NULL_VALUE;

        /// <summary>
        /// X轴 选择范围 结束点
        /// </summary>
        public int SelectedXEnd { get; set; } = NULL_VALUE;

        /// <summary>
        /// Y轴 选择范围 开始点
        /// </summary>
        public int SelectedYBegin { get; set; } = NULL_VALUE;

        /// <summary>
        /// Y轴 选择范围 结束点
        /// </summary>
        public int SelectedYEnd { get; set; } = NULL_VALUE;
        #endregion

        /// <summary>
        /// 区域放大
        /// </summary>
        public RelayCommand ZoomInCmd { get; private set; }

        /// <summary>
        /// 撤销之前的放大
        /// </summary>
        public RelayCommand ZoomOutCmd { get; private set; }

        public RelayCommand FullscreenCmd { get; private set; }

        /// <summary>
        /// 使能撤销按钮
        /// </summary>
        public bool IsZoomOutEnable { get; private set; }

        public System.Windows.Point pBegin;
        public System.Windows.Point pEnd;

        private bool isDown = false;

        CartesianChart chart;
        /// <summary>
        /// 数据已经绑定了
        /// </summary>
        bool isBinding;

        public CartesianChartZoomInHelper()
        {
            ZoomInCmd = new RelayCommand(ZoomIn);
            ZoomOutCmd = new RelayCommand(ZoomOut);
            FullscreenCmd = new RelayCommand(Fullscreen);
            YRangeSlider = new XYRangeSlider();
            XRangeSlider = new XYRangeSlider();
        }



        public void Init(CartesianChart chart)
        {
            this.chart = chart;

            YRangeSlider.Init();
            XRangeSlider.Init();

            SetBinding();

        }
        public void SetBinding()
        {
            if (isBinding)//已经绑定了
                return;
            isBinding = true;
            if (chart != null)
            {
                chart.MouseMove += UIElement_OnMouseMove;
                chart.MouseDown += UIElement_MouseDown;
                chart.MouseUp += UIElement_MouseUp;
            }
        }
        /// <summary>
        /// 解除绑定
        /// </summary>
        public void DisposeBinding()
        {
            if (!isBinding)//已经解除绑定了
                return;
            isBinding = false;
            if (chart != null)
            {
                chart.MouseMove -= UIElement_OnMouseMove;
                chart.MouseDown -= UIElement_MouseDown;
                chart.MouseUp -= UIElement_MouseUp;
            }
        }
        private void UIElement_OnMouseMove(object sender, MouseEventArgs e)
        {
            if (!isDown)
                return;


            var chart = (LiveCharts.Wpf.CartesianChart)sender;


            //lets get where the mouse is at our chart
            var mouseCoordinate = e.GetPosition(chart);

            //now that we know where the mouse is, lets use
            //ConverToChartValues extension
            //it takes a point in pixes and scales it to our chart current scale/values
            var p = chart.ConvertToChartValues(mouseCoordinate);


            //var series = vm.Series[0];

            //var closetsPoint = series.ClosestPointTo(p.X, AxisOrientation.X);
            //if (closetsPoint == null)
            //    return;

            //pEnd = closetsPoint;
            pEnd = p;
            Select(pBegin, pEnd);

        }
        private void UIElement_MouseDown(object sender, MouseButtonEventArgs e)
        {
            isDown = true;

            var chart = (LiveCharts.Wpf.CartesianChart)sender;


            var mouseCoordinate = e.GetPosition(chart);
            var p = chart.ConvertToChartValues(mouseCoordinate);
            pBegin = p;

            Select(pBegin, pBegin);

        }
        private void UIElement_MouseUp(object sender, MouseButtonEventArgs e)
        {
            isDown = false;

            //var series = vm.Series[0];
            var chart = (LiveCharts.Wpf.CartesianChart)sender;

            //lets get where the mouse is at our chart
            var mouseCoordinate = e.GetPosition(chart);

            //now that we know where the mouse is, lets use
            //ConverToChartValues extension
            //it takes a point in pixes and scales it to our chart current scale/values
            var p = chart.ConvertToChartValues(mouseCoordinate);

            //for X in this case we will only highlight the closest point.
            //lets use the already defined ClosestPointTo extension
            //it will return the closest ChartPoint to a value according to an axis.
            //here we get the closest point to p.X according to the X axis
            //var series = chart.Series[0];
            //var closetsPoint = series.ClosestPointTo(p.X, AxisOrientation.X);
            //if (closetsPoint == null)
            //    return;
            pEnd = p;
            Select(pBegin, pEnd);
        }



        void Select(System.Windows.Point cpBegin, System.Windows.Point cpEnd)
        {
            double xMin = Math.Min(cpBegin.X, cpEnd.X);
            double xMax = Math.Max(cpBegin.X, cpEnd.X);

            double yMin = Math.Min(cpBegin.Y, cpEnd.Y);
            double yMax = Math.Max(cpBegin.Y, cpEnd.Y);

            SelectedXBegin = (int)xMin;
            SelectedXEnd = (int)xMax;

            SelectedYBegin = (int)yMin;
            SelectedYEnd = (int)yMax;
        }

        /// <summary>
        /// 显示全部范围
        /// </summary>
        private void Fullscreen()
        {
            XRangeSlider.SetFullView();
            YRangeSlider.SetFullView();

            rangeMarks.Clear();
            IsZoomOutEnable = false;

            CancelSelected();
        }
        class RangeMark
        {
            public double XMax;
            public double XMin;

            public double YMax;
            public double YMin;
        }
        List<RangeMark> rangeMarks = new List<RangeMark>();
        /// <summary>
        /// 把选择区域放大为 整个显示区域
        /// </summary>
        private void ZoomIn()
        {
            var rm = new RangeMark()
            {
                XMin = XRangeSlider.Min,
                XMax = XRangeSlider.Max,
                YMin = YRangeSlider.Min,
                YMax = YRangeSlider.Max
            };

            bool ret = zoomIn(XRangeSlider, SelectedXBegin, SelectedXEnd);
            bool ret1 = zoomIn(YRangeSlider, SelectedYBegin, SelectedYEnd);
            if (ret || ret1)
            {
                rangeMarks.Add(rm);
                if (rangeMarks.Count() > 10)
                    rangeMarks.RemoveAt(0);
                IsZoomOutEnable = true;
            }
            CancelSelected();
        }
        bool zoomIn(XYRangeSlider rangeSlider, double begin, double end)
        {
            if (begin > rangeSlider.SliderMin
                && begin < rangeSlider.SliderMax
                || (end - begin) > rangeSlider.MinRange)
            {
                rangeSlider.SetLowerUpper(begin, end);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 显示区域 缩小为 选择区域
        /// </summary>
        private void ZoomOut()
        {
            if (rangeMarks.Count() > 0)
            {
                var rm = rangeMarks.Last();
                zoomIn(XRangeSlider, rm.XMin, rm.XMax);
                zoomIn(YRangeSlider, rm.YMin, rm.YMax);
                rangeMarks.RemoveAt(rangeMarks.Count() - 1);
                IsZoomOutEnable = rangeMarks.Count() > 0;
            }

            CancelSelected();
        }

        public void CancelSelected()
        {
            SelectedXBegin = NULL_VALUE;
            SelectedXEnd = NULL_VALUE;
            SelectedYBegin = NULL_VALUE;
            SelectedYEnd = NULL_VALUE;
        }
        public int SelectedXWidth => SelectedXEnd - SelectedXBegin;
        public int SelectedYWidth => SelectedYEnd - SelectedYBegin;

        public bool IsXAxisSelected()
        {
            if (SelectedXBegin > XRangeSlider.SliderMin
                && SelectedXBegin < XRangeSlider.SliderMax)
            {
                return true;
            }
            return false;
        }

        public bool IsYAxisSelected()
        {
            if (SelectedYBegin > YRangeSlider.SliderMin
                && SelectedYBegin < YRangeSlider.SliderMax)
            {
                return true;
            }
            return false;
        }
    }
}
