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

namespace Sonex.Client.Controls.DataGridView
{
    // Odpowiedzialnosc pliku: rdzen budowania menu kontekstowego i akcji kontekstowych zaleznych od obszaru.
    public sealed partial class DataGridView
    {
        // Buduje menu dynamicznie na podstawie obszaru klikniecia i stanu zaznaczenia.
        private void ShowContextMenu(Point position, AreaType area)
        {
            var menu = BuildContextMenu(position, area);
            if (menu.Items.Count == 0)
            {
                return;
            }

            menu.MenuFlyoutPresenterStyle = GetContextMenuPresenterStyle();

            menu.Opened += (_, _) => CursorDefault();
            menu.Closing += (_, _) => CursorDefault();
            menu.Closed += (_, _) => CursorDefault();

            menu.ShowAt(_Canvas, new FlyoutShowOptions
            {
                Position = position
            });
        }

        private MenuFlyout BuildContextMenu(Point position, AreaType area)
        {
            // Każdy obszar ma własny zestaw akcji, ale na końcu zawsze dokładamy pozycje wspólne.
            var menu = new MenuFlyout();
            var hasSelection = HasAnySelection();
            var hasCopySelection = HasCopySelection();

            switch (area)
            {
                case AreaType.Header:
                    AppendHeaderContextMenuItems(menu, position, hasSelection);
                    break;
                case AreaType.Index:
                    AppendIndexContextMenuItems(menu, hasSelection, hasCopySelection);
                    break;
                case AreaType.Cell:
                    AppendCellContextMenuItems(menu, position, hasSelection, hasCopySelection);
                    break;
                default:
                    AppendDefaultContextMenuItems(menu, hasSelection);
                    break;
            }

            AppendCommonContextMenuItems(menu);
            return menu;
        }

        private void AppendHeaderContextMenuItems(MenuFlyout menu, Point position, bool hasSelection)
        {
            var column = position.X < _IndexColWidth ? null : GetColumnAtPosition(position);
            if (column != null)
            {
                AppendHeaderColumnContextMenuItems(menu, column);
            }

            AppendSelectionContextMenuItems(menu, hasSelection);
        }

        private void AppendHeaderColumnContextMenuItems(MenuFlyout menu, Column column)
        {
            var title = string.IsNullOrWhiteSpace(column.Title) ? column.Name : column.Title;

            if (column.CanSort)
            {
                menu.Items.Add(CreateContextMenuItem("Sort", () =>
                {
                    column.Sort();
                    RequestRender();
                }, Symbol.Sort));
            }

            if (column.CanFilter)
            {
                menu.Items.Add(CreateContextMenuItem(
                    $"Open filter for \"{title}\"...",
                    () => column.ShowFilter(),
                    "filter.svg",
                    acceleratorKey: VirtualKey.F,
                    acceleratorModifiers: VirtualKeyModifiers.Control,
                    acceleratorText: "Ctrl+F"));
            }

            menu.Items.Add(CreateContextMenuItem("Auto size column", () =>
            {
                column.AutoSize();
                RequestRender();
            }, "autosize.svg", acceleratorText: "Ctrl + W"));

            if (column.isSelected)
            {
                menu.Items.Add(CreateContextMenuItem(
                    "Unselect column",
                    () => UnselectColumnFromContextMenu(column),
                    Symbol.Clear,
                    acceleratorText: "Ctrl + Header"));
            }
            else
            {
                menu.Items.Add(CreateContextMenuItem(
                    "Select column",
                    () => SelectColumnFromContextMenu(column),
                    Symbol.SelectAll,
                    acceleratorText: "Ctrl + Header"));
            }

            if (column.CanPin)
            {
                menu.Items.Add(CreateContextMenuItem(column.IsPinned ? "Unpin column" : "Pin column", () =>
                {
                    if (column.IsPinned)
                    {
                        UnPin(column.Name);
                    }
                    else
                    {
                        Pin(column.Name);
                    }
                }, Symbol.Pin, acceleratorText: "Shift + Header"));
            }

            var visibleColumnsCount = _Columns.Count(x => !x.IsHiden);
            menu.Items.Add(CreateContextMenuItem(
                "Hide column",
                () => HideColumn(column.Name),
                Symbol.Delete,
                visibleColumnsCount > 1,
                acceleratorText: "Alt + Header"));
            menu.Items.Add(new MenuFlyoutSeparator());
        }

