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

namespace InABox.DynamicGrid
{
    internal class DynamicColumnGrid : DynamicGrid<DynamicGridColumn>
    {
        public DynamicColumnGrid()
        {
            Columns = new DynamicGridColumns();
        }

        protected override void Init()
        {
            ActionColumns.Add(new DynamicRowMovementColumn(DynamicRowMovement.Up, SwapRows));
            ActionColumns.Add(new DynamicRowMovementColumn(DynamicRowMovement.Down, SwapRows));

            //MasterColumns.AddRange(LoadColumns());
        }

        protected override void DoReconfigure(FluentList<DynamicGridOption> options)
        {
            options.AddRange(DynamicGridOption.RecordCount, DynamicGridOption.MultiSelect, DynamicGridOption.AddRows, DynamicGridOption.EditRows,
                DynamicGridOption.DeleteRows);
        }

        public Type Type { get; set; }

        public DynamicGridColumns Columns { get; }

        public bool DirectEdit { get; set; }

        private bool SwapRows(int row1, int row2)
        {
            var item = Columns[row1];
            Columns.Remove(item);
            Columns.Insert(row2, item);
            return true;
        }


        //public DynamicGridColumns DefineColumns()
        //{
        //	return LoadColumns();
        //}

        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 DynamicGridColumns LoadColumns()
        {
            var columns = new DynamicGridColumns
            {
                new()
                {
                    ColumnName = "ColumnName", /* Type = typeof(String), */ Width = 0, Editor = new ComboLookupEditor(typeof(ColumnNameGenerator))
                },
                new() { ColumnName = "Width", /* Type = typeof(int),  */ Width = 80 },
                new() { ColumnName = "Caption", /* Type = typeof(String), */ Width = 0 },
                new() { ColumnName = "Format", /* Type = typeof(String), */ Width = 60 },
                new() { ColumnName = "Alignment", /* Type = typeof(String), */ Width = 100, Editor = new EnumLookupEditor(typeof(Alignment)) }
            };
            return columns;
        }

        public override void ConfigureColumns(DynamicGridColumns columns)
        {
            base.ConfigureColumns(columns);
            var column = columns.FirstOrDefault(x => x.ColumnName.Equals("ColumnName"));
            if (column != null)
            {
                var lookup = column.Editor as ComboLookupEditor;
                lookup.OnAfterGenerateLookups += DoGenerateColumns;
            }
        }

        private IEnumerable<DynamicGridColumn> ProcessColumns()
        {
            var result = new List<DynamicGridColumn>();
            var cols = new DynamicGridColumns();
            cols.ExtractColumns(Type);
            foreach (var col in cols)
            {
                if (col.Editor == null)
                    continue;
                if (col.Editor is NullEditor)
                    continue;
                if (col.Editor.Visible != Visible.Hidden)
                {
                    result.Add(col);
                    continue;
                }

                if (!DirectEdit)
                    continue;

                if (col.Editor.Editable.IsEditable() && col.ColumnName.Split('.').Length <= 2)
                    result.Add(col);
            }
            result.Sort((a, b) => a.ColumnName.CompareTo(b.ColumnName));

            return result;
        }

        private void DoGenerateColumns(ILookupGenerator generator, List<LookupEntry> entries)
        {
            var cols = ProcessColumns();
            foreach (var col in cols)
            {
                var entry = new LookupEntry(col.ColumnName, col.ColumnName);
                entries.Add(entry);
            }
        }

        protected override void DefineLookups(ILookupEditorControl sender, DynamicGridColumn[] items, bool async = true)
        {
            if (Type != null && sender.ColumnName.Equals("ColumnName"))
            {
                var results = new CoreTable();
                results.Columns.Add(new CoreColumn { ColumnName = sender.ColumnName, DataType = typeof(string) });
                results.Columns.Add(new CoreColumn { ColumnName = "Display", DataType = typeof(string) });

                var cols = ProcessColumns();
                foreach (var col in cols)
                {
                    var row = results.NewRow();
                    row[sender.ColumnName] = col.ColumnName;
                    row["Display"] = col.ColumnName;
                    results.Rows.Add(row);
                }

                ;
                sender.LoadLookups(results);
            }
            else
            {
                base.DefineLookups(sender, items, async);
            }
        }

        #region Save / Load

        protected override void Reload(Filters<DynamicGridColumn> criteria, Columns<DynamicGridColumn> columns, ref SortOrder<DynamicGridColumn>? sort,
            Action<CoreTable, Exception?> action)
        {
            var result = new CoreTable();
            if (columns == null || !columns.Items.Any())
                result.LoadColumns(typeof(DynamicGridColumn));
            else
                foreach (var column in columns.Items)
                    result.Columns.Add(new CoreColumn { ColumnName = column.ToString(), DataType = column.Expression.Type });
            result.LoadRows(Columns);
            action.Invoke(result, null);
        }

        //protected override DataTable Reload(Dictionary<String,Object> criteria, List<String> columnnames, String sort)
        //{
        //	DataTable result = new DataTable();
        //	result.LoadColumns(typeof(DynamicGridColumn));
        //	result.LoadRows(Columns);
        //	return result;
        //}

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

        public override void SaveItem(DynamicGridColumn item)
        {
            try
            {
                var prop = DatabaseSchema.Property(Type, item.ColumnName);
                item.Editor = prop.Editor;
            }
            catch (Exception e)
            {
                Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
            }

            if (!Columns.Contains(item))
                Columns.Add(item);
        }

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

        #endregion
    }
}