using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using InABox.Core;

namespace InABox.DynamicGrid;


public class DynamicColumnGrid : DynamicGrid<DynamicGridColumn>
{
    public DynamicColumnGrid(IDynamicGridColumnSchema schema)
    {
        Columns = new DynamicGridColumns();
        Schema = schema;
    }

    protected override void Init()
    {
        base.Init();
    }

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

        options.RecordCount = true;
        options.MultiSelect = true;
        options.AddRows = true;
        options.EditRows = true;
        options.DeleteRows = true;

        options.ReorderRows = true;
    }

    private IDynamicGridColumnSchema _schema;
    public IDynamicGridColumnSchema Schema
    {
        get => _schema;
        [MemberNotNull(nameof(_schema))]
        set
        {
            _schema = value;

            var column = MasterColumns.FirstOrDefault(x => string.Equals(x.ColumnName, nameof(DynamicGridColumn.ColumnName)));
            if(column is not null && column.Editor is DynamicColumnNameEditor edit)
            {
                edit.Schema = value;
            }
        }
    }


    public DynamicGridColumns Columns { get; }

    public bool DirectEdit { get; set; }

    protected override void MoveRows(CoreRow[] rows, int index, bool isCopy)
    {
        var targetCol = index < Columns.Count ? Columns[index] : null;
 
        var cols = LoadItems(rows);
        if (isCopy)
        {
            cols = cols.ToArray(x => x.Copy());
        }
        else
        {
            foreach(var col in cols)
            {
                Columns.Remove(col);
            }
        }
        if(targetCol is not null)
        {
            var idx = Columns.IndexOf(targetCol);
            Columns.InsertRange(idx, cols);
        }
        else
        {
            Columns.AddRange(cols);
        }
        Refresh(false, true);
        SelectedRows = cols.Select(x => Columns.IndexOf(x)).Select(x => Data.Rows[x]).ToArray();
    }

    protected override void DoAdd(bool openEditorOnDirectEdit = false)
    {
        if(DynamicGridColumnNameSelectorGrid.SelectColumnName(Schema, out var column))
        {
            var item = Schema.GetColumn(column);
            SaveItem(item);
            DoChanged();
            Refresh(false, true);
        }
    }

    protected override void DoValidate(DynamicGridColumn[] items, List<string> errors)
    {
        base.DoValidate(items, errors);

        if (items.Any(x => string.IsNullOrWhiteSpace(x.ColumnName)))
            errors.Add("[ColumnName] must not be blank!");
    }

    protected override Dictionary<string, object?> EditorValueChanged(IDynamicEditorForm editor, DynamicGridColumn[] items, string name, object value)
    {
        var changes = base.EditorValueChanged(editor, items, name, value);
        if(name == nameof(DynamicGridColumn.ColumnName) && value is string columnName)
        {
            var newCol = Schema.GetColumn(columnName);

            foreach(var item in items)
            {
                CoreUtils.MonitorChanges(item, () =>
                {
                    item.Width = newCol.Width;
                    item.Alignment = newCol.Alignment;
                    item.Format = newCol.Format;
                    item.Editor = newCol.Editor.CloneEditor();
                    item.Caption = newCol.Caption;
                }, changes);
            }
        }
        return changes;
    }


    #region Save / Load

    protected override void Reload(
        Filters<DynamicGridColumn> criteria, Columns<DynamicGridColumn> columns, ref SortOrder<DynamicGridColumn>? sort, 
        CancellationToken token, Action<CoreTable, Exception?> action)
    {
        var result = new CoreTable();
        if (columns == null || columns.Count == 0)
            result.LoadColumns(typeof(DynamicGridColumn));
        else
            result.LoadColumns(columns);
        result.LoadRows(Columns);
        action.Invoke(result, null);
    }

    public override DynamicGridColumn LoadItem(CoreRow row)
    {
        var index = Data.Rows.IndexOf(row);
        return Columns[index];
    }

    public override void SaveItem(DynamicGridColumn item)
    {
        if (!Columns.Contains(item))
            Columns.Add(item);
    }

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

    #endregion
}