using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using System;
using System.Diagnostics;
using Windows.Foundation;
using Windows.System;
using Windows.UI;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace Sonex.Client.Controls.DataGridView;

// Odpowiedzialnosc pliku: inicjalizacja kontrolki, podpianie eventow i logika cyklu zycia.

public sealed partial class DataGridView : UserControl
{
    SolidColorBrush backColor = new();
    SolidColorBrush HeaderBackColor = new();
    SolidColorBrush HeaderBackColorPressed = new();
    Color HeaderIconColor = new();
    Color HoverHeaderIconColor = new();
    Color SelectedHeaderIconColor = new();

    SolidColorBrush textColor = new();
    SolidColorBrush borderColor = new();
    SolidColorBrush indexBackColor = new();
    SolidColorBrush indexTextColor = new();
    Color selectedIndexTextColor = new();
    SolidColorBrush indexBorderColor = new();
    SolidColorBrush ActiveCellborderColor = new();
    SolidColorBrush ActiveRowFillColor = new();
    Color SelectedCallFillColor = new();
    Color SelectRangeColor = new();
    Color UnSelectRangeColor = new();
    Color ActiveCellColor = new();
    SmoothStepScroller _ScrollMoverVertical;
    SmoothStepScroller _ScrollMoverHorizontal;
    SolidColorBrush CellBackColor;
    Color LoadingBackColor;
    private readonly FilterFlyout _filterFlyout;
    private bool _isReleased;
    public DataGridView()
    {
        InicjalizeColors();
        InitializeComponent();
        _filterFlyout = new FilterFlyout();
        Restart();
        _SelectedRows = new(0);
        _Canvas.Draw += Canvas_Draw;
        _Canvas.Loaded += Canvas_Loaded;
        _Canvas.SizeChanged += Canvas_SizeChanged;
        _ScrollHorizontal.ValueChanged += _ScrollHorizontal_ValueChanged;
        _ScrollVertical.ValueChanged += _ScrollVertical_ValueChanged;
        _Canvas.PointerExited += _Canvas_PointerExited;
        _Canvas.PointerEntered += _Canvas_PointerEntered;
        _Canvas.GotFocus += _Canvas_GotFocus;
        _Canvas.PreviewKeyDown += _Canvas_KeyDown;
        _Canvas.PreviewKeyUp += _Canvas_KeyUp;
        _Canvas.LostFocus += _Canvas_LostFocus; ;
        _ScrollHorizontal.PreviewKeyDown += _Canvas_KeyDown;
        _ScrollHorizontal.PreviewKeyUp += _Canvas_KeyUp;
        PreviewKeyDown += _Canvas_KeyDown;
        PreviewKeyUp += _Canvas_KeyUp;
        _ScrollVertical.PreviewKeyDown += _Canvas_KeyDown;
        _ScrollVertical.PreviewKeyUp += _Canvas_KeyUp;
        _CornerMenuButton.PreviewKeyDown += _Canvas_KeyDown;
        _CornerMenuButton.PreviewKeyUp += _Canvas_KeyUp;

        GettingFocus += DataGridView_GettingFocus;
        GotFocus += DataGridView_GotFocus;
        LostFocus += DataGridView_LostFocus;


        this.ActualThemeChanged += DataGridView_ActualThemeChanged;

        _Canvas.PointerWheelChanged += _Canvas_PointerWheelChanged;
        _ScrollHorizontal.SmallChange = 20;
        _ScrollHorizontal.LargeChange = 1;
        _Canvas.PointerMoved += _Canvas_PointerMoved;
        _Canvas.PointerPressed += _Canvas_PointerPressed;
        _Canvas.PointerReleased += _Canvas_PointerReleased;

        _ScrollVertical.SmallChange = 1;
        _ScrollVertical.LargeChange = 1;

        Unloaded += DataGridView_Unloaded;

        _ScrollHorizontal.GotFocus += _ScrollHorizontal_GotFocus;
        _ScrollVertical.GotFocus += _ScrollVertical_GotFocus;
        _ScrollMoverVertical = new SmoothStepScroller(_ScrollVertical, step: 1, intervalMs: 20);
        _ScrollMoverHorizontal = new SmoothStepScroller(_ScrollHorizontal, step: 20, intervalMs: 20);
        UpdateCornerMenuButtonLayout();
        InitializeGlobalViewDensity();
        CaptureGridStateSnapshot();



    }

