using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using InABox.Core;

namespace InABox.DynamicGrid
{
    public abstract class DynamicEnclosedEditorControl<T, TEditor> : BaseDynamicEditorControl<TEditor>
        where T : IEnclosedEntity
        where TEditor : BaseEditor
    {
        protected bool Updating;

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override bool Changed { get; set; }

        public override event EditorControlValueChangedHandler? OnEditorValueChanged;

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        protected virtual Dictionary<string, object?> OtherValues { get; }

        public DynamicEnclosedEditorControl()
        {
            Loaded = false;
            OtherValues = new();
            MinHeight = 25;
            Focusable = false;
        }

        /// <summary>
        /// Trigger a change notification.
        /// </summary>
        /// <param name="changedFields">A list of fields that have been changed. If empty, then it is assumed that all child fields are changed.</param>
        protected virtual bool CheckChanged(params string[] changedFields)
        {
            //Logger.Send(LogType.Information, "", string.Format("{0}({1}).CheckChanged()", GetType().EntityName().Split('.').Last(), ColumnName));
            if (Loaded && !Updating)
            {
                Updating = true;
                try
                {
                    var values = new Dictionary<string, object?>();
                    var sColumn = string.IsNullOrEmpty(ColumnName) ? "" : ColumnName;
                    if(changedFields.Length > 0)
                    {
                        foreach(var field in changedFields)
                        {
                            values[$"{ColumnName}.{field}"] = GetChildValue(field);
                        }
                    }
                    else
                    {
                        foreach(var (k, v) in GetChildValues())
                        {
                            values[$"{ColumnName}.{k}"] = v;
                        }
                    }
                    foreach (var key in OtherValues.Keys)
                        values[key] = OtherValues[key];
                    OnEditorValueChanged?.Invoke(this, values);
                }
                finally
                {
                    Changed = true;
                    Updating = false;
                }
            }

            return Changed;
        }

        public override void SetEnabled(bool enabled)
        {
            if(Content is FrameworkElement element) element.IsEnabled = enabled;
            SetColor(enabled ? Color : Colors.WhiteSmoke);
        }

        public override void SetVisible(bool visible)
        {
            Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
        }

        protected abstract IEnumerable<KeyValuePair<string, object?>> GetChildValues();
        public override Dictionary<string, object?> GetValues()
        {
            return GetChildValues()
                .Select(x => new KeyValuePair<string, object?>($"{ColumnName}.{x.Key}", x.Value))
                .ToDictionary();
        }

        protected abstract object? GetChildValue(string property);

        public override object? GetValue(string property)
        {
            if (!property.StartsWith($"{ColumnName}.")) return null;
            property = property[(ColumnName.Length + 1)..];

            return GetChildValue(property);
        }

        protected abstract void SetChildValue(string property, object? value);
        public override void SetValue(string property, object? value)
        {
            if (!property.StartsWith($"{ColumnName}.")) return;
            property = property[(ColumnName.Length + 1)..];
            SetChildValue(property, value);
            base.SetValue(property,value);
        }
    }
}