using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using System;
using System.Linq;
using Windows.Foundation;

namespace Sonex.Client.Controls.DataGridView
{
    // Odpowiedzialnosc pliku: osobny flyout do zarzadzania kolumnami (widocznosc, pin, kolejnosc).
    public sealed partial class DataGridView
    {
        private MenuFlyoutItem BuildColumnsFlyoutItem()
        {
            var item = new MenuFlyoutItem
            {
                Text = "Columns",
                Icon = CreateContextMenuSvgIcon("columns.svg")
            };

            item.Click += (_, _) => OpenColumnsFlyout();
            return item;
        }

        private void OpenColumnsFlyout()
        {
            EnsureColumnsFlyout();
            RebuildColumnsFlyoutItems();

            if (_columnsFlyout == null || _columnsFlyoutListView == null)
            {
                return;
            }

            _columnsFlyout.ShowAt(_Canvas, new FlyoutShowOptions
            {
                Position = GetColumnsFlyoutPosition()
            });
            CursorDefault();
        }

        private void EnsureColumnsFlyout()
        {
            if (_columnsFlyout != null && _columnsFlyoutListView != null)
            {
                return;
            }

            // Border host ma wewnętrzny padding, więc szerokość ListView musi być
            // odpowiednio mniejsza od szerokości całego flyoutu.
            var columnsFlyoutContentWidth = Math.Max(240d, ColumnsFlyoutWidth - 12d);

            // Osobny flyout listy kolumn pozwala na wielokrotne akcje bez zamykania całego menu.
            _columnsFlyoutListView = new ListView
            {
                CanDragItems = true,
                CanReorderItems = true,
                AllowDrop = true,
                SelectionMode = ListViewSelectionMode.Single,
                MaxHeight = ColumnsFlyoutMaxHeight,
                MinWidth = columnsFlyoutContentWidth,
                Width = columnsFlyoutContentWidth
            };
            _columnsFlyoutListView.DragItemsStarting += ColumnsFlyoutListView_DragItemsStarting;
            _columnsFlyoutListView.DragItemsCompleted += ColumnsFlyoutListView_DragItemsCompleted;
            _columnsFlyoutListView.Transitions = new Microsoft.UI.Xaml.Media.Animation.TransitionCollection();
            _columnsFlyoutListView.ItemContainerTransitions = new Microsoft.UI.Xaml.Media.Animation.TransitionCollection();

            var listViewItemStyle = new Style(typeof(ListViewItem));
            listViewItemStyle.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch));
            listViewItemStyle.Setters.Add(new Setter(Control.PaddingProperty, new Thickness(0)));
            listViewItemStyle.Setters.Add(new Setter(UIElement.TransitionsProperty, new Microsoft.UI.Xaml.Media.Animation.TransitionCollection()));
            _columnsFlyoutListView.ItemContainerStyle = listViewItemStyle;

            var host = new Border
            {
                Child = _columnsFlyoutListView,
                MinWidth = ColumnsFlyoutWidth,
                MaxWidth = ColumnsFlyoutWidth,
                Padding = new Thickness(6, 4, 6, 4)
            };

