using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using InABox.Core;
using NPOI.Util.Collections;

namespace InABox.DynamicGrid
{
    internal class DynamicVariableGrid : DynamicOneToManyGrid<DigitalForm, DigitalFormVariable>
    {
        public DynamicVariableGrid()
        {
            Options.Add(DynamicGridOption.MultiSelect);
        }

        public bool EditProperties(Type type, DFLayoutFieldProperties item)
        {
            var editor = new DynamicEditorForm(type);
            if (item is DFLayoutLookupFieldProperties)
            {
                editor.OnFormCustomiseEditor += LookupEditor_OnFormCustomiseEditor;
                editor.OnEditorValueChanged += (sender, name, value) =>
                {
                    var result = DynamicGridUtils.UpdateEditorValue(new[] { item }, name, value);
                    if (name == "LookupType")
                    {
                        var grid = (sender as DynamicEditorGrid)!;
                        var edit = grid.FindEditor("Filter");
                        if (edit is FilterEditorControl filter)
                        {
                            filter.FilterType = value is string str ?
                                CoreUtils.GetEntityOrNull(str) :
                                null;
                        }

                        var propertiesEditor = grid.FindEditor(nameof(DFLayoutLookupFieldProperties.AdditionalProperties));
                        if(propertiesEditor is MultiLookupEditorControl multi && multi.EditorDefinition is ComboMultiLookupEditor combo)
                        {
                            combo.Clear();
                            multi.Configure();
                        }
                    }
                    return new();
                };
            }
            else
            {
                editor.OnFormCustomiseEditor += Editor_OnFormCustomiseEditor;
            }
            editor.Items = new BaseObject[] { item };
            editor.OnDefineLookups += o =>
            {
                var def = (o.EditorDefinition as ILookupEditor)!;
                var colname = o.ColumnName;
                // Nope, there is nothing dodgy about this at all
                // I am not breaking any rules by passing in the QA Form instance, rather than the Field instance 
                // so that I can get access to the "AppliesTo" property, and thus the list of properties that can be updated
                // Nothing to see here, I promise!
                CoreTable? values;
                if(o.ColumnName == "Property")
                {
                    values = def.Values(colname, new object[] { Item });
                }
                else
                {
                    values = def.Values(colname, new object[] { item });
                }

                o.LoadLookups(values);
            };
            return editor.ShowDialog() == true;
        }

        private void Editor_OnFormCustomiseEditor(IDynamicEditorForm sender, object[] items, DynamicGridColumn column, BaseEditor editor)
        {
            if ((column.ColumnName == "Expression" || column.ColumnName == "ColourExpression") && editor is ExpressionEditor exp)
            {
                var variables = new List<string>();
                foreach (var variable in Items)
                {
                    //variables.Add(variable.Code);
                    foreach (var col in variable.GetVariableColumns())
                    {
                        variables.Add(col.ColumnName);
                    }
                }
                variables.Sort();
                exp.VariableNames = variables;
            }
        }

        private void LookupEditor_OnFormCustomiseEditor(IDynamicEditorForm sender, object[] items, DynamicGridColumn column, BaseEditor editor)
        {
            if(column.ColumnName == "Filter" && editor is FilterEditor fe)
            {
                var properties = items[0] as DFLayoutLookupFieldProperties;
                var lookupType = properties.LookupType;
                var entityType = CoreUtils.GetEntityOrNull(lookupType);
                fe.Type = entityType;
            }
            Editor_OnFormCustomiseEditor(sender, items, column, editor);
        }

        private void CreateMenu(ContextMenu parent, string header, Type type)
        {
            var menu = new MenuItem();
            menu.Header = header;
            menu.Tag = type;
            menu.Click += (o, e) =>
            {
                var itemtype = (o as MenuItem).Tag as Type;

                var fieldBaseType = itemtype.GetSuperclassDefinition(typeof(DFLayoutField<>));
                if(fieldBaseType != null)
                {
                    var propertiesType = fieldBaseType.GetGenericArguments()[0];
                    var properties = Activator.CreateInstance(propertiesType) as DFLayoutFieldProperties;
                    if (EditProperties(propertiesType, properties))
                    {
                        var variable = CreateItem();
                        variable.SaveProperties(itemtype, properties);
                        SaveItem(variable);
                        Refresh(false, true);
                    }
                }
            };
            parent.Items.Add(menu);
        }

        protected override void DoAdd()
        {
            var menu = new ContextMenu();

            foreach(var fieldType in DFUtils.GetFieldTypes())
            {
                var caption = fieldType.GetCaption();
                if (string.IsNullOrWhiteSpace(caption))
                {
                    caption = CoreUtils.Neatify(fieldType.Name);
                }
                CreateMenu(menu, caption, fieldType);
            }

            menu.IsOpen = true;
        }

        /*protected override DigitalFormVariable LoadItem(CoreRow row)
        {
            return Items.FirstOrDefault(r => r.ID.Equals(row.Get<DigitalFormVariable, Guid>(c => c.ID)));
        }*/

        protected override void DoEdit()
        {
            if (!SelectedRows.Any())
                return;
            var variable = LoadItem(SelectedRows.First());
            var properties = variable.CreateProperties();
            if (EditProperties(properties.GetType(), properties))
            {
                variable.SaveProperties(properties);
                SaveItem(variable);
                Refresh(false, true);
            }
        }
    }
}