using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using InABox.Configuration;
using InABox.Core;

namespace InABox.DynamicGrid;

public class DynamicGridColumns : List<DynamicGridColumn>, IGlobalConfigurationSettings, IUserConfigurationSettings
{
    public string GridName { get; set; }

    private static Dictionary<Type, List<DynamicGridColumn>> _columnscache = new Dictionary<Type, List<DynamicGridColumn>>();

    public DynamicGridColumns ExtractColumns(Type type)
    {
        if (!_columnscache.TryGetValue(type, out List<DynamicGridColumn>? value))
        {
            value = [];
            _columnscache[type] = value;

            var defaults = DefaultColumns.GetDefaultColumns(type);

            var properties = DatabaseSchema.Properties(type).OrderBy(x => x.Sequence);
            foreach (var prop in properties)
            {
                if ((prop.Editor != null && !(prop.Editor is NullEditor)) || prop.Required)
                {
                    var defaultCol = defaults.FirstOrDefault(x => x.Property == prop);
                    if(defaultCol is not null)
                    {
                        value.Add(DynamicGridColumn.FromCoreGridColumn(defaultCol));
                    }
                    else
                    {
                        
                        value.Add(new(prop));
                    }
                }
            }
        }
        AddRange(value);

        return this;
    }
    public static DynamicGridColumns ExtractColumns(Type type, IColumns columns)
    {
        var cols = new DynamicGridColumns();
        var master = new DynamicGridColumns().ExtractColumns(type);

        foreach (var col in columns)
        {
            var mc = master.FirstOrDefault(x => x.ColumnName.Equals(col.Property));
            if (mc != null && mc.Editor is not NullEditor && mc.Editor.Visible != Visible.Hidden)
                cols.Add(mc);
        }

        return cols;
    }

    public static DynamicGridColumn CreateColumn<TType>(
        Expression<Func<TType, object?>> member,
        int? width = null,
        string? caption = null,
        string? format = null,
        Alignment? alignment = null)
    {
        var prop = DatabaseSchema.Property(member);
        var col = new DynamicGridColumn
        {
            ColumnName = prop.Name,
            Width = width ?? prop.Editor.Width,
            Alignment = alignment ?? prop.Editor.Alignment,
            Format = format ?? prop.Editor.Format,
            Editor = prop.Editor.CloneEditor(),
            Caption = caption ?? prop.Caption
        };
        return col;
    }

    public DynamicGridColumn Add<TType>(
        Expression<Func<TType, object?>> member,
        int? width = null,
        string? caption = null,
        string? format = null,
        Alignment? alignment = null
    )
    {
        var col = CreateColumn(member, width: width, caption: caption, format: format, alignment: alignment);
        Add(col);
        return col;
    }
    
    public DynamicGridColumn Insert<TType>(
        int index,
        Expression<Func<TType, object?>> member,
        int? width = null,
        string? caption = null,
        string? format = null,
        Alignment? alignment = null
    )
    {
        var col = CreateColumn(member, width: width, caption: caption, format: format, alignment: alignment);
        Insert(index,col);
        return col;
    }

    public DynamicGridColumns AddFluent<TType>(
        Expression<Func<TType, object?>> member,
        int? width = null,
        string? caption = null,
        string? format = null,
        Alignment? alignment = null
    )
    {
        Add(member, width: width, caption: caption, format: format, alignment: alignment);
        return this;
    }
}

public class DynamicGridColumns<T> : DynamicGridColumns
{
    public DynamicGridColumn Add(Expression<Func<T, object?>> member, int width, string caption, string format, Alignment alignment)
    {
        return Add<T>(member, width, caption, format, alignment);
    }
    public DynamicGridColumn Add(
        Expression<Func<T, object?>> member,
        int? width = null,
        string? caption = null,
        string? format = null,
        Alignment? alignment = null
    )
    {
        var col = CreateColumn(member, width: width, caption: caption, format: format, alignment: alignment);
        Add(col);
        return col;
    }
    public DynamicGridColumns<T> AddFluent(
        Expression<Func<T, object?>> member,
        int? width = null,
        string? caption = null,
        string? format = null,
        Alignment? alignment = null
    )
    {
        Add(member, width: width, caption: caption, format: format, alignment: alignment);
        return this;
    }
}

public class DynamicGridColumnGroup(string header, DynamicColumnBase start, DynamicColumnBase end, object? tag = null)
{
    public string Header { get; set; } = header;

    public DynamicColumnBase StartColumn { get; set; } = start;

    public DynamicColumnBase EndColumn { get; set; } = end;

    public object? Tag { get; set; } = tag;
}

public class DynamicGridColumnGrouping
{
    public List<DynamicGridColumnGroup> Groups = new();

    public DynamicGridColumnGrouping AddGroup(string header, DynamicColumnBase start, DynamicColumnBase end, object? tag = null)
    {
        Groups.Add(new(header, start, end, tag: tag));
        return this;
    }
}

public class DynamicGridColumnGroupings : List<DynamicGridColumnGrouping>
{
}