using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
using System;
using System.Collections;
using System.Collections.Generic;

namespace Sonex.Client.Controls.DataGridView;

[ContentProperty(Name = nameof(HeaderLeftContent))]
public sealed partial class DataGridViewPanel : UserControl
{
    public static readonly DependencyProperty HeaderLeftContentProperty =
        DependencyProperty.Register(
            nameof(HeaderLeftContent),
            typeof(object),
            typeof(DataGridViewPanel),
            new PropertyMetadata(null, OnHeaderLeftContentChanged));

    public static readonly DependencyProperty ItemsTypeProperty =
        DependencyProperty.Register(
            nameof(ItemsType),
            typeof(Type),
            typeof(DataGridViewPanel),
            new PropertyMetadata(null, OnItemsTypeChanged));

    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register(
            nameof(ItemsSource),
            typeof(IList),
            typeof(DataGridViewPanel),
            new PropertyMetadata(null, OnItemsSourceChanged));

    public static readonly DependencyProperty HeaderHeightProperty =
        DependencyProperty.Register(
            nameof(HeaderHeight),
            typeof(double),
            typeof(DataGridViewPanel),
            new PropertyMetadata(22d, OnHeaderHeightChanged));

    public static readonly DependencyProperty RowsHeightProperty =
        DependencyProperty.Register(
            nameof(RowsHeight),
            typeof(double),
            typeof(DataGridViewPanel),
            new PropertyMetadata(24d, OnRowsHeightChanged));

    public static readonly DependencyProperty LoadingRingProperty =
        DependencyProperty.Register(
            nameof(LoadingRing),
            typeof(bool),
            typeof(DataGridViewPanel),
            new PropertyMetadata(false, OnLoadingRingChanged));

    public static readonly DependencyProperty RefreshOnLoadedProperty =
        DependencyProperty.Register(
            nameof(RefreshOnLoaded),
            typeof(bool),
            typeof(DataGridViewPanel),
            new PropertyMetadata(false));

    public static readonly DependencyProperty RefreshButtonEnabledProperty =
        DependencyProperty.Register(
            nameof(RefreshButtonEnabled),
            typeof(bool),
            typeof(DataGridViewPanel),
            new PropertyMetadata(true, OnRefreshButtonEnabledChanged));

    public DataGridViewPanel()
    {
        InitializeComponent();
        HeaderLeftContentPresenter.Content = HeaderLeftContent;
        RefreshButton.IsEnabled = RefreshButtonEnabled;
        Loaded += DataGridViewPanel_Loaded;
    }

    public DataGridView DataGrid => InnerDataGrid;

    public object? HeaderLeftContent
    {
        get => GetValue(HeaderLeftContentProperty);
        set => SetValue(HeaderLeftContentProperty, value);
    }

    public Type? ItemsType
    {
        get => (Type?)GetValue(ItemsTypeProperty);
        set => SetValue(ItemsTypeProperty, value);
    }

    public IList? ItemsSource
    {
        get => (IList?)GetValue(ItemsSourceProperty);
        set => SetValue(ItemsSourceProperty, value);
    }

    public double HeaderHeight
    {
        get => (double)GetValue(HeaderHeightProperty);
        set => SetValue(HeaderHeightProperty, value);
    }

    public double RowsHeight
    {
        get => (double)GetValue(RowsHeightProperty);
        set => SetValue(RowsHeightProperty, value);
    }

    public bool LoadingRing
    {
        get => (bool)GetValue(LoadingRingProperty);
        set => SetValue(LoadingRingProperty, value);
    }

    public bool RefreshOnLoaded
    {
        get => (bool)GetValue(RefreshOnLoadedProperty);
        set => SetValue(RefreshOnLoadedProperty, value);
    }

    public bool RefreshButtonEnabled
    {
        get => (bool)GetValue(RefreshButtonEnabledProperty);
        set => SetValue(RefreshButtonEnabledProperty, value);
    }

    public event EventHandler? RefreshRequested;
    public event EventHandler<DataGridView.DataGridStateChangedEventArgs>? OnChangeActiveCell;
    public event EventHandler<DataGridView.DataGridStateChangedEventArgs>? OnChangeActiveRow;
    public event EventHandler<DataGridView.DataGridStateChangedEventArgs>? OnChangeSelection;

    public List<object> GetSelectedItems()
    {
        return InnerDataGrid.GetSelectedItems();
    }

    public List<T> GetSelectedItems<T>()
    {
        return InnerDataGrid.GetSelectedItems<T>();
    }

    private static void OnHeaderLeftContentChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        if (dependencyObject is DataGridViewPanel panel)
        {
            panel.HeaderLeftContentPresenter.Content = args.NewValue;
        }
    }

    private static void OnItemsTypeChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        if (dependencyObject is DataGridViewPanel panel)
        {
            panel.InnerDataGrid.ItemsType = (Type?)args.NewValue;
        }
    }

    private static void OnItemsSourceChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        if (dependencyObject is DataGridViewPanel panel)
        {
            panel.InnerDataGrid.ItemsSource = (IList?)args.NewValue;
        }
    }

    private static void OnHeaderHeightChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        if (dependencyObject is DataGridViewPanel panel)
        {
            panel.InnerDataGrid.HeaderHeight = (double)args.NewValue;
        }
    }

    private static void OnRowsHeightChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        if (dependencyObject is DataGridViewPanel panel)
        {
            panel.InnerDataGrid.RowsHeight = (double)args.NewValue;
        }
    }

    private static void OnLoadingRingChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        if (dependencyObject is DataGridViewPanel panel)
        {
            panel.InnerDataGrid.LoadingRing = (bool)args.NewValue;
        }
    }

    private static void OnRefreshButtonEnabledChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        if (dependencyObject is DataGridViewPanel panel)
        {
            panel.RefreshButton.IsEnabled = (bool)args.NewValue;
        }
    }

    private void DataGridViewPanel_Loaded(object sender, RoutedEventArgs e)
    {
        if (RefreshOnLoaded)
        {
            RefreshRequested?.Invoke(this, EventArgs.Empty);
        }
    }

    private void ExportButton_Click(object sender, RoutedEventArgs e)
    {
        InnerDataGrid.ShowExportMenu(ExportButton);
    }

    private void ColumnsButton_Click(object sender, RoutedEventArgs e)
    {
        InnerDataGrid.ShowColumnsFlyout(ColumnsButton);
    }

    private void FiltersButton_Click(object sender, RoutedEventArgs e)
    {
        InnerDataGrid.ShowFilters();
    }

    private void ClearFiltersButton_Click(object sender, RoutedEventArgs e)
    {
        InnerDataGrid.ClearFilters();
    }

    private void RefreshButton_Click(object sender, RoutedEventArgs e)
    {
        RefreshRequested?.Invoke(this, EventArgs.Empty);
    }

    private void InnerDataGrid_OnChangeActiveCell(object? sender, DataGridView.DataGridStateChangedEventArgs e)
    {
        OnChangeActiveCell?.Invoke(this, e);
    }

    private void InnerDataGrid_OnChangeActiveRow(object? sender, DataGridView.DataGridStateChangedEventArgs e)
    {
        OnChangeActiveRow?.Invoke(this, e);
    }

    private void InnerDataGrid_OnChangeSelection(object? sender, DataGridView.DataGridStateChangedEventArgs e)
    {
        OnChangeSelection?.Invoke(this, e);
    }
}