        private void AppendIndexContextMenuItems(MenuFlyout menu, bool hasSelection, bool hasCopySelection)
        {
            AppendCopyContextMenuItems(menu, hasCopySelection);
            menu.Items.Add(new MenuFlyoutSeparator());

            menu.Items.Add(CreateContextMenuItem(
                "Select all rows",
                SelectAllRowsFromContextMenu,
                "select_all.svg",
                acceleratorKey: VirtualKey.A,
                acceleratorModifiers: VirtualKeyModifiers.Control | VirtualKeyModifiers.Shift,
                acceleratorText: "Ctrl+Shift+A"));
            AppendSelectionContextMenuItems(menu, hasSelection);
        }

        private void AppendCellContextMenuItems(MenuFlyout menu, Point position, bool hasSelection, bool hasCopySelection)
        {
            var column = GetColumnAtPosition(position);
            if (column != null && column.CanFilter)
            {
                var title = string.IsNullOrWhiteSpace(column.Title) ? column.Name : column.Title;
                menu.Items.Add(CreateContextMenuItem(
                    $"Open filter for \"{title}\"...",
                    () => column.ShowFilter(),
                    "filter.svg",
                    acceleratorKey: VirtualKey.F,
                    acceleratorModifiers: VirtualKeyModifiers.Control,
                    acceleratorText: "Ctrl+F"));
                var canFilterBySelectedValue = TryBuildFilterRuleFromCell(position, out var selectedValueRule, out var selectedValuePreview);
                var filterByValueText = canFilterBySelectedValue
                    ? $"Filter by {selectedValuePreview}"
                    : "Filter by value";
                menu.Items.Add(CreateContextMenuItem(filterByValueText, () =>
                {
                    if (selectedValueRule != null)
                    {
                        ApplyQuickCellFilter(selectedValueRule);
                    }
                },
                "filter.svg",
                canFilterBySelectedValue,
                acceleratorKey: VirtualKey.F,
                acceleratorModifiers: VirtualKeyModifiers.Control | VirtualKeyModifiers.Shift,
                acceleratorText: "Ctrl + Shift + F"));
                menu.Items.Add(new MenuFlyoutSeparator());
            }

            AppendCopyContextMenuItems(menu, hasCopySelection);
            menu.Items.Add(new MenuFlyoutSeparator());
            AppendSelectionContextMenuItems(menu, hasSelection);
        }

        private void AppendDefaultContextMenuItems(MenuFlyout menu, bool hasSelection)
        {
            AppendSelectionContextMenuItems(menu, hasSelection);
        }

        private void AppendCopyContextMenuItems(MenuFlyout menu, bool hasCopySelection)
        {
            menu.Items.Add(CreateContextMenuItem(
                "Copy selection",
                () => SelectToClipboard(withHeaders: false),
                Symbol.Copy,
                hasCopySelection,
                acceleratorKey: VirtualKey.C,
                acceleratorModifiers: VirtualKeyModifiers.Control,
                acceleratorText: "Ctrl+C"));
            menu.Items.Add(CreateContextMenuItem(
                "Copy selection with headers",
                () => SelectToClipboard(withHeaders: true),
                Symbol.Copy,
                hasCopySelection,
                acceleratorKey: VirtualKey.C,
                acceleratorModifiers: VirtualKeyModifiers.Control | VirtualKeyModifiers.Shift,
                acceleratorText: "Ctrl+Shift+C"));
        }

        private void AppendSelectionContextMenuItems(MenuFlyout menu, bool hasSelection)
        {
            menu.Items.Add(CreateContextMenuItem(
                "Select all",
                SelectAllFromContextMenu,
                "select_all.svg",
                acceleratorKey: VirtualKey.A,
                acceleratorModifiers: VirtualKeyModifiers.Control,
                acceleratorText: "Ctrl+A"));
            menu.Items.Add(CreateContextMenuItem(
                "Clear selection",
                ClearSelectionFromContextMenu,
                "clear_selection.svg",
                hasSelection,
                acceleratorKey: VirtualKey.D,
                acceleratorModifiers: VirtualKeyModifiers.Control,
                acceleratorText: "Ctrl+D"));
        }

