using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;

namespace Sonex.Client.UserControls.DataGridView
{
    public sealed partial class DataGridView
    {
        public class Column
        {
            public Column(DataGridView root, IFilterFlyout filterFlyout) 
            {
                Root = root;
                FilterFlyout = filterFlyout;
                if (FilterFlyout.XamlRoot == null)
                    FilterFlyout.XamlRoot = Root._Canvas.XamlRoot;
            }
            public DataGridView Root {  get; set; }
            public IFilterFlyout FilterFlyout { get; set; }
            public PropertyInfo PropertyInfo { get; set; }
            public bool CanSort { get; set; } = true;
            public bool CanFilter { get; set; } = true;
            public bool CanResize { get; set; } = true;
            public bool CanPin { get; set; } = true;
            public bool IsPinned => Index < 0;
            public int Index { get; set; }
            public string Title { get; set; }
            public double Width { get; set; }
            public float _Width => (float)Width;
            public double CellHeight => Root.RowsHeight;
            public float _CellHeight => Root._RowsHeight;
            public double Left { get; set; }
            public float _Left => (float)Left;
            public double LeftOnScreen { get; internal set; }
            public float _LeftOnScreen => (float)LeftOnScreen;
            public CanvasTextFormat TextFormat { get; set; }
            public bool isSelected { get; set; }
            public bool IsHiden => Index >= 1000000;
            public bool IsOnScreen { get; set; }
            public bool SortDescending { get; private set; }
            public bool IsCellSelected(int rowIndex) => (isSelected && Root._SelectedRows.Has(rowIndex));
            public bool IsCellDrag(int rowIndex) => Root._SelectRange.IsInclude(this, rowIndex);
            public bool IsRowFocus(int rowIndex) => Root._ActiveCell != null && Root._ActiveCell.RowIndex == rowIndex;
            public bool IsCellFocus(int rowIndex) => IsRowFocus(rowIndex) && Root?._ActiveCell?.ColumnIndex == Index ;
            public void ToggleSortDirection()
            {
                SortDescending = !SortDescending;
            }
            public virtual void OnDrawCell(CanvasDrawingSession ds, int rowIndex)
            {
                bool isCellSelected = IsCellSelected(rowIndex);
                bool isDrag = IsCellDrag(rowIndex);
                bool isRowFocus = IsRowFocus(rowIndex);
                bool isCellFocus = IsCellFocus(rowIndex);
                string? value = GetValue(rowIndex);


                // wypełnianie zaznaczonych komórek
                ds.FillRectangle(0f, 0f, _Width, _CellHeight, Root.CellBackColor.Color);

                if (IsPinned)
                {
                    ds.FillRectangle(0f, 0f, _Width-1, _CellHeight-1, Root.ActiveRowFillColor.Color);
                }
                if (isCellSelected)
                {
                    ds.FillRectangle(0f, 0f, _Width - 1, _CellHeight - 1, Root.SelectedCallFillColor);
                }
                // wypełnianie przeciąganych komórek (selectrange)
                if (isDrag)
                {
                    ds.FillRectangle(0f, 0, _Width - 1, _CellHeight - 1, Root._SelectRange.Remove ? Root.UnSelectRangeColor : Root.SelectRangeColor);
                }
                if (isCellFocus)
                {
                    ds.FillRectangle(0f, 0f, _Width - 1, _CellHeight - 1, Root.ActiveCellColor);
                }

                if (isRowFocus && !isCellFocus && !isCellSelected && !isDrag)
                {
                    ds.FillRectangle(0f, 0f, _Width - 1, _CellHeight - 1, Root.ActiveRowFillColor.Color);
                }
                if (!string.IsNullOrEmpty(value))
                {
                    ds.DrawText(value.ToString(), 6f, 0f, _Width - 13f, _CellHeight-1, Root.indexTextColor.Color, TextFormat);
                }
            }