    private void _ScrollVertical_GotFocus(object sender, RoutedEventArgs e)
    {
        _Canvas.Focus(FocusState.Programmatic);

    }
    private void _ScrollHorizontal_GotFocus(object sender, RoutedEventArgs e)
    {

        _Canvas.Focus(FocusState.Programmatic);
    }
    private void _Canvas_LostFocus(object sender, RoutedEventArgs e)
    {
        var focused = FocusManager.GetFocusedElement(this.XamlRoot);

        Debug.WriteLine($"_Canvas_LostFocus for: {focused?.GetType().Name ?? "null"}");
        if (focused?.GetType().Name == "ScrollViewer")
        {
            _Canvas.Focus(FocusState.Programmatic);
        }
    }

    private void _Canvas_PointerEntered(object sender, PointerRoutedEventArgs e)
    {
        Debug.WriteLine("_Canvas_PointerEntered");
        _Canvas.Focus(FocusState.Programmatic);
    }

    private void _Canvas_GotFocus(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine($"_Canvas_GotFocus");
    }

    private void DataGridView_GotFocus(object sender, RoutedEventArgs e)
    {
        _Canvas.Focus(FocusState.Programmatic);
    }

    private void DataGridView_LostFocus(object sender, RoutedEventArgs e)
    {
    }

    private void DataGridView_GettingFocus(UIElement sender, GettingFocusEventArgs args)
    {
        
    }