        private void SelectAllRowsFromContextMenu()
        {
            SelectAllRows();
            UpdateFooterTextSelected();
            RequestRender();
            NotifyGridStateChanged("ContextMenu.SelectAllRows");
        }

        private void OpenFilterForActiveColumn()
        {
            var column = _ActiveCell?.Header ?? HeaderHover;
            var isFallbackFirst = false;
            if (column == null)
            {
                column = GetFirstFilterableColumn();
                isFallbackFirst = true;
            }

            if (column == null || !column.CanFilter)
            {
                return;
            }

            EnsureActiveCellForColumn(column);
            var preferRightEdge = isFallbackFirst && !IsColumnVisibleOnScreen(column);
            ShowFilter(column, preferRightEdge);
        }

        private void ApplyFilterByActiveCellValue()
        {
            var activeCell = _ActiveCell;
            if (activeCell == null)
            {
                var firstColumn = GetFirstFilterableColumn();
                if (firstColumn == null)
                {
                    return;
                }

                if ((_ItemsSourceFiltred?.Count ?? 0) == 0)
                {
                    return;
                }

                EnsureActiveCellForColumn(firstColumn);
                activeCell = _ActiveCell;
                if (activeCell == null)
                {
                    return;
                }
            }

            if (!TryBuildFilterRuleFromCell(activeCell.Header, activeCell.RowIndex, out var rule, out _)
                || rule == null)
            {
                return;
            }

            ApplyQuickCellFilter(rule);
        }

        private Column? GetFirstFilterableColumn()
        {
            return _Columns
                .Where(c => !c.IsHiden && c.CanFilter)
                .OrderBy(c => c.Index)
                .FirstOrDefault();
        }

        private void EnsureActiveCellForColumn(Column column)
        {
            if (_ActiveCell != null)
            {
                return;
            }

            var rowCount = _ItemsSourceFiltred?.Count ?? 0;
            if (rowCount == 0)
            {
                return;
            }

            _ActiveCell = new CellVector(column, 0);
            RequestRender();
        }

        private bool IsColumnVisibleOnScreen(Column column)
        {
            var left = column.LeftOnScreen;
            var right = column.LeftOnScreen + column.Width;
            return right > _IndexColWidth && left < ActualWidth;
        }

        private void SelectAllFromContextMenu()
        {
            SellectAll();
            UpdateFooterTextSelected();
            RequestRender();
            NotifyGridStateChanged("ContextMenu.SelectAll");
        }

        private void ClearSelectionFromContextMenu()
        {
            UnSellectAll();
            UpdateFooterTextSelected();
            RequestRender();
            NotifyGridStateChanged("ContextMenu.ClearSelection");
        }

        private MenuFlyoutItem CreateContextMenuItem(
            string text,
            Action onClick,
            Symbol iconSymbol,
            bool isEnabled = true,
            VirtualKey? acceleratorKey = null,
            VirtualKeyModifiers acceleratorModifiers = VirtualKeyModifiers.None,
            string? acceleratorText = null)
        {
            return CreateContextMenuItem(
                text,
                onClick,
                (IconElement)new SymbolIcon(iconSymbol),
                isEnabled,
                acceleratorKey,
                acceleratorModifiers,
                acceleratorText);
        }

        private MenuFlyoutItem CreateContextMenuItem(
            string text,
            Action onClick,
            string svgIconPath,
            bool isEnabled = true,
            VirtualKey? acceleratorKey = null,
            VirtualKeyModifiers acceleratorModifiers = VirtualKeyModifiers.None,
            string? acceleratorText = null)
        {
            return CreateContextMenuItem(
                text,
                onClick,
                CreateContextMenuSvgIcon(svgIconPath),
                isEnabled,
                acceleratorKey,
                acceleratorModifiers,
                acceleratorText);
        }