            public virtual string? GetValue(int rowIndex)
            {
                if (Root._ItemsSourceFiltred == null) return null;
                if (rowIndex < 0 || rowIndex >= Root._ItemsSourceFiltred.Count) return null;

                if (PropertyInfo == null) return null;
                var item = Root._ItemsSourceFiltred[rowIndex];
                if (item == null) return null;
                var value = PropertyInfo.GetValue(item);
                var t = PropertyInfo.PropertyType.UnderlyingSystemType;

                if (t == typeof(string)) return ((string?)value)?.ToString() ?? null;

                if (t == typeof(int))
                    return ((int?)value)?.ToString("n0") ?? null;

                if (t == typeof(uint))
                    return ((uint?)value)?.ToString("n0") ?? null;

                if (t == typeof(long))
                    return ((long?)value)?.ToString("n0") ?? null;

                if (t == typeof(ulong))
                    return ((ulong?)value)?.ToString("n0") ?? null;

                if (t == typeof(short))
                    return ((short?)value)?.ToString("n0") ?? null;

                if (t == typeof(ushort))
                    return ((short?)value)?.ToString("n0") ?? null;



                if (t == typeof(float))
                    return ((float?)value)?.ToString("n2") ?? null;

                if (t == typeof(double))
                    return ((double?)value)?.ToString("n2") ?? null;

                if (t == typeof(decimal))
                    return ((decimal?)value)?.ToString("n2") ?? null;

                if (t == typeof(bool))
                    return value == null ? null : ((bool)value ? "Yes" : "No");

                if (t == typeof(char))
                    return ((char?)value)?.ToString() ?? null;

                if (t == typeof(DateTime))
                    return ((DateTime?)value)?.ToString("dd-MM-yyyy HH:mm:ss") ?? null;

                if (t == typeof(DateOnly))
                    return ((DateOnly?)value)?.ToString("dd-MM-yyyy") ?? null;

                if (t == typeof(TimeOnly))
                    return ((TimeOnly?)value)?.ToString("HH:mm:ss") ?? null;

                if (t == typeof(TimeSpan))
                    return value is TimeSpan ts ? ts.ToString(@"d\.hh\:mm\:ss").Replace(".", "d ") : null;

                if (t == typeof(Guid))
                    return ((Guid?)value)?.ToString("N") ?? null;

                if (t == typeof(byte[]))
                    return value is byte[] bytes
                        ? Convert.ToHexString(bytes)
                        : null;

                return value?.ToString();
            }
            public async Task SortAsync()
            {
                await Task.Run(() =>
                {
                    Sort(); // Twoja metoda sortująca in-place
                });

            }
            public virtual void Sort()
            {
                if (!CanSort) return;

                SortDescending = !SortDescending;

                if (!CanSort) return;
                if (Root._ItemsSourceFiltred == null || Root._ItemsSourceFiltred.Count < 2) return;
                if (PropertyInfo == null) return;

                Root.UnSellectAll();


                var src = Root._ItemsSourceFiltred;

                // 1) tablica
                if (src is object[] arr)
                {
                    Array.Sort(arr, CompareObjects);
                    return;
                }

                // 2) List<T> (np. List<DapperTestTypesRow>) – in-place, bez kopii
                var t = src.GetType();
                if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>))
                {
                    // List<T>.Sort(Comparison<T>)
                    var itemType = t.GetGenericArguments()[0];
                    var comparisonType = typeof(Comparison<>).MakeGenericType(itemType);

                    var sortMethod = t.GetMethod("Sort", new[] { comparisonType });
                    if (sortMethod == null)
                        throw new InvalidOperationException("Nie znaleziono List<T>.Sort(Comparison<T>).");

                    var del = Delegate.CreateDelegate(comparisonType, this,
                        GetType().GetMethod(nameof(CompareItemsTyped), BindingFlags.Instance | BindingFlags.NonPublic)!);

                    sortMethod.Invoke(src, new object[] { del });
                    return;
                }

                // 3) inne IList – brak bezpiecznego sort in-place bez kopii
                throw new NotSupportedException("Sortowanie bez kopii wspiera tylko List<T> oraz object[].");
            }

            // Comparison<T> będzie wołało tę metodę (parametry muszą być zgodne: (T a, T b))
            private int CompareItemsTyped(object? a, object? b) => CompareObjects(a, b);

            private int CompareObjects(object? a, object? b)
            {
                if (a is null) return b is null ? 0 : 1;
                if (b is null) return -1;

                var av = PropertyInfo!.GetValue(a);
                var bv = PropertyInfo!.GetValue(b);

                if (av is null) return bv is null ? 0 : 1;
                if (bv is null) return -1;

                int result;

                if (av is IComparable ca && bv.GetType() == av.GetType())
                    result = ca.CompareTo(bv);
                else
                    result = StringComparer.CurrentCulture.Compare(av.ToString(), bv.ToString());

                return SortDescending ? -result : result;
            }

            public void ShowFilter()
            {
                if (FilterFlyout.IsOpen)
                {
                    //FilterFlyout.Hide();
                    return;
                }
                var content = FilterFlyout.Content as FrameworkElement;
                double flyoutW = 300; // fallback
                if (content != null)
                {
                    content.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                    flyoutW = content.DesiredSize.Width;
                }
                double xMin = (flyoutW * 0.5d) + 10;
                double xMax = Root._Canvas.ActualWidth - 10 - (flyoutW * 0.5d);
                double x = 0;
                if (xMin < xMax)
                {
                    x = Math.Clamp((LeftOnScreen + (Width * 0.5d)), xMin, xMax);
                }
                else
                {
                    x = Root._Canvas.ActualWidth * 0.5d;
                }

                FlyoutShowOptions showOptions = new FlyoutShowOptions()
                {

                    Position = new Point(x, Root._HeaderHeight + 8),
                    ShowMode = FlyoutShowMode.Transient,
                    Placement = FlyoutPlacementMode.Bottom
                };

                FilterFlyout.ShowAt(Root._Canvas, showOptions);
               
            }
        }
    }
}
