using System;
using System.Collections;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using MECF.Framework.Common.Account;
using MECF.Framework.Common.Account.Permissions;
using MECF.Framework.UI.Client.ClientBase;
using MECF.Framework.UI.Client.DataGridTransform.DataGrid.Microsoft.Windows.Controls.Primitives;
using MECF.Framework.UI.Client.RecipeEditorLib.DGExtension.CustomColumn;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
using EGC = ExtendedGrid.Microsoft.Windows.Controls;
using Point = System.Windows.Point;
using Size = System.Windows.Size;

namespace MECF.Framework.UI.Client.RecipeEditorLib.DGExtension
{
    public sealed class XDataGrid : ExtendedGrid.Microsoft.Windows.Controls.DataGrid
    {
        #region Variables

        public ScrollViewer ref_scrollviewer;

        #endregion

        #region Constructors

        public XDataGrid()
        {
            SelectionChanged += OnSelectionChanged;
        }

        #endregion

        #region Properties

        public static readonly DependencyProperty SelectedItemsListProperty = DependencyProperty.Register(
            nameof(SelectedItemsList), typeof(IList), typeof(XDataGrid), new PropertyMetadata(default(IList)));

        public IList SelectedItemsList
        {
            get => (IList)GetValue(SelectedItemsListProperty);
            set => SetValue(SelectedItemsListProperty, value);
        }


        public static readonly DependencyProperty UseHorizontalScrollingProperty = DependencyProperty.RegisterAttached("UseHorizontalScrolling", typeof(bool), typeof(XDataGrid),
              new PropertyMetadata(default(bool), UseHorizontalScrollingChangedCallback));

        public bool UseHorizontalScrolling
        {
            get => (bool)GetValue(UseHorizontalScrollingProperty);
            set => SetValue(UseHorizontalScrollingProperty, value);
        }

        public static readonly DependencyProperty IsAccessibleWhitelistEditModeProperty = DependencyProperty.Register(
            nameof(IsAccessibleWhitelistEditMode), typeof(bool), typeof(XDataGrid), new PropertyMetadata(default(bool), IsCellAccessPermissionEditModePropertyChangedCallback));

        private static void IsCellAccessPermissionEditModePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is XDataGrid grid && e.NewValue is bool isAweMode)
            {
                if (isAweMode)
                {
                    // 如果进入单元格访问权限编辑模式，清除之前的拖拽框。
                    grid.ClearCellSelectionAdorner();
                }
            }
        }

        /// <summary>
        /// 设置或返回当前DataGrid是否处于单元格访问权限编辑模式。
        /// </summary>
        public bool IsAccessibleWhitelistEditMode
        {
            get => (bool)GetValue(IsAccessibleWhitelistEditModeProperty);
            set => SetValue(IsAccessibleWhitelistEditModeProperty, value);
        }

        #endregion

        #region DPs

        public static readonly DependencyProperty AllowDragToFillProperty = DependencyProperty.Register(
            nameof(AllowDragToFill), typeof(bool), typeof(XDataGrid), new PropertyMetadata(true));

        public bool AllowDragToFill
        {
            get => (bool)GetValue(AllowDragToFillProperty);
            set => SetValue(AllowDragToFillProperty, value);
        }

        public static readonly DependencyProperty DragToFillAdornerThumbStyleProperty = DependencyProperty.Register(
            nameof(DragToFillAdornerThumbStyle), typeof(Style), typeof(XDataGrid), 
            new PropertyMetadata(default(Style)));

        public Style DragToFillAdornerThumbStyle    
        {
            get => (Style)GetValue(DragToFillAdornerThumbStyleProperty);
            set => SetValue(DragToFillAdornerThumbStyleProperty, value);
        }

        public static readonly DependencyProperty DragToFillAdornerColorBrushProperty = DependencyProperty.Register(
            nameof(DragToFillAdornerColorBrush), typeof(Brush), typeof(XDataGrid), new PropertyMetadata(default(Brush)));

        public Brush DragToFillAdornerColorBrush
        {
            get => (Brush)GetValue(DragToFillAdornerColorBrushProperty);
            set => SetValue(DragToFillAdornerColorBrushProperty, value);
        }
        
        #endregion

        #region Excel-Like Cell Drag-To-Fill Adorner

        private DataGridCellDragToFillAdorner _lastAdorner;

        private void ClearCellSelectionAdorner()
        {
            // 清空之前的Adorner
            if (_lastAdorner != null && _lastAdorner.AdornedElement is EGC.DataGridCell cell)
            {
                var al = AdornerLayer.GetAdornerLayer(cell);
                var ads = al?.GetAdorners(cell)?.ToList();
                if (ads != null && ads.Any())
                    foreach (var ad in ads)
                        al.Remove(ad);
            }

            if (_lastAdorner != null)
            {
                (_lastAdorner.AdornedElement as EGC.DataGridCell).KeyDown -= Cell_KeyDown;

                _lastAdorner.OnDragStart -= LastAdornerOnOnDragStart;
                _lastAdorner.OnDragDelta -= LastAdornerOnOnDragDelta;
                _lastAdorner.OnDragCompleted -= LastAdornerOnOnDragCompleted;
            }

            _lastAdorner = null;
        }

        private void CreateCellSelectionAdorner(EGC.DataGridCellInfo? cellInfo)
        {
            ClearCellSelectionAdorner();

            if (!AllowDragToFill)
                return;

            // 如果选中了单元格，并且没有在编辑模式，显示Adorner
            if (CurrentCellContainer.IsEditing || !cellInfo.HasValue) 
                return;

            if (!CheckIsCellSupportDragToFill(TryFindCell(cellInfo.Value)))
                return;

            var cell = TryFindCell(cellInfo.Value);
            cell.KeyDown += Cell_KeyDown;

            if (cell != null && cell.DataContext is Param param)
            {
                // 根据Cell中Param的权限决定是否禁用拖拽填充功能
                var isEnabled = param.Permission != MenuPermissionEnum.MP_NONE;

                _lastAdorner =
                    new DataGridCellDragToFillAdorner(cell, new Size(cell.ActualWidth, cell.ActualHeight))
                    {
                        IsEnabled = isEnabled,
                        ThumbStyle = DragToFillAdornerThumbStyle,
                        Stroke = DragToFillAdornerColorBrush
                    };
                _lastAdorner.OnDragStart += LastAdornerOnOnDragStart;
                _lastAdorner.OnDragDelta += LastAdornerOnOnDragDelta;
                _lastAdorner.OnDragCompleted += LastAdornerOnOnDragCompleted;
                AdornerLayer.GetAdornerLayer(cell).Add(_lastAdorner);
            }
        }

        private Param GetParamFromCell(EGC.DataGridCellInfo? cellInfo)
        {
            if (cellInfo is { Item: RecipeStep rs, Column: EditorDataGridTemplateColumnBase col })
            {
                return rs.FirstOrDefault(x => x.ControlName == col.ControlName);
            }

            return null;
        }

        private Param GetParamFromCell(EGC.DataGridCell cell)
        {
            return GetParamFromCell(new EGC.DataGridCellInfo(cell));
        }

        /// <summary>
        /// 检查指定的单元格是否支持拖动填充功能。
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        private bool CheckIsCellSupportDragToFill(EGC.DataGridCell cell)
        {
            // 仅当单元格绑定的参数为数值型参数、并且参数访问权限不为MP_NONE、并且所属列不为ReadOnly，可以开启拖动填充功能
            if (cell.DataContext is Param param and IValueParam
                && cell.Column is EditorDataGridTemplateColumnBase { IsExpander: false, IsReadOnly: false })
                return true;

            return false;
        }

        /// <summary>
        /// If ESC key down when dragging, cancel the dragging.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Cell_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                _lastAdorner?.Cancel();
            }
        }

        private void LastAdornerOnOnDragStart(object sender, DragStartedEventArgs e)
        {
            //throw new NotImplementedException();
        }

        private void LastAdornerOnOnDragCompleted(object sender, DragCompletedEventArgs e)
        {
            if (sender is DataGridCellDragToFillAdorner adorner
                && adorner.AdornedElement is EGC.DataGridCell cell
                && _selectionAnchor != null)
            {
                // 源单元格不支持拖放填充
                if (!CheckIsCellSupportDragToFill(cell))
                    return;

                if (adorner.StartCellIndex != adorner.EndCellIndex)
                {
                    // 复制值
                    var srcParam = GetParamFromCell(_selectionAnchor);

                    if (srcParam is IValueParam param)
                    {
                        // 获取源数据
                        var value = param.GetValue();

                        var itemsHost = InternalItemsHost;
                        if (itemsHost != null)
                        {

                            var start = Math.Min(adorner.StartCellIndex, adorner.EndCellIndex);
                            var end = Math.Max(adorner.StartCellIndex, adorner.EndCellIndex);
                            for (var i = start; i <= end; i++)
                            {
                                if (itemsHost.Children[i] is EGC.DataGridRow row)
                                {
                                    var targetCell = row.TryGetCell(_selectionAnchor.Value.Column.DisplayIndex);
                                    
                                    // 如果当前行被设置为Visibility.Collapsed，则无法通过TryGetCell方法获取Cell对象
                                    if(targetCell == null)
                                        continue;

                                    // 获取目标单元格绑定的Recipe参数对象
                                    var targetParam = GetParamFromCell(targetCell);
                                    
                                    // 如果目标参数没有写权限，则不要赋值
                                    if(targetParam.Permission != MenuPermissionEnum.MP_READ_WRITE)
                                        continue;

                                    // 如果目标参数是值型参数，则写入源参数数值
                                    if (targetParam is IValueParam p)
                                        p.SetValue(value);
                                }
                            }
                        }
                    }
                }

                // 更新adorner尺寸
                //adorner.Arrange(adorner.GetSelectionBound());
            }
        }

        private void LastAdornerOnOnDragDelta(object sender, DragDeltaEventArgs e)
        {
            if (sender is DataGridCellDragToFillAdorner adorner && adorner.AdornedElement is EGC.DataGridCell cell)
            {
                // 检查当前Cell是否支持拖动填充
                if (!CheckIsCellSupportDragToFill(cell))
                    return;

                var itemsHost = InternalItemsHost;
                if (itemsHost == null)
                    return;

                // 获取当前鼠标附近的Cell
                var closestCell = MouseOverCell ?? GetCellNearMouse();
                if (closestCell != null)
                {
                    var originCellInfo = new EGC.DataGridCellInfo(cell);
                    var closestCellInfo = new EGC.DataGridCellInfo(closestCell);

                    var startIndex = Items.IndexOf(originCellInfo.Item);
                    var endIndex = Items.IndexOf(closestCellInfo.Item);

                    // 判断当前鼠标的Y坐标是否超过了当前Row高度的一半。
                    // 如果超过一半，则选中当前行对应的单元格；否则不选择。
                    var closestRow = closestCell.RowOwner;
                    var pt = Mouse.GetPosition(closestRow);
                    var rowBounds = new Rect(new Point(), closestRow.RenderSize);

                    // 默认选择当前单元格
                    var recRender = new Rect(0, 0, cell.ActualWidth, cell.ActualHeight);

                    // 判断鼠标是否划过当前Cell一半的位置，超过一半选中，没超过则不选中。
                    if (endIndex > startIndex) // Select the cells below the origin cell.
                    {
                        if (pt.Y < (rowBounds.Height / 2.0))
                            endIndex -= 1; // don't select the cell nearby mouse

                        recRender.Height = 0;
                        for (var i = startIndex; i <= endIndex; i++)
                        {
                            if (itemsHost.Children[i] is EGC.DataGridRow row)
                                recRender.Height += row.RenderSize.Height;
                        }
                    }
                    else if (endIndex < startIndex) // Select the cells above the origin cell.
                    {
                        if (pt.Y > (rowBounds.Height / 2.0))
                            endIndex += 1; // don't select the cell nearby mouse

                        recRender.Height = 0;
                        for (var i = endIndex; i <= startIndex; i++)
                        {
                            if (itemsHost.Children[i] is EGC.DataGridRow row)
                                recRender.Height += row.RenderSize.Height;
                        }

                        /*Debug.WriteLine($"Start: {startIndex}, End: {endIndex}", "Adorner");
                        Debug.WriteLine($"Rendering Adorner: {recRender}", "Adorner");
                        Debug.WriteLine($"Cell Height: {cell.ActualHeight}, Render Height: {recRender.Height}", "Adorner");*/

                        recRender.Y = cell.ActualHeight - recRender.Height;

                        //Debug.WriteLine($"Render Y: {recRender.Y}", "Adorner");
                    }

                    // 重新计算Adorner尺寸
                    adorner.ArrangeSelectionBound(recRender, startIndex, endIndex);
                }
            }
        }

        protected override void EnsureInternalScrollControls()
        {
            base.EnsureInternalScrollControls();

            if (_internalScrollHost != null)
                _internalScrollHost.ScrollChanged += (sender, args) =>
                {
                    // Clear the cell adorner while the view is scrolling.
                    ClearCellSelectionAdorner();
                };
        }

        protected override void MakeFullRowSelection(object dataItem, bool allowsExtendSelect, bool allowsMinimalSelect)
        {
            base.MakeFullRowSelection(dataItem, allowsExtendSelect, allowsMinimalSelect);
            /*if (CurrentCell != null)
                CreateCellSelectionAdorner(CurrentCell);*/
        }

        protected override void MakeCellSelection(EGC.DataGridCellInfo cellInfo, bool allowsExtendSelect, bool allowsMinimalSelect)
        {
            base.MakeCellSelection(cellInfo, allowsExtendSelect, allowsMinimalSelect);

            // 如果是单元格访问权限编辑模式，则不要启用Drag-To-Fill功能
            if (IsAccessibleWhitelistEditMode)
                return;

            if (_selectionAnchor != null)
                CreateCellSelectionAdorner(_selectionAnchor);
        }

        public override bool BeginEdit(RoutedEventArgs editingEventArgs)
        {
            if (IsAccessibleWhitelistEditMode)
                return false;

            return base.BeginEdit(editingEventArgs);
        }

        #endregion

        #region Methods

        private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            SelectedItemsList = SelectedItems;
        }

        protected override void OnArrowKeyDown(KeyEventArgs e)
        {
            //TODO 重映射方向键后，拖拽填充控件的位置不对，此功能还需要调试。
            var remapKey = e.Key;

            remapKey = remapKey switch
            {
                Key.Left => Key.Down,
                Key.Down => Key.Right,
                Key.Right => Key.Up,
                Key.Up => Key.Left,
                _ => remapKey
            };

            var args = new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, remapKey);
            args.RoutedEvent = e.RoutedEvent;
            
            base.OnArrowKeyDown(e);
        }

        private void _UseHorizontalScrollingChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            PreviewMouseWheel += delegate (object sender, MouseWheelEventArgs args)
            {
                ScrollViewer scrollViewer = GetTemplateChild("DG_ScrollViewer") as ScrollViewer;
                if (scrollViewer != null)
                {
                    if (args.Delta > 0)
                        scrollViewer.LineLeft();
                    else
                        scrollViewer.LineRight();
                }
                ref_scrollviewer = scrollViewer;
                args.Handled = true;
            };
        }

        private static void UseHorizontalScrollingChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            if (!(dependencyObject is XDataGrid dg))
                throw new ArgumentException("Element is not an ItemsControl");

            dg._UseHorizontalScrollingChangedCallback(dependencyObject, dependencyPropertyChangedEventArgs);
        }

        public static void SetUseHorizontalScrolling(ItemsControl element, bool value)
        {
            element.SetValue(UseHorizontalScrollingProperty, value);
        }

        public static bool GetUseHorizontalScrolling(ItemsControl element)
        {
            return (bool)element.GetValue(UseHorizontalScrollingProperty);
        }

        #endregion
    }
}
