using System;
using System.Collections.Generic;
using System.Linq;
using Assets.Source.Constants;
using Assets.Source.Settings;
using UnityEngine;

namespace Assets.Source.UI
{
    public abstract class UILayer<T_Element> : MonoBehaviour where T_Element : IUIElement
    {
        public List<UIElementBase> Prefabs;

        protected Dictionary<Type, IUIElement> _elementsTypeLookup = new Dictionary<Type, IUIElement>();
        protected List<IUIElement> _elements = new List<IUIElement>();

        public void Init()
        {
            if (global::Get.Scenes.LastActiveSceneType == GameSceneType.Undefined)
                return;

            foreach (var prefab in Prefabs)
            {
                var e = Instantiate(prefab, transform);
                var type = e.GetType();
                _elements.Add(e);
                if (!_elementsTypeLookup.ContainsKey(type))
                    _elementsTypeLookup.Add(type, e);
            }

            VInit();

            foreach (var uiElement in _elements)
            {
                if (uiElement.OpenedInitially)
                    uiElement.Open(null, true);
            }
        }

        public virtual void VInit() { }

        public virtual T Get<T>(string explicitId = null) where T : T_Element
        {
            IUIElement e;
            if (explicitId == null || explicitId == UIConstants.DEFAULT_EXPLICIT_ID)
                e = _elementsTypeLookup[typeof(T)];
            else
                e = _elements.First(element => element is T && string.Equals(element.ExplicitID, explicitId));
            return (T) e;
        }
        public virtual IUIElement Get(Type type, string explicitId = null)
        {
            IUIElement e;
            if (explicitId == null || explicitId == UIConstants.DEFAULT_EXPLICIT_ID)
                e = _elementsTypeLookup[type];
            else
                e = _elements.First(element => element.GetType() == type && string.Equals(element.ExplicitID, explicitId));
            return e;
        }

        public virtual T Open<T>(string explicitId = null) where T : T_Element
        {
            var e = Get<T>(explicitId);
            e.Open();
            return e;
        }

        public virtual T Open<T, P>(string explicitId, P properties, bool instantly) 
            where T : T_Element
            where P : IUIElementProperties
        {
            var e = Get<T>(explicitId);
            e.Open(properties, instantly);
            return e;
        }

        public T Open<T, P>(P properties, bool instantly)
            where T : T_Element
            where P : IUIElementProperties
        {
            return Open<T, P>(null, properties, instantly);
        }

        public IUIElement Open(Type type, string explicitId = null)
        {
            if (!_elementsTypeLookup.ContainsKey(type))
                return null;
            var e = Get(type, explicitId);
            e.Open();
            return e;
        }

        public virtual IUIElement Close<T>(string explicitId = null) where T : T_Element
        {
            var e = Get<T>(explicitId);
            if (e != null)
            {
                e.Close();
                return e;
            }
            Debug.LogWarning("UI Element == null");
            return null;
        }

        public IUIElement Close(Type type, string explicitId = null)
        {
            if (!_elementsTypeLookup.ContainsKey(type))
                return null;
            var e = Get(type, explicitId);
            e.Close();
            return e;
        }

        public void CloseAll(bool instantly = false, params IUIElement[] exceptions)
        {
            foreach (var e in _elements)
                if (exceptions.Length == 0 || !exceptions.Contains(e))
                    e.Close(instantly);
        }
    }
}