    private void InicjalizeColors()
    {
        backColor = (SolidColorBrush)Application.Current.Resources["SolidBackgroundFillColorQuarternaryBrush"];
        HeaderBackColor = (SolidColorBrush)Application.Current.Resources["SolidBackgroundFillColorTertiaryBrush"];
        textColor = (SolidColorBrush)Application.Current.Resources["TextFillColorPrimaryBrush"];
        borderColor = (SolidColorBrush)Application.Current.Resources["SurfaceStrokeColorDefaultBrush"];
        indexBackColor = (SolidColorBrush)Application.Current.Resources["SolidBackgroundFillColorTertiaryBrush"];
        indexTextColor = (SolidColorBrush)Application.Current.Resources["TextFillColorSecondaryBrush"];
        indexBorderColor = (SolidColorBrush)Application.Current.Resources["ControlStrongStrokeColorDefaultBrush"];
        selectedIndexTextColor = (Color)Application.Current.Resources["SystemAccentColorDark3"];
        selectedIndexTextColor.A = 190;
        ActiveCellborderColor = (SolidColorBrush)Application.Current.Resources["AccentFillColorDefaultBrush"];
        ActiveRowFillColor = (SolidColorBrush)Application.Current.Resources["ControlAltFillColorSecondaryBrush"];
        SelectedCallFillColor = (Color)Application.Current.Resources["SystemAccentColorLight2"];
        SelectedCallFillColor.A = 40;
        SelectRangeColor = (Color)Application.Current.Resources["SystemAccentColorLight2"];
        SelectRangeColor.A = 30;
        UnSelectRangeColor = ((SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"]).Color;
        UnSelectRangeColor.A = 20;
        ActiveCellColor = (Color)Application.Current.Resources["SystemAccentColorLight2"];
        ActiveCellColor.A = 60;
        CellBackColor = (SolidColorBrush)Application.Current.Resources["SolidBackgroundFillColorQuarternaryBrush"];
        LoadingBackColor = ((SolidColorBrush)Application.Current.Resources["SolidBackgroundFillColorQuarternaryBrush"]).Color;
        LoadingBackColor.A = 160;
        HeaderIconColor = ((SolidColorBrush)Application.Current.Resources["SurfaceStrokeColorDefaultBrush"]).Color;
        HeaderIconColor.A = 100;
        HoverHeaderIconColor = (Color)Application.Current.Resources["SystemAccentColorDark2"];
        SelectedHeaderIconColor = (Color)Application.Current.Resources["SystemAccentColorDark1"];
        HeaderBackColorPressed = (SolidColorBrush)Application.Current.Resources["SystemControlPageBackgroundAltMediumBrush"];
    }

    private void _Canvas_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
    {
        var p = e.GetCurrentPoint(_Canvas);
        if (p == null) return;

        var now = Environment.TickCount64;
        var dt = _lastWheelTick == 0 ? 999.0 : (now - _lastWheelTick);
        _lastWheelTick = now;

        if (p.Position.Y <= HeaderHeight || e.KeyModifiers.HasFlag(VirtualKeyModifiers.Shift))
        {
            var step = ApplyWheel(ref _velH, p.Properties.MouseWheelDelta, baseStep: 5.0, dtMs: 10);

            _ScrollHorizontal.Value = Math.Clamp(
                _ScrollHorizontal.Value + step,
                _ScrollHorizontal.Minimum,
                _ScrollHorizontal.Maximum
            );
        }
        else
        {
            var step = ApplyWheel(ref _velV, p.Properties.MouseWheelDelta, baseStep: 1.0, dtMs: dt);

            _ScrollVertical.Value = Math.Clamp(
                _ScrollVertical.Value + step,
                _ScrollVertical.Minimum,
                _ScrollVertical.Maximum
            );
        }
    }
    private long _lastWheelTick;
    private double _velV; // "prędkość" pionowa
    private double _velH; // "prędkość" pozioma
    private static double SmoothMultiplier(double dtMs, double min = 1.0, double max = 10.0, double tau = 10.0)
    {
        // dt -> 0  => mult -> max
        // dt duże => mult -> min
        // tau steruje "jak szybko" rośnie (mniejszy tau = agresywniej)
        var x = Math.Exp(-dtMs / tau);          // 1..0
        return min + (max - min) * x;           // min..max
    }
    private double ApplyWheel(ref double velocity, int wheelDelta, double baseStep, double dtMs)
    {
        var dir = wheelDelta > 0 ? -1.0 : 1.0;

        var mult = SmoothMultiplier(dtMs, min: 1.0, max: 2.0, tau: 10.0);

        // impuls zależny od dt
        var impulse = dir * baseStep * mult;

        // inercja: wygładza + kumuluje szybkie kręcenie
        // dt=0..∞ => decay 0.0..1.0
        var decay = Math.Exp(-dtMs / 20.0);
        velocity = velocity * decay + impulse;

        return velocity;
    }

    private void DataGridView_ActualThemeChanged(FrameworkElement sender, object args)
    {
        InicjalizeColors();
        RequestRender();
    }


    private void Canvas_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        _NeedCalcHorizontalScroll = true;
        _NeedCalcVerticalScroll = true;
        _NeedCalcHeaders = true;
        RequestRender();
    }

    private void Canvas_Loaded(object sender, RoutedEventArgs e)
    {
        _isReleased = false;
        UpdateCornerMenuButtonLayout();
        ReapplyGlobalViewDensityIfAvailable();
    }
    private void DataGridView_Unloaded(object sender, RoutedEventArgs e)
    {
        _isReleased = true;
        ReleaseDataReferences();
        ReleaseFlyoutReferences();
        ReleaseCanvasReferences();
        ReleasePointerReferences();

        // 1️⃣ odpinanie eventów UI (opcjonalne, ale bezpieczne)
        _Canvas.Draw -= Canvas_Draw;
        _Canvas.Loaded -= Canvas_Loaded;
        _Canvas.SizeChanged -= Canvas_SizeChanged;
        _Canvas.PointerExited -= _Canvas_PointerExited;
        _Canvas.PreviewKeyDown -= _Canvas_KeyDown;
        _Canvas.PreviewKeyUp -= _Canvas_KeyUp;
        _Canvas.PointerWheelChanged -= _Canvas_PointerWheelChanged;
        _Canvas.PointerMoved -= _Canvas_PointerMoved;
        _Canvas.PointerPressed -= _Canvas_PointerPressed;
        _Canvas.PointerReleased -= _Canvas_PointerReleased;

        _ScrollHorizontal.ValueChanged -= _ScrollHorizontal_ValueChanged;
        _ScrollVertical.ValueChanged -= _ScrollVertical_ValueChanged;

        ActualThemeChanged -= DataGridView_ActualThemeChanged;
        GettingFocus -= DataGridView_GettingFocus;
        LostFocus -= DataGridView_LostFocus;
        Unloaded -= DataGridView_Unloaded;

        // 2️⃣ odczepienie danych
        _ItemsSourceFiltred = null;
        _itemType = null;

        // 3️⃣ reset stanu renderingu (opcjonalnie)
        _NeedCalcHorizontalScroll = true;
        _NeedCalcVerticalScroll = true;
        _NeedCalcHeaders = true;
        CleanupGlobalViewDensity();
        GC.Collect();
    }

    private void ReleaseDataReferences()
    {
        _ScrollMoverVertical?.Dispose();
        _ScrollMoverHorizontal?.Dispose();

        if (ItemsSource != null)
        {
            SetValue(ItemsSourceProperty, null);
        }

        if (ItemsType != null)
        {
            SetValue(ItemsTypeProperty, null);
        }

        _ItemsSource = null;
        _ItemsSourceFiltred = null;
        _itemType = null;
        Filter = null;
        _filterRules.Clear();

        _ActiveCell = null;
        _HoverCell = null;
        _LastPointer = null;
        _SelectRange.Clear();
        _SelectedRows = new IntBitSet(0);

        HeaderHover = null;
        ColumnResizing = null;
        ColumnDraging = null;
        _Columns.Clear();

        _FooterText1.Text = "Rows: 0/0";
        _FooterText2.Text = "Selected: 0 rows";
        _FooterText3.Text = "Filtered: 0 | Sum: 0.00";
    }

    private void ReleaseFlyoutReferences()
    {
        _filterFlyout.ReleaseOwner();

        try
        {
            _columnsFlyout?.Hide();
        }
        catch
        {
        }

        if (_columnsFlyoutListView != null)
        {
            _columnsFlyoutListView.DragItemsStarting -= ColumnsFlyoutListView_DragItemsStarting;
            _columnsFlyoutListView.DragItemsCompleted -= ColumnsFlyoutListView_DragItemsCompleted;
            _columnsFlyoutListView.Items.Clear();
            _columnsFlyoutListView.ItemsSource = null;
        }

        if (_columnsFlyout != null)
        {
            _columnsFlyout.Opened -= ColumnsFlyout_Opened;
            _columnsFlyout.Closed -= ColumnsFlyout_Closed;
        }

        if (_columnsFlyout?.Content is Border host)
        {
            host.Child = null;
        }

        if (_columnsFlyout != null)
        {
            _columnsFlyout.Content = null;
        }

        _columnsFlyout = null;
        _columnsFlyoutListView = null;
        _columnsFlyoutUpdating = false;
        _columnsFlyoutDragInProgress = false;
        _columnsFlyoutPinToggleInProgress = false;
    }

    private void ReleaseCanvasReferences()
    {
        try
        {
            _Canvas.GetType().GetMethod("RemoveFromVisualTree")?.Invoke(_Canvas, null);
        }
        catch
        {
        }

    }

    private void ReleasePointerReferences()
    {
        MouseLeftButtonDown = false;
        MouseRightButtonDown = false;
        _ActualArea = AreaType.None;
        _HandleArea = AreaType.None;
        CursorDefault();
    }

    internal void ShowFilter(Column column, bool preferRightEdge = false)
    {
        if (_filterFlyout.XamlRoot == null)
        {
            _filterFlyout.XamlRoot = _Canvas.XamlRoot;
        }

        _filterFlyout.Show(column, preferRightEdge);
    }

    private void _CornerMenuButton_Click(object sender, RoutedEventArgs e)
    {
        CursorDefault();
        var position = new Point(2d, Math.Max(2d, HeaderHeight + 2d));
        ShowContextMenu(position, AreaType.None);
        CursorDefault();
    }

    private void UpdateCornerMenuButtonLayout()
    {
        if (_CornerMenuButton == null)
        {
            return;
        }

        var width = Math.Max(0d, _IndexColWidth);
        var height = Math.Max(0d, HeaderHeight);
        var visibility = width > 0d && height > 0d ? Visibility.Visible : Visibility.Collapsed;

        if (Math.Abs(_CornerMenuButton.Width - width) > 0.001d)
        {
            _CornerMenuButton.Width = width;
        }

        if (Math.Abs(_CornerMenuButton.Height - height) > 0.001d)
        {
            _CornerMenuButton.Height = height;
        }

        if (_CornerMenuButton.Visibility != visibility)
        {
            _CornerMenuButton.Visibility = visibility;
        }
    }

}
