using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Diagnostics;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
using MECF.Framework.UI.Client.RecipeEditorLib.DGExtension.CustomColumn;
using MECF.Framework.Common.Account.Permissions;
using OpenSEMI.ClientBase;
using DataGridRowEventArgs = ExtendedGrid.Microsoft.Windows.Controls.DataGridRowEventArgs;
using DataGridCellEditEndingEventArgs = ExtendedGrid.Microsoft.Windows.Controls.DataGridCellEditEndingEventArgs;
using DataGridBeginningEditEventArgs = ExtendedGrid.Microsoft.Windows.Controls.DataGridBeginningEditEventArgs;
using ExDataGridRow = ExtendedGrid.Microsoft.Windows.Controls.DataGridRow;

namespace MECF.Framework.UI.Client.RecipeEditorLib.DGExtension
{
    /// <summary>
    /// Interaction logic for DataGridRecipe.xaml
    /// </summary>
    public partial class DataGridRecipe : UserControl
    {
        enum Scroll
        {
            VerticalOffset,
            HorizontalOffset
        }

        #region Constructors

        ScrollViewer scroll;
        public DataGridRecipe()
        {
            InitializeComponent();
        }

        private void dgCustom_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            
            if (scroll==null)
                scroll = (ScrollViewer)e.OriginalSource;

            if (ScrollViewerOffset == null)
                ScrollViewerOffset=new double[2];

            var _verticalOffset = scroll.VerticalOffset < scroll.ScrollableHeight ? scroll.VerticalOffset : 
                                        ScrollViewerOffset[(int)Scroll.VerticalOffset] <= scroll.ScrollableHeight? scroll.VerticalOffset : ScrollViewerOffset[(int)Scroll.VerticalOffset];

            var _horizontalOffset= scroll.HorizontalOffset < scroll.ScrollableWidth ? scroll.HorizontalOffset :
                                        ScrollViewerOffset[(int)Scroll.HorizontalOffset] <= scroll.ScrollableWidth ? scroll.HorizontalOffset: ScrollViewerOffset[(int)Scroll.HorizontalOffset];

            ScrollViewerOffset = new double[] { _verticalOffset, _horizontalOffset };
        }

        #endregion

        #region Properties


        #endregion

        #region Dependency Properties

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

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


        public double[] ScrollViewerOffset
        {
            get { return (double[])GetValue(ScrollViewerOffsetProperty); }
            set { SetValue(ScrollViewerOffsetProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScrollViewerOffset.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScrollViewerOffsetProperty =
            DependencyProperty.Register("ScrollViewerOffset", typeof(double[]), typeof(DataGridRecipe), new PropertyMetadata(new double[2], ScrollViewerOffsetPropertyChangedCallback));

        #region RecipeData


        public static readonly DependencyProperty RecipeProperty = DependencyProperty.Register(
            nameof(Recipe), typeof(RecipeData), typeof(DataGridRecipe), new PropertyMetadata(default(RecipeData), RecipePropertyChangedCallback));

        public ExtendedGrid.Microsoft.Windows.Controls.DataGridHeadersVisibility ComperHeadersVisibility
        {
            get { return (ExtendedGrid.Microsoft.Windows.Controls.DataGridHeadersVisibility)GetValue(ComperHeadersVisibilityProperty); }
            set { SetValue(ComperHeadersVisibilityProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ComperHeadersVisibility.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ComperHeadersVisibilityProperty =
            DependencyProperty.Register("ComperHeadersVisibility", typeof(ExtendedGrid.Microsoft.Windows.Controls.DataGridHeadersVisibility), typeof(DataGridRecipe), new PropertyMetadata(ExtendedGrid.Microsoft.Windows.Controls.DataGridHeadersVisibility.Column));


        private static void ScrollViewerOffsetPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DataGridRecipe self)
            {
                if (self.scroll != null)
                {
                    if (e.NewValue != null)
                    {
                        var _scOffset = (double[])e.NewValue;

                        self.scroll.ScrollToVerticalOffset(_scOffset[(int)Scroll.VerticalOffset] <= self.scroll.ScrollableHeight ? _scOffset[(int)Scroll.VerticalOffset] : self.scroll.ScrollableHeight);
                        self.scroll.ScrollToHorizontalOffset(_scOffset[(int)Scroll.HorizontalOffset] <= self.scroll.ScrollableWidth ? _scOffset[(int)Scroll.HorizontalOffset] : self.scroll.ScrollableWidth);
                    }
                    
                }

            }
        }

        private static void RecipePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DataGridRecipe dg)
            {
                if (e.NewValue is RecipeData recipe)
                {
                    dg.dgCustom.ItemsSource = recipe.Steps;
                    recipe.PropertyChanged += (sender, e) =>
                    {
                        // 同步白名单编辑模式
                        if (e.PropertyName == nameof(RecipeData.IsAccessibleWhitelistEditMode))
                        {
                            dg.dgCustom.IsAccessibleWhitelistEditMode = recipe.IsAccessibleWhitelistEditMode;
                        }

                    };

                    // 创建DataGrid列
                    dg.ClearColumns();

                    if (recipe.Columns != null)
                    {
                        foreach (var col in recipe.Columns)
                            dg.AddColumn(col);
                    }
                }
                else
                    dg.dgCustom.ItemsSource = null;
            }
        }

        /// <summary>
        /// 设置或返回编辑器正在编辑的Recipe。
        /// </summary>
        public RecipeData Recipe
        {
            get => (RecipeData)GetValue(RecipeProperty);
            set => SetValue(RecipeProperty, value);
        }

        #endregion

        #region FrozenColumnCount

        public static readonly DependencyProperty FrozenColumnCountProperty = DependencyProperty.Register(
            nameof(FrozenColumnCount), typeof(int), typeof(DataGridRecipe), new PropertyMetadata(default(int), FrozenColumnCountPropertyChangedCallback));

        private static void FrozenColumnCountPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DataGridRecipe dg)
            {
                if (e.NewValue is int count)
                    dg.dgCustom.FrozenColumnCount = count;
                else
                    dg.dgCustom.FrozenColumnCount = 0;
            }
        }

        /// <summary>
        /// 设置或返回编辑器冻结的列数。
        /// </summary>
        public int FrozenColumnCount
        {
            get => (int)GetValue(FrozenColumnCountProperty);
            set => SetValue(FrozenColumnCountProperty, value);
        }

        #endregion
        
        #endregion

        #region Methods

        private void RowOnSelected(object sender, RoutedEventArgs e)
        {
            if (!(e.Source is ExDataGridRow dgr))
                return;

            if (!(dgr.DataContext is RecipeStep recipeStep))
                return;

            var param = recipeStep.FindParamByControlName(RecipeControlNames.STEP_NO);
            if (param is StepParam sp)
            {
                sp.IsChecked = true;
            }
        }

        private void RowOnUnselected(object sender, RoutedEventArgs e)
        {
            if (!(e.Source is ExDataGridRow dgr))
                return;

            if (!(dgr.DataContext is RecipeStep recipeStep))
                return;

            var param = recipeStep.FindParamByControlName(RecipeControlNames.STEP_NO);
            if (param is StepParam sp)
            {
                sp.IsChecked = false;
            }
        }

        private void ClearColumns()
        {
            dgCustom.Columns.Clear();
        }

        /// <summary>
        /// 生成编辑器的列。
        /// </summary>
        private void AddColumn(EditorDataGridTemplateColumnBase col)
        {
            // 设置ColumnHeaderTemplate和DataGridCellTemplate
            if (string.IsNullOrEmpty(col.StringCellTemplate) == false)
                col.CellTemplate = (DataTemplate)FindResource(col.StringCellTemplate);

            if (string.IsNullOrEmpty(col.StringCellEditingTemplate) == false)
                col.CellEditingTemplate = (DataTemplate)FindResource(col.StringCellEditingTemplate);

            if (string.IsNullOrEmpty(col.StringHeaderTemplate) == false)
                col.HeaderTemplate = (DataTemplate)FindResource(col.StringHeaderTemplate);

            // 通过Columns重建XDataGrid列
            dgCustom.Columns.Add(col);
        }

        /// <summary>
        /// 滚动到并高亮指定的参数单元格。
        /// </summary>
        /// <param name="param"></param>
        public void FocusToParam(IParam param)
        {
            if (param == null)
                return;

            Recipe.Steps.ResetHighlight();

            var row = param.RowOwner;
            var col = param.ColumnOwner;

            if (row != null && col != null)
            {
                dgCustom.ScrollIntoView(param.Parent, col);
                param.Highlight();
            }
        }

        #endregion

        #region Events
        
        private void DgCustom_OnBeginningEdit(object sender, DataGridBeginningEditEventArgs e)
        {
            Debug.Assert(e.Row.Item is RecipeStep, "The content of row is not RecipeStep.");
            if (e.Row.Item is RecipeStep step)
            {
                var param = step[e.Column.DisplayIndex];
                
                if (param is IValueParam && param.Permission != MenuPermissionEnum.MP_READ_WRITE || param.IsHideValue)
                {
                    e.Cancel = true;

                    // 如果单元格为只读权限、或设置了隐藏参数值，则提示不能编辑
                    var reason = "";
                    if (param.ColumnPermission != MenuPermissionEnum.MP_READ_WRITE)
                        reason = "Recipe Row Access Denied!\r\n\r\nPlease check the RecipeRow Access Permission.";
                    else if (param.StepPermission != MenuPermissionEnum.MP_READ_WRITE)
                        reason = "Recipe Step Access Denied!\r\n\r\nPlease check the RecipeCol Access Permission.";
                    else if (param.IsHideValue)
                        reason = "Hidden Cell is denied editing.";
                    else
                        reason = "Cell Access Denied!\r\n\r\nPlease check the RecipeRow/RecipeCol Access Permission.";
                    
                    
                    DialogBox.ShowError(reason);
                }
            }
            else
                e.Cancel = true;
        }

        private void DataGridCell_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
           
                // 仅在编辑AccessPermissionWhitelist编辑模式下有效。
                if (!Recipe.IsAccessibleWhitelistEditMode)
                    return;

                if (sender is Border bdr && bdr.DataContext is Param param)
                {
                    if (param.IsHighlighted)
                        param.ResetHighlight();
                    else
                        param.Highlight();
                }
        }

        private void DgCustom_OnLoadingRow(object sender, DataGridRowEventArgs e)
        {
            e.Row.Selected += RowOnSelected;
            e.Row.Unselected += RowOnUnselected;

            if (sender is XDataGrid dg && e.Row.DataContext is RecipeStep step)
            {
                for (var i = 0; i < step.Count; i++)
                {
                    step[i].RowOwner = e.Row;
                    step[i].ColumnOwner = dg.Columns[i];
                }
            }
        }

        private void DgCustom_OnUnloadingRow(object sender, DataGridRowEventArgs e)
        {
            e.Row.Selected -= RowOnSelected;
            e.Row.Unselected -= RowOnUnselected;
        }
        

        private void DgCustom_OnCellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
        {
            if (e.Row.Item is RecipeStep step)
            {
                step.CalculateGasFlow();
                step.Parent.Validate();
            }
        }

        private void Expander_OnExpanded(object sender, RoutedEventArgs e)
        {
            if (sender is Expander expander && expander.DataContext is ExpanderColumn col)
            {
                foreach (var subCol in col.ChildColumns)
                {
                    subCol.UpdateVisibility();
                }
            }
        }

        private void Expander_OnCollapsed(object sender, RoutedEventArgs e)
        {
            if (sender is Expander expander && expander.DataContext is ExpanderColumn col)
            {
                foreach (var subCol in col.ChildColumns)
                {
                    subCol.Visibility = Visibility.Collapsed;
                }
            }
        }

        /// <summary>
        /// 滚动DataGrid视图到指定的配方步骤。
        /// </summary>
        /// <param name="step"></param>
        public void ScrollToRecipeStep(RecipeStep step)
        {
            dgCustom.ScrollIntoView(step);
        }

        #endregion
    }
}
