using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using FastReport.Utils;
using InABox.Configuration;
using InABox.Core;

namespace InABox.DynamicGrid;

public interface IDynamicEnclosedListGrid<TOne, TMany> : IDynamicEditorPage
{
    TOne Entity { get; set; }
    List<TMany> Items { get; }
    void LoadItems(IEnumerable<TMany> items);
}

public class DynamicEnclosedListGrid<TOne, TMany> : DynamicGrid<TMany>, IDynamicEditorPage, IDynamicEnclosedListGrid<TOne, TMany>
    where TMany : BaseObject, new() where TOne : Entity, IRemotable, IPersistent, new()
{
    private readonly List<TMany> MasterList = new();

    private readonly PropertyInfo property;

    public PageType PageType => PageType.Other;

    public bool Visible => true;

    public bool ReadOnly { get; set; }

    protected DynamicGridCustomColumnsComponent<TMany> ColumnsComponent;

    public DynamicEnclosedListGrid(PropertyInfo prop)
    {
        Items = new List<TMany>();
        property = prop;

        ColumnsComponent = new(this, null);
    }

    protected override void DoReconfigure(DynamicGridOptions options)
    {
        base.DoReconfigure(options);

        options.RecordCount = true;
        options.SelectColumns = true;
    }

    public DynamicEditorGrid EditorGrid { get; set; }

    public bool Ready { get; set; }

    public string Caption()
    {
        var caption = typeof(TMany).GetCustomAttribute(typeof(Caption));
        if (caption != null)
            return ((Caption)caption).Text;
        var result = new Inflector.Inflector(new CultureInfo("en")).Pluralize(typeof(TMany).Name);
        return result;
    }

    public virtual int Order { get; set; } = int.MinValue;

    public void Load(object item, Func<Type, CoreTable?>? PageDataHandler)
    {
        Entity = (TOne)item;
        MasterList.Clear();
        if (property.GetValue(item) is IList list)
            foreach (var entry in list)
                MasterList.Add((TMany)entry);
        Items.AddRange(MasterList);
        Refresh(true, true);
        Ready = true;
    }

    public void Cancel()
    {
        foreach(var item in MasterList)
        {
            item.CancelChanges();
        }

        Items.Clear();
        Items.AddRange(MasterList);
        Refresh(false, true);
    }

    public void BeforeSave(object item)
    {
        var list = Activator.CreateInstance(property.PropertyType) as IList;
        foreach (var entry in Items)
            list.Add(entry);
        property.SetValue(item, list);
    }

    public void AfterSave(object item)
    {
    }

    public Size MinimumSize()
    {
        return new Size(400, 400);
    }

    public List<TMany> Items { get; private set; }

    public TOne Entity { get; set; }

    public void LoadItems(IEnumerable<TMany> items)
    {
        Items.Clear();
        if (items != null)
            Items.AddRange(items);
        Refresh(false, true);
    }

    public override DynamicGridColumns GenerateColumns()
    {
        var cols = new DynamicGridColumns();
        cols.AddRange(base.GenerateColumns().Where(x => !x.ColumnName.StartsWith(property.Name + ".")));
        return cols;
    }

    protected override DynamicGridColumns LoadColumns()
    {
        return ColumnsComponent.LoadColumns();
    }

    protected override void SaveColumns(DynamicGridColumns columns)
    {
        ColumnsComponent.SaveColumns(columns);
    }

    protected override void LoadColumnsMenu(ContextMenu menu)
    {
        base.LoadColumnsMenu(menu);
        ColumnsComponent.LoadColumnsMenu(menu);
    }

    public override TMany LoadItem(CoreRow row)
    {
        return Items[row.Index];
    }

    public override void SaveItem(TMany item)
    {
        if (!Items.Contains(item))
            Items.Add(item);

        if (item is ISequenceable && LookupFactory.DefineSort<TMany>() is SortOrder<TMany> sort)
        {
            Items = Items.AsQueryable().SortBy(sort.Expression).ToList();
        }
    }

    public override void DeleteItems(params CoreRow[] rows)
    {
        foreach (var row in rows.OrderByDescending(x => x.Index))
            Items.RemoveAt(row.Index);
    }

    protected override void Reload(
        Filters<TMany> criteria, Columns<TMany> columns, ref SortOrder<TMany>? sort, 
        CancellationToken token, Action<CoreTable?, Exception?> action)
    {
        var results = new CoreTable();
        results.LoadColumns(typeof(TMany));

        if (sort != null)
        {
            var exp = IQueryableExtensions.ToLambda<TMany>(sort.Expression);
            var sorted = sort.Direction == SortDirection.Ascending
                ? Items.AsQueryable().OrderBy(exp)
                : Items.AsQueryable().OrderByDescending(exp);
            foreach (var then in sort.Thens)
            {
                var thexp = IQueryableExtensions.ToLambda<TMany>(then.Expression);
                sorted = sort.Direction == SortDirection.Ascending ? sorted.ThenBy(exp) : sorted.ThenByDescending(exp);
            }

            results.LoadRows(sorted);
        }
        else
        {
            results.LoadRows(Items);
        }

        //if (sort != null)
        //    results.LoadRows(Items.AsQueryable().SortBy(sort.Expression));
        //else
        //    results.LoadRows(Items.OrderBy(x => x.Sort));

        action.Invoke(results, null);
    }
}