using InABox.Core;
using InABox.Wpf;
using Syncfusion.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace InABox.DynamicGrid;

public interface IDynamicGridUIComponentParent : IBaseDynamicGrid
{
    bool IsRefreshing { get; }

    bool CanFilter();
    bool CanSort();

    DynamicGridRowStyleSelector RowStyleSelector { get; }

    void BeforeSelection(CancelEventArgs cancel);

    void SelectItems(CoreRow[] rows);

    void HandleKey(KeyEventArgs args);

    void LoadColumnsMenu(ContextMenu menu);

    BaseEditor CustomiseEditor(DynamicGridColumn column, BaseEditor editor);

    void DoubleClickCell(CoreRow? row, DynamicColumnBase? column);
    void ExecuteActionColumn(DynamicActionColumn column, CoreRow[]? rows);
    void OpenColumnMenu(DynamicColumnBase column);

    void UpdateRecordCount(int count);
    public bool IsDirectEditMode();

    void DragOver(object sender, DragEventArgs e);
    void Drop(object sender, DragEventArgs e);
    void DragStart(object? sender, CoreRow[] rows);

    /// <summary>
    /// Move the given rows from where they are, inserting them at <paramref name="index"/>. (i.e., before the row at the given index).
    /// To insert at the end, set <paramref name="index"/> to the number of rows.
    /// </summary>
    /// <remarks>
    /// Only applicable if <typeparamref name="T"/> is <see cref="ISequenceable"/>.
    /// </remarks>
    void MoveRows(CoreRow[] rows, int index);
    
    void UIFilterChanged(object sender);

    void UpdateData(CoreRow row, string changedColumn, Dictionary<CoreColumn, object?> updates);
}

public interface IDynamicGridUIComponentParent<T> : IDynamicGrid<T>, IDynamicGridUIComponentParent
    where T : BaseObject, new()
{
    void UpdateData(T obj, CoreRow row, string changedColumn, Dictionary<CoreColumn, object?> updates);
    void EntityChanged(T obj, CoreRow row, string changedColumn, Dictionary<string, object?> changes);
}

public interface IDynamicGridUIComponent
{
    IDynamicGridUIComponentParent Parent { get; set; }

    FrameworkElement Control { get; }
    
    CoreRow[] SelectedRows { get; set; }

    double RowHeight { get; set; }
    double HeaderRowHeight { get; set; }
    int DesiredWidth();

    /// <summary>
    /// Do any required updates when the options list is changed.
    /// </summary>
    /// <returns>Whether the columns need to be reloaded.</returns>
    bool OptionsChanged();

    void UpdateRow(CoreRow row);
    void UpdateCell(CoreRow row, string column, object? value);
    void UpdateCell(CoreRow row, DynamicColumnBase column);

    void AddVisualFilter(string column, string value, FilterType filtertype = FilterType.Contains);
    List<Tuple<string, Func<CoreRow, bool>>> GetFilterPredicates();

    void BeforeRefresh();
    void RefreshColumns(IEnumerable<DynamicColumnBase> columns, DynamicGridColumnGroupings groupings);
    void RefreshData(CoreTable data);
    void AddPage(IEnumerable<CoreRow> page);
    void InvalidateRow(CoreRow row);

    void ScrollIntoView(CoreRow row);
    CoreRow[] GetVisibleRows();
}

public interface IDynamicGridUIComponent<T> : IDynamicGridUIComponent
    where T : BaseObject, new()
{
    new IDynamicGridUIComponentParent<T> Parent { get; set; }

    IDynamicGridUIComponentParent IDynamicGridUIComponent.Parent
    {
        get => Parent;
        set => Parent = (IDynamicGridUIComponentParent<T>)value;
    }
}