using ICSharpCode.AvalonEdit.Indentation;
using InABox.Clients;
using InABox.Core;
using sun.tools.tree;
using Syncfusion.Data;
using Syncfusion.UI.Xaml.Grid;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms.VisualStyles;

namespace InABox.DynamicGrid;

public interface IDynamicGridGridUIComponent
{
    IList<DynamicColumnBase> ColumnList { get; }

    int RowHeight { get; }
}

internal static class DynamicGridGridUIComponentExtension
{
    public static Dictionary<int, double> CalculateColumnSizes(this IDynamicGridGridUIComponent component, double width)
    {
        var fAvailWidth = width - (SystemParameters.VerticalScrollBarWidth);
        
        //if (Data.Rows.Count * (DataGrid.RowHeight + 1) + DataGrid.HeaderRowHeight > height + 0.5F)
        //if (height < DataGrid.AutoScroller.VScrollBar.Maximum)
        //    fAvailWidth -= (SystemParameters.VerticalScrollBarWidth + 0.75);


        double fCurWidth = 0.0F;
        var NumAutoCols = 0;

        var colWidths = new Dictionary<int, double>();
        for (var i = 0; i < component.ColumnList.Count; i++)
        {
            var col = component.ColumnList[i];
            if (col is DynamicImageColumn dic)
            {
                colWidths[i] = component.RowHeight;
                fCurWidth += colWidths[i];
            }
            else if (col is DynamicTextColumn dxc)
            {
                colWidths[i] = dxc.Width;
                if (dxc.Width != 0)
                    fCurWidth += Math.Max(0.0F, dxc.Width);
                else
                    NumAutoCols++;
            }
            else if (col is DynamicTemplateColumn dtc)
            {
                colWidths[i] = dtc.Width;
                if (dtc.Width != 0)
                    fCurWidth += Math.Max(0.0F, dtc.Width);
                else
                    NumAutoCols++;
            }
            else if (col is DynamicGridColumn dgc)
            {
                colWidths[i] = dgc.Width;
                if (dgc.Width != 0)
                    fCurWidth += Math.Max(0.0F, dgc.Width);
                else
                    NumAutoCols++;
            }
        }

        if (NumAutoCols > 0)
        {
            var fAutoWidth = (fAvailWidth - fCurWidth) / NumAutoCols;
            if (fAutoWidth < 100)
                fAutoWidth = 100;
            for (var i = 0; i < component.ColumnList.Count; i++)
                if (colWidths[i] == 0)
                    colWidths[i] = fAutoWidth;
        }

        return colWidths;
    }

    public static int DesiredWidth(this IDynamicGridGridUIComponent component)
    {
        var result = 0;
        for (var i = 0; i < component.ColumnList.Count; i++)
        {
            var col = component.ColumnList[i];
            if (col is DynamicActionColumn)
            {
                result += (int)component.RowHeight;
            }
            else if (col is DynamicGridColumn)
            {
                var dgc = (DynamicGridColumn)col;
                result += dgc.Width > 0 ? dgc.Width : 300;
            }
        }

        return result;
    }

    private static Dictionary<Type, Type>? _editorColumnMap;
    private static Dictionary<Type, Type> EditorColumnMap
    {
        get
        {
            _editorColumnMap ??= CoreUtils.Entities.Where(x => x.IsClass && x.HasInterface<IDynamicGridEditorColumn>()).Select(x =>
            {
                var def = x.GetSuperclassDefinition(typeof(DynamicGridEditorColumn<,,>))!;
                return new KeyValuePair<Type, Type>(def.GenericTypeArguments[0], x);
            }).ToDictionary();
            return _editorColumnMap;
        }
    }

    public static bool CreateEditorColumn<T>(this IDynamicGridGridUIComponent component, DynamicGridColumn column,
        [NotNullWhen(true)] out IDynamicGridEditorColumn? newcol)
    {
        newcol = null;

        if (EditorColumnMap.TryGetValue(column.Editor.GetType(), out var colType))
        {
            if(colType.GetInterfaceDefinition(typeof(IDynamicGridEditorColumn<>)) is Type genericInterface)
            {
                newcol = Activator.CreateInstance(colType.MakeGenericType(typeof(T)), column) as IDynamicGridEditorColumn;
            }
            else
            {
                newcol = Activator.CreateInstance(colType, column) as IDynamicGridEditorColumn;
            }
            if(newcol is IDynamicGridEditorColumn gridCol)
            {
                gridCol.UpdateUIComponent(component);
            }
            return newcol is not null;
        }
        else
        {
            return false;
        }
    }

    public static bool CreateEditorColumn(this IDynamicGridGridUIComponent component, DynamicGridColumn column,
        [NotNullWhen(true)] out IDynamicGridEditorColumn? newcol)
    {
        newcol = null;

        if (EditorColumnMap.TryGetValue(column.Editor.GetType(), out var colType))
        {
            if(colType.GetInterfaceDefinition(typeof(IDynamicGridEditorColumn<>)) is not Type genericInterface)
            {
                newcol = Activator.CreateInstance(colType, column) as IDynamicGridEditorColumn;
            }
            if(newcol is IDynamicGridEditorColumn gridCol)
            {
                gridCol.UpdateUIComponent(component);
            }
            return newcol is not null;
        }
        else
        {
            return false;
        }
    }

    private static bool FilterByPredicate(CoreRow row, string column, FilterPredicate predicate)
    {
        var value = row[column];
        var vStr = value?.ToString()?.ToLower() ?? "";
        var pValue = predicate.FilterValue;
        var pStr = pValue?.ToString()?.ToLower() ?? "";
        return predicate.FilterType switch
        {
            FilterType.Contains => vStr.Contains(pStr),
            FilterType.EndsWith => vStr.EndsWith(pStr),
            FilterType.Equals => vStr.Equals(pStr),
            FilterType.GreaterThan => vStr.CompareTo(pStr) > 0,
            FilterType.GreaterThanOrEqual => vStr.CompareTo(pStr) >= 0,
            FilterType.LessThan => vStr.CompareTo(pStr) < 0,
            FilterType.LessThanOrEqual => vStr.CompareTo(pStr) <= 0,
            FilterType.NotContains => !vStr.Contains(pStr),
            FilterType.NotEndsWith => !vStr.EndsWith(pStr),
            FilterType.NotEquals => !vStr.Equals(pStr),
            FilterType.NotStartsWith => !vStr.StartsWith(pStr),
            FilterType.StartsWith => vStr.StartsWith(pStr),
            _ => true,
        };
    }

    public static Func<CoreRow, bool>? ConvertColumnPredicates(DynamicGridColumn gridColumn, IEnumerable<FilterPredicate> predicates)
    {
        Func<CoreRow, bool>? rowPredicate = null;
        foreach (var predicate in predicates)
        {
            var p = (CoreRow row) => FilterByPredicate(row, gridColumn.ColumnName, predicate);
            if(rowPredicate is null)
            {
                rowPredicate = p;
            }
            else
            {
                var prevP = rowPredicate;
                if(predicate.PredicateType == PredicateType.And)
                {
                    rowPredicate = r => prevP(r) && p(r);
                }
                else
                {
                    rowPredicate = r => prevP(r) || p(r);
                }
            }
        }
        return rowPredicate;
    }
}
