using System;
using System.ComponentModel;
using System.Linq;

namespace InABox.Core
{
    public interface IBaseEditor
    {
        Visible Visible { get; set; }

        Editable Editable { get; set; }

        string ToolTip { get; set; }

        Alignment Alignment { get; set; }

        int Width { get; set; }

        string Format { get; set; }

        int ColumnSequence { get; set; }

        int EditorSequence { get; set; }

        string Caption { get; set; }

        string? Page { get; set; }

        Summary Summary { get; set; }

        SecurityAttribute[] Security { get; set; }
        
        Type? Information { get; set; }

        BaseEditor CloneEditor();
        public object Clone();
    }

    public interface IEditorInformation
    {
        string Display(BaseObject[] items);
    }
    
    public abstract class EditorInformation<T> : IEditorInformation where T : class
    {

        public abstract string GetInfo(T item);
        
        public string Display(BaseObject[] items)
        {
            var _results = items.OfType<T>().Select(GetInfo).ToArray();
            return _results.Length == 0
                ? ""
                : _results.Length == 1
                    ? _results[0]
                    : "(Multiple Values)";
            
        }
    }

    public abstract class BaseEditor : Attribute, IEnclosedEntity, ICloneable, IBaseEditor
    {

        private BaseObject _linkedParent;

        private string _linkedPath;
        
        public void SetLinkedParent(BaseObject parent)
        {
            _linkedParent = parent;
        }

        public void SetLinkedPath(string path)
        {
            _linkedPath = path;
        }

        public BaseObject GetLinkedParent() => _linkedParent;

        public string GetLinkedPath() => _linkedPath;

        protected BaseEditor()
        {
            Editable = Editable.Enabled;
            Visible = Visible.Optional;
            Alignment = Alignment.MiddleLeft;
            Width = 0;
            Format = "";
            ColumnSequence = 0;
            EditorSequence = 0;
            Caption = "";
            Summary = Summary.None;
            ToolTip = "";
            Security = Array.Empty<SecurityAttribute>();
        }

        [EnumLookupEditor(typeof(Visible))]
        public Visible Visible { get; set; }

        [EnumLookupEditor(typeof(Editable))]
        public Editable Editable { get; set; }

        [NullEditor]
        public string ToolTip { get; set; }

        [NullEditor]
        public Alignment Alignment { get; set; }

        [NullEditor]
        public int Width { get; set; }

        [NullEditor]
        public string Format { get; set; }

        [NullEditor]
        public int ColumnSequence { get; set; }

        [NullEditor]
        public int EditorSequence { get; set; }

        [NullEditor]
        public string Caption { get; set; }

        [NullEditor]
        public string? Page { get; set; }

        [NullEditor]
        public Summary Summary { get; set; }

        [NullEditor]
        public SecurityAttribute[] Security { get; set; }

        private Type? _information;
        public Type? Information
        {
            get => _information;
            set
            {
                if (value?.GetInterfaces(typeof(IEditorInformation)) != null)
                    _information = value;
                else
                {
                    if (value != null)
                        throw new Exception($"{value.EntityName()} does not implement IEditorInformation!");
                }
            }
        }

        public BaseEditor CloneEditor()
        {
            var result = DoClone();
            result.Visible = Visible;
            result.Editable = Editable;
            result.Alignment = Alignment;
            result.Width = Width;
            result.Format = Format;
            result.ColumnSequence = ColumnSequence;
            result.EditorSequence = EditorSequence;
            result.Caption = Caption;
            result.Page = Page;
            result.Summary = Summary;
            result.ToolTip = ToolTip;
            result.Security = Security.Select(x => x.Clone()).ToArray();
            result.Information = Information;

            return result;
        }

        public object Clone() => CloneEditor();

        protected abstract BaseEditor DoClone();
    }
}