using InABox.Configuration;
using InABox.Core;
using InABox.WPF;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace InABox.DynamicGrid;

/// <summary>
/// A component which loads a custom set of columns from the database.
/// </summary>
public class DynamicGridCustomColumnsComponent<T>
    where T : BaseObject, new()
{
    private readonly DynamicGrid<T> Grid;

    public string? Tag { get; set; }

    public DynamicGridCustomColumnsComponent(DynamicGrid<T> grid, string? tag)
    {
        Grid = grid;
        Tag = tag;
    }

    public DynamicGridColumns LoadColumns()
    {
        var tag = GetTag(Grid.IsDirectEditMode());
        
        var user = Task.Run(() => new UserConfiguration<DynamicGridColumns>(tag).Load());
        var global = Task.Run(() => new GlobalConfiguration<DynamicGridColumns>(tag).Load());
        Task.WaitAll(user, global);

        var columns = user.Result.Any() ? user.Result : global.Result;

        if (!columns.Any())
            columns = Grid.GenerateColumns();

        var removes = columns.Where(x => x is null || string.IsNullOrWhiteSpace(x.ColumnName) || DatabaseSchema.Property(typeof(T), x.ColumnName) == null || GetColumnEditor(x) is NullEditor)
           .ToArray();
        foreach (var remove in removes)
            columns.Remove(remove);

        foreach (var column in columns)
            try
            {
                var prop = DatabaseSchema.Property(typeof(T), column.ColumnName);
                if (prop != null)
                {
                    column.Editor = prop.Editor;
                }
                else
                {
                    var type = CoreUtils.GetProperty(typeof(T), column.ColumnName);
                    column.Editor = type.GetEditor() ?? new NullEditor();
                }
            }
            catch (Exception e)
            {
                Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
            }

        columns.RemoveAll(x => DatabaseSchema.Property(typeof(T), x.ColumnName) == null || GetColumnEditor(x) is NullEditor);
        return columns;
    }

    public void SaveColumns(DynamicGridColumns columns)
    {
        var tag = GetTag(Grid.IsDirectEditMode());
        new UserConfiguration<DynamicGridColumns>(tag).Save(columns);
    }

    private string GetTag(bool directEdit)
    {
        var tag = Tag ?? typeof(T).Name;
        if (directEdit)
            tag += ":DirectEdit";
        return tag;
    }

    private static BaseEditor GetColumnEditor(DynamicGridColumn column)
    {
        try
        {
            var prop = DatabaseSchema.Property(typeof(T), column.ColumnName);
            if (prop != null) return prop.Editor;

            var type = CoreUtils.GetProperty(typeof(T), column.ColumnName);
            return type.GetEditor() ?? new NullEditor();
        }
        catch (Exception e)
        {
            Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
        }

        return new NullEditor();
    }

    public void LoadColumnsMenu(ContextMenu menu)
    {
        menu.AddSeparatorIfNeeded();
        menu.AddItem("Reset Columns to Default", null, ResetColumnsClick);
        if (Security.IsAllowed<CanSetDefaultColumns>())
        {
            menu.AddItem("Reset Columns to System Default", null, ResetColumnsToSystemClick);
            menu.AddSeparator();
            menu.AddItem("Mark Columns as Default", null, UpdateDefaultColumnsClick);
        }
    }

    private void ResetColumnsToSystemClick()
    {
        SaveColumns(Grid.GenerateColumns());
        Grid.Refresh(true, true);
    }

    private void ResetColumnsClick()
    {
        Grid.VisibleColumns.Clear();
        SaveColumns(Grid.VisibleColumns);
        Grid.Refresh(true, true);
    }

    private void UpdateDefaultColumnsClick()
    {
        var tag = GetTag(Grid.IsDirectEditMode());
        new GlobalConfiguration<DynamicGridColumns>(tag).Save(Grid.VisibleColumns);
        new UserConfiguration<DynamicGridColumns>(tag).Delete();
        Grid.Refresh(true, true);
    }
}