            _columnsFlyout = new Flyout
            {
                Content = host,
                Placement = FlyoutPlacementMode.Bottom
            };
            _columnsFlyout.Opened += ColumnsFlyout_Opened;
            _columnsFlyout.Closed += ColumnsFlyout_Closed;
        }

        private void ColumnsFlyout_Opened(object? sender, object e)
        {
            CursorDefault();
        }

        private void ColumnsFlyout_Closed(object? sender, object e)
        {
            CursorDefault();
        }

        private void RebuildColumnsFlyoutItems()
        {
            if (_columnsFlyoutListView == null)
            {
                return;
            }
            _columnsFlyoutUpdating = true;
            try
            {
                _columnsFlyoutListView.Items.Clear();

                foreach (var column in _Columns
                             .OrderBy(c => c.Index))
                {
                    _columnsFlyoutListView.Items.Add(BuildColumnListViewRow(column));
                }
            }
            catch
            {
                // Leave current list as-is; this method is used as a safe fallback path.
            }
            finally
            {
                _columnsFlyoutUpdating = false;
            }
        }

        private FrameworkElement BuildColumnListViewRow(Column column)
        {
            var title = string.IsNullOrWhiteSpace(column.Title) ? column.Name : column.Title;
            var isPinnedByIndex = DecodeColumnIndexState(column.Index).IsPinned;

            var row = new Grid
            {
                Tag = column,
                Margin = new Thickness(8, 1, 8, 1),
                MinHeight = 30
            };
            row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(44) });
            row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
            row.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(52) });

            var checkBox = new CheckBox
            {
                IsChecked = !column.IsHiden,
                VerticalAlignment = VerticalAlignment.Center,
                Margin = new Thickness(0, 0, 8, 0),
                Tag = column
            };
            checkBox.Checked += ColumnsFlyoutCheckBox_Checked;
            checkBox.Unchecked += ColumnsFlyoutCheckBox_Unchecked;
            Grid.SetColumn(checkBox, 0);

            var text = new TextBlock
            {
                Text = title,
                VerticalAlignment = VerticalAlignment.Center,
                TextTrimming = TextTrimming.CharacterEllipsis
            };
            Grid.SetColumn(text, 1);

            var pinButton = new Button
            {
                Tag = column,
                Content = new SymbolIcon(Symbol.Pin),
                VerticalAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center,
                Width = 38,
                Height = 30,
                MinWidth = 38,
                MinHeight = 30,
                Padding = new Thickness(8, 2, 8, 2),
                IsEnabled = column.CanPin,
                Opacity = isPinnedByIndex ? 1d : 0.45d
            };
            if (Application.Current?.Resources.TryGetValue("SubtleButtonStyle", out var subtleStyleObj) == true
                && subtleStyleObj is Style subtleButtonStyle)
            {
                pinButton.Style = subtleButtonStyle;
            }

            ToolTipService.SetToolTip(pinButton, isPinnedByIndex ? "Unpin column" : "Pin column");
            pinButton.Click += ColumnsFlyoutPinButton_Click;
            Grid.SetColumn(pinButton, 2);

            row.Children.Add(checkBox);
            row.Children.Add(text);
            row.Children.Add(pinButton);
            return row;
        }

        private void ColumnsFlyoutListView_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
        {
            try
            {
                _columnsFlyoutDragInProgress = false;

                if (_columnsFlyoutUpdating)
                {
                    return;
                }

                DispatcherQueue.TryEnqueue(() =>
                {
                    if (_columnsFlyoutUpdating || _columnsFlyoutDragInProgress)
                    {
                        return;
                    }

                    TryApplyColumnOrderFromListView();
                });
            }
            catch
            {
                _columnsFlyoutDragInProgress = false;
                RebuildColumnsFlyoutItems();
            }
        }

        private void ColumnsFlyoutListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
        {
            _columnsFlyoutDragInProgress = true;
        }

        private void TryApplyColumnOrderFromListView()
        {
            try
            {
                ApplyColumnOrderFromListView();
            }
            catch (ArgumentException)
            {
                RebuildColumnsFlyoutItems();
            }
            catch
            {
                RebuildColumnsFlyoutItems();
            }
        }

        private void ApplyColumnOrderFromListView()
        {
            if (_columnsFlyoutListView == null)
            {
                return;
            }

            var orderedColumns = _columnsFlyoutListView.Items
                .OfType<FrameworkElement>()
                .Select(item => item.Tag)
                .OfType<Column>()
                .ToList();
            if (orderedColumns.Count == 0)
            {
                return;
            }

            const int baseStart = 10000;
            const int baseStep = 10;

            for (var i = 0; i < orderedColumns.Count; i++)
            {
                var column = orderedColumns[i];
                var state = DecodeColumnIndexState(column.Index);
                var baseIndex = baseStart + (i * baseStep);
                column.Index = ComposeColumnIndex(baseIndex, state.IsPinned, state.IsHiden);
            }

            _NeedCalcHeaders = true;
            _NeedCalcHorizontalScroll = true;
            RequestRender();
        }

        private void ColumnsFlyoutCheckBox_Checked(object sender, RoutedEventArgs e)
        {
            try
            {
                if (_columnsFlyoutUpdating || _columnsFlyoutDragInProgress || sender is not CheckBox checkBox || checkBox.Tag is not Column column)
                {
                    return;
                }

                if (column.IsHiden)
                {
                    ShowColumn(column.Name);
                    SafeRefreshColumnsFlyoutRow(column);
                }
            }
            catch
            {
                RebuildColumnsFlyoutItems();
            }
        }

        private void ColumnsFlyoutCheckBox_Unchecked(object sender, RoutedEventArgs e)
        {
            try
            {
                if (_columnsFlyoutUpdating || _columnsFlyoutDragInProgress || sender is not CheckBox checkBox || checkBox.Tag is not Column column)
                {
                    return;
                }

                var visibleColumnsCount = _Columns.Count(c => !c.IsHiden);
                if (visibleColumnsCount <= 1)
                {
                    _columnsFlyoutUpdating = true;
                    checkBox.IsChecked = true;
                    _columnsFlyoutUpdating = false;
                    return;
                }

                if (!column.IsHiden)
                {
                    HideColumn(column.Name);
                    SafeRefreshColumnsFlyoutRow(column);
                }
            }
            catch
            {
                _columnsFlyoutUpdating = false;
                RebuildColumnsFlyoutItems();
            }
        }

        private void ColumnsFlyoutPinButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (_columnsFlyoutUpdating
                    || _columnsFlyoutDragInProgress
                    || _columnsFlyoutPinToggleInProgress
                    || sender is not Button button
                    || button.Tag is not Column column
                    || !column.CanPin)
                {
                    return;
                }

                _columnsFlyoutPinToggleInProgress = true;
                var state = DecodeColumnIndexState(column.Index);
                var baseIndex = ExtractColumnBaseIndex(column.Index);
                column.Index = ComposeColumnIndex(baseIndex, !state.IsPinned, state.IsHiden);

                _NeedCalcHeaders = true;
                _NeedCalcHorizontalScroll = true;
                RequestRender();
                SafeRefreshColumnsFlyoutRow(column);
            }
            catch
            {
                RebuildColumnsFlyoutItems();
            }
            finally
            {
                _columnsFlyoutPinToggleInProgress = false;
            }
        }

        private void SafeRefreshColumnsFlyoutRow(Column column)
        {
            try
            {
                RefreshColumnsFlyoutRow(column);
            }
            catch
            {
                RebuildColumnsFlyoutItems();
            }
        }

        private void RefreshColumnsFlyoutRow(Column column)
        {
            var row = FindColumnsFlyoutRow(column);
            if (row is not Grid grid)
            {
                return;
            }

            var previousUpdating = _columnsFlyoutUpdating;
            _columnsFlyoutUpdating = true;
            try
            {
                foreach (var child in grid.Children)
                {
                    if (child is CheckBox checkBox)
                    {
                        checkBox.IsChecked = !column.IsHiden;
                        continue;
                    }

                    if (child is Button pinButton)
                    {
                        var isPinned = DecodeColumnIndexState(column.Index).IsPinned;
                        pinButton.IsEnabled = column.CanPin;
                        pinButton.Opacity = isPinned ? 1d : 0.45d;
                        ToolTipService.SetToolTip(pinButton, isPinned ? "Unpin column" : "Pin column");
                    }
                }
            }
            finally
            {
                _columnsFlyoutUpdating = previousUpdating;
            }
        }

        private FrameworkElement? FindColumnsFlyoutRow(Column column)
        {
            return _columnsFlyoutListView?.Items
                .OfType<FrameworkElement>()
                .FirstOrDefault(item => ReferenceEquals(item.Tag, column));
        }

        private static (bool IsHiden, bool IsPinned) DecodeColumnIndexState(int index)
        {
            var normalized = index;
            var isHiden = normalized >= 1000000;
            if (isHiden)
            {
                normalized -= 1100000;
            }

            var isPinned = normalized < 0;
            return (isHiden, isPinned);
        }

        private static int ExtractColumnBaseIndex(int index)
        {
            var normalized = index;
            if (normalized >= 1000000)
            {
                normalized -= 1100000;
            }

            if (normalized < 0)
            {
                normalized += 100000;
            }

            return Math.Max(0, normalized);
        }

        private static int ComposeColumnIndex(int baseIndex, bool isPinned, bool isHiden)
        {
            var index = baseIndex;
            if (isPinned)
            {
                index -= 100000;
            }

            if (isHiden)
            {
                index += 1100000;
            }

            return index;
        }

        private Point GetColumnsFlyoutPosition()
        {
            var desiredHeight = Math.Min(ColumnsFlyoutMaxHeight, Math.Max(120d, (_Columns.Count * 34d) + 16d));
            var desiredX = (ActualWidth - ColumnsFlyoutWidth) * 0.5d;
            var desiredY = (ActualHeight - desiredHeight) * 0.5d;
            var maxX = Math.Max(0, ActualWidth - ColumnsFlyoutWidth);
            var maxY = Math.Max(0, ActualHeight - desiredHeight);

            return new Point(
                Math.Clamp(desiredX, 0, maxX),
                Math.Clamp(desiredY, 0, maxY));
        }

        private Style GetContextMenuPresenterStyle()
        {
            if (_contextMenuPresenterStyle != null)
            {
                return _contextMenuPresenterStyle;
            }

            var resources = Application.Current?.Resources;
            if (resources != null
                && resources.TryGetValue("DefaultMenuFlyoutPresenterStyle", out var baseStyleObj)
                && baseStyleObj is Style baseStyle)
            {
                _contextMenuPresenterStyle = baseStyle;
                return _contextMenuPresenterStyle;
            }

            _contextMenuPresenterStyle = new Style(typeof(MenuFlyoutPresenter));
            return _contextMenuPresenterStyle;
        }
    }
}