        private MenuFlyoutItem CreateContextMenuItem(
            string text,
            Action onClick,
            IconElement icon,
            bool isEnabled = true,
            VirtualKey? acceleratorKey = null,
            VirtualKeyModifiers acceleratorModifiers = VirtualKeyModifiers.None,
            string? acceleratorText = null)
        {
            var item = new MenuFlyoutItem
            {
                Text = text,
                IsEnabled = isEnabled,
                Icon = icon
            };

            if (acceleratorKey.HasValue)
            {
                item.KeyboardAccelerators.Add(new KeyboardAccelerator
                {
                    Key = acceleratorKey.Value,
                    Modifiers = acceleratorModifiers
                });
            }

            if (!string.IsNullOrWhiteSpace(acceleratorText))
            {
                item.KeyboardAcceleratorTextOverride = acceleratorText;
            }

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

        private static ImageIcon CreateContextMenuSvgIcon(string svgIconPath)
        {
            return new ImageIcon
            {
                Source = new SvgImageSource(new Uri($"{ContextMenuIconsBaseUri}{svgIconPath}"))
            };
        }

        private bool HasAnySelection()
        {
            return (_SelectedRows?.CountSelected() ?? 0) > 0 || _Columns.Any(x => x.isSelected);
        }

        private bool HasCopySelection()
        {
            return (_SelectedRows?.CountSelected() ?? 0) > 0 && _Columns.Any(x => x.isSelected);
        }

        private bool TryBuildFilterRuleFromCell(Point position, out FilterRule? rule, out string selectedValuePreview)
        {
            var column = GetColumnAtPosition(position);
            var rowIndex = GetRowIndexAtPosition(position);
            return TryBuildFilterRuleFromCell(column, rowIndex, out rule, out selectedValuePreview);
        }

        private bool TryBuildFilterRuleFromCell(Column? column, int rowIndex, out FilterRule? rule, out string selectedValuePreview)
        {
            rule = null;
            selectedValuePreview = "(empty)";

            if (column == null || !column.CanFilter || _ItemsSourceFiltred == null || _ItemsSourceFiltred.Count == 0 || column.PropertyInfo == null)
            {
                return false;
            }

            var item = _ItemsSourceFiltred[rowIndex];
            if (item == null)
            {
                return false;
            }

            var value = column.PropertyInfo.GetValue(item);
            if (value == null || (value is string text && string.IsNullOrWhiteSpace(text)))
            {
                rule = new FilterRule(column.Name, FilterComparison.IsEmpty, true);
                selectedValuePreview = "(empty)";
                return true;
            }

            rule = new FilterRule(column.Name, FilterComparison.Equals, value);
            selectedValuePreview = FormatMenuValuePreview(value);
            return true;
        }

        private void ApplyQuickCellFilter(FilterRule rule)
        {
            var nextRules = _filterRules
                .Where(r => !r.ColumnName.Equals(rule.ColumnName, StringComparison.OrdinalIgnoreCase))
                .ToList();

            nextRules.Add(rule);
            ApplyColumnFiltersFromFlyout(nextRules);
        }

        private void SelectColumnFromContextMenu(Column column)
        {
            if (column.isSelected)
            {
                return;
            }

            column.isSelected = true;
            UpdateFooterTextSelected();
            RequestRender();
            NotifyGridStateChanged("ContextMenu.SelectColumn");
        }

        private void UnselectColumnFromContextMenu(Column column)
        {
            if (!column.isSelected)
            {
                return;
            }

            column.isSelected = false;
            UpdateFooterTextSelected();
            RequestRender();
            NotifyGridStateChanged("ContextMenu.UnselectColumn");
        }

        private static string FormatMenuValuePreview(object value)
        {
            var raw = Convert.ToString(value);
            if (string.IsNullOrWhiteSpace(raw))
            {
                return "(empty)";
            }

            var normalized = raw.Replace("\r", " ").Replace("\n", " ").Replace("\t", " ").Trim();
            var trimmed = TrimForMenu(normalized, 48);
            return $"\"{trimmed}\"";
        }

        private static string TrimForMenu(string text, int maxLength)
        {
            if (string.IsNullOrEmpty(text) || text.Length <= maxLength)
            {
                return text;
            }

            if (maxLength <= 3)
            {
                return "...";
            }

            return text.Substring(0, maxLength - 3) + "...";
        }
    }
}