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

namespace InABox.DynamicGrid
{
    public abstract class BaseDynamicEditorControl : ContentControl, IDynamicEditorControl
    {
        public static readonly DependencyProperty ColumnNameProperty =
            DependencyProperty.Register(nameof(ColumnName), typeof(string), typeof(BaseDynamicEditorControl));

        public static readonly DependencyProperty ColorProperty =
            DependencyProperty.Register("Color", typeof(Color), typeof(BaseDynamicEditorControl));

        public new static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.Register(nameof(IsEnabled), typeof(bool), typeof(BaseDynamicEditorControl));

        private IBaseEditor _editordefinition;

        public BaseDynamicEditorControl()
        {
            Color = Colors.LightYellow;
        }

        public Type ValueType { get; set; }

        public Color Color
        {
            get => (Color)GetValue(ColorProperty);
            set
            {
                SetValue(ColorProperty, value);
                if (EditorDefinition != null)
                    SetColor(Color);
            }
        }

        public string ColumnName
        {
            get => (string)GetValue(ColumnNameProperty);
            set => SetValue(ColumnNameProperty, value);
        }
        
        protected TextBox? Information { get; private set; }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IBaseEditor EditorDefinition
        {
            get => _editordefinition;
            set
            {
                _editordefinition = value;
                
                if (_editordefinition.Information != null)
                {
                    DockPanel _dock = new DockPanel();
                    var _editor = CreateEditor();
                    _editor.SetValue(DockPanel.DockProperty, Dock.Left);
                    _dock.Children.Add(_editor);
                    Information = new TextBox()
                    {
                        VerticalAlignment = VerticalAlignment.Stretch,
                        VerticalContentAlignment = VerticalAlignment.Center,
                        HorizontalAlignment = HorizontalAlignment.Stretch,
                        Margin = new Thickness(5, 0, 0, 0),
                        IsReadOnly = true,
                        Focusable = false,
                        Background = new SolidColorBrush(Colors.WhiteSmoke),
                        BorderBrush = new SolidColorBrush(Colors.Silver)
                    };
                    Information.SetValue(DockPanel.DockProperty, Dock.Left);
                    _dock.Children.Add(Information);
                    Content = _dock;
                }
                else
                    Content = CreateEditor();

                SetColor(Color);
            }
        }

        protected void UpdateInformation()
        {
            if (EditorDefinition?.Information != null  && Information != null)
            {
                var _info = Activator.CreateInstance(EditorDefinition.Information) as IEditorInformation;
                Information.Text = _info?.Display(Host.GetItems()) ?? "";
            }
        }

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

        public abstract bool Changed { get; set; }


        public virtual event EditorControlValueChangedHandler OnEditorValueChanged;

        #region Abstract Functions

        public abstract void Configure();

        protected abstract FrameworkElement CreateEditor();

        public abstract int DesiredWidth();

        public abstract int DesiredHeight();

        public abstract void SetColor(Color color);

        public abstract void SetFocus();
        
        public abstract void SetEnabled(bool enabled);

        public abstract void SetVisible(bool visible);

        #endregion

        public virtual void SetValue(string property, object? value)
        {
            UpdateInformation();
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="property">The full property name of the entity being edited.</param>
        /// <returns></returns>
        public abstract object? GetValue(string property);

        public abstract Dictionary<string, object?> GetValues();

        public new bool IsEnabled
        {
            get => (bool)GetValue(IsEnabledProperty);
            set
            {
                SetValue(IsEnabledProperty, value);
                SetEnabled(value);
            }
        }

        public IDynamicEditorHost Host { get; set; }

        protected List<Button> CreateButtons(out bool bDisableEditor)
        {
            var buttons = new List<Button>();
            bDisableEditor = false;
            if (EditorDefinition != null && EditorDefinition is IButtonEditor ce && ce.Buttons is not null)
            {
                foreach (var ceb in ce.Buttons.Reverse())
                {
                    if (ceb.DisableEditor)
                        bDisableEditor = true;

                    var button = new Button
                    {
                        HorizontalAlignment = HorizontalAlignment.Left,
                        VerticalAlignment = VerticalAlignment.Stretch,
                        VerticalContentAlignment = VerticalAlignment.Center,
                        HorizontalContentAlignment = HorizontalAlignment.Center,
                        Content = ceb.Caption,
                        Width = ceb.Width,
                        Margin = new Thickness(5, 0, 0, 0),
                        Padding = new Thickness(5, 0, 5, 0),
                        Tag = ceb,
                        IsEnabled = ceb.IsEnabled,
                        Visibility = ceb.IsVisible ? Visibility.Visible : Visibility.Collapsed
                    };
                    button.Click += (o, e) =>
                    {
                        var b = (Button)o;
                        var eb = b.Tag as EditorButton;
                        eb.Click(this);
                    };
                    ceb.OnVisible += (visible) =>
                    {
                        button.Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
                    };
                    ceb.OnEnabled += (enabled) =>
                    {
                        button.IsEnabled = enabled;
                    };
                    buttons.Add(button);
                }
            }
            return buttons;
        }
        
        
    }
    
    public abstract class BaseDynamicEditorControl<TEditor> : BaseDynamicEditorControl
        where TEditor : IBaseEditor
    {
        public new TEditor EditorDefinition
        {
            get => (TEditor)base.EditorDefinition;
            set
            {
                base.EditorDefinition = value;
            }
        }
    }
}