using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

namespace TFramework
{
    [DefaultExecutionOrder(-9999)]
    public class UIManager : BaseManager
    {
        private Stack<BasePanel> panelStack;
        private Dictionary<string, BasePanel> panelDict;
        private List<BasePanel> panelBuffer;

        private Dictionary<string, Transform> _worldUIDomain;

        private TAction<BasePanel, BasePanel> OnPanelChanged;

        private BasePanel _currentPanel;
        /// <summary>
        /// 当前打开的面板
        /// </summary>
        public BasePanel CurrentPanel
        {
            get => _currentPanel;
            private set
            {
                OnPanelChanged?.Invoke(_currentPanel, value);
                _currentPanel = value;
            }
        }

        public const string DEFAULTDOMAIN = "默认UI域";

        public void Awake()
        {
            panelStack = new Stack<BasePanel>();
            panelDict = new Dictionary<string, BasePanel>();
            panelBuffer = new List<BasePanel>();
            _worldUIDomain = new Dictionary<string, Transform>();
        }

        /// <summary>
        /// 注册UI作用域 （即父物体）
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="domain">作用域</param>
        public void RegisterUIDomain(string name, Transform domain)
        {
            if (_worldUIDomain.ContainsKey(name))
                Log.Error($"UI作用域名称【{name}】被重复注册");
            else
                _worldUIDomain.Add(name, domain);
        }

        public void UnregisterUIDomain(string name)
        {
            if (_worldUIDomain.ContainsKey(name))
                _worldUIDomain.Remove(name);
            else
                Log.Error($"不存在名为【{name}】的UI作用域");
        }

        /// <summary>
        /// 打开UI
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public T OpenUI<T>(IPanelData args = null) where T : BasePanel => OpenUI(typeof(T), args) as T;

        public BasePanel OpenUI(Type type, IPanelData args = null)
        {
            if (panelStack.Count > 0)
                panelStack.Peek().OnPause(args);

            BasePanel panel = GetPanel(type);
            if (panel == null) return null;
            panel.UIEntity.SetActive(true);
            CurrentPanel = panel;
            panel.UIEntity.transform.SetAsLastSibling();
            panelStack.Push(panel);
            panel.OnEnter(args);
            StickyTopic();
            return panel;
        }

        /// <summary>
        /// 预加载UI 加载完成不打开
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void PreopenUI<T>() => PreopenUI(typeof(T));

        /// <summary>
        /// 预加载UI 加载完成不打开
        /// </summary>
        /// <typeparam name="Type"></typeparam>
        public void PreopenUI(Type type)
        {
            BasePanel panel = GetPanel(type);
            if (panel != null)
                panel.UIEntity.SetActive(false);
        }

        /// <summary>
        /// 置顶UI
        /// </summary>
        private void StickyTopic()
        {
            foreach (var item in panelDict.Values)
                if (item.UIEntity!=null && item.UIEntity.activeSelf && item.StickyTopic)
                    item.UIEntity.transform.SetAsLastSibling();
        }

        /// <summary>
        /// 关闭UI
        /// </summary>
        public void CloseUI(IPanelData args=null)
        {
            if (panelStack.Count <= 0) return;

            BasePanel toPanel = panelStack.Pop();
            if (toPanel.UIEntity == null) return;
            toPanel.UIEntity.SetActive(false);
            toPanel.OnExit(args);

            if (panelStack.Count <= 0) return;
            CurrentPanel = panelStack.Peek();
            CurrentPanel.OnResume(args);
        }

        /// <summary>
        /// 关闭UI
        /// </summary>
        /// <param name="type">UI类型</param>
        /// <param name="isDestroy">是否销毁</param>
        /// <param name="args">参数</param>
        public void CloseUI<T>(bool isDestroy = false, IPanelData args=null) => CloseUI(typeof(T), isDestroy, args);

        /// <summary>
        /// 关闭UI
        /// </summary>
        /// <param name="type">UI类型</param>
        /// <param name="isDestroy">是否销毁</param>
        /// <param name="args">参数</param>
        public void CloseUI(Type type, bool isDestroy = false, IPanelData args=null)
        {
            BasePanel panel = GetAlreadyHavePanel(type.FullName);
            if (panel == null) return;

            if (panel.UIEntity == null) return;

            if (panelStack.Peek() == panel)
                CloseUI(args);
            else
            {
                panelBuffer.Clear();
                if (panel.UIEntity.activeSelf)
                {
                    while (panelStack.Peek() != panel)
                        panelBuffer.Add(panelStack.Pop());
                    BasePanel toPanel = panelStack.Pop();
                    if(toPanel.UIEntity!=null)
                    {
                        toPanel.UIEntity.SetActive(false);
                        toPanel.OnExit(args,isDestroy);
                    }
                    for (int i = panelBuffer.Count - 1; i >= 0; i--)
                        panelStack.Push(panelBuffer[i]);
                }
            }
            if (isDestroy)
            {
                GameObject.DestroyImmediate(panel.UIEntity);
                panelDict.Remove(type.FullName);
            }
        }

        /// <summary>
        /// 获取面板
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private BasePanel GetPanel(Type type)
        {
            UIResourceAttribute attribute = type.GetCustomAttribute<UIResourceAttribute>();
            BasePanel panel = panelDict.TryGet(type.FullName);
            if (panel == null)
            {
                panel = Activator.CreateInstance(type) as BasePanel;
                GameObject game = Main.GetMagr<ResourceManager>().LoadAsset(new LoadResHandle<GameObject>(attribute));
                if(game==null)
                {
                    Log.Error($"未加载到【{type}】UI实体,请检查实体路径是否正确！");
                    return panel;
                }
                panel.UIEntity = Instantiate(game);
                if (!string.IsNullOrEmpty(attribute.WorlUIDomain))
                {
                    if (!_worldUIDomain.ContainsKey(attribute.WorlUIDomain))
                        Log.Error($"UI【{game.name}】执行文件【{type.Name}】的作用域未注册，请确定其作用域对象挂载了【WorldUIDomain】脚本！");
                    else
                        panel.UIEntity.transform.SetParent(_worldUIDomain[attribute.WorlUIDomain], false);
                }
                panel.OnInit();
                panel.ChangedWord();
                panelDict.Add(type.FullName, panel);
            }

            return panel;
        }

        /// <summary>
        /// 获取已创建的面板
        /// </summary>
        /// <returns></returns>
        public T GetAlreadyHavePanel<T>() where T : BasePanel => panelDict.TryGet(typeof(T).FullName) as T;

        /// <summary>
        /// 获取已创建的面板
        /// </summary>
        /// <returns></returns>
        public BasePanel GetAlreadyHavePanel(string typeFullName) => panelDict.TryGet(typeFullName);

        /// <summary>
        /// 关闭指定UIPanel
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void CloseUI<T>(IPanelData args) where T : BasePanel => CloseUI<T>(false, args);

        public void AddPanelChanged(TAction<BasePanel, BasePanel> action) => OnPanelChanged += action;

        public void RemovePanelChanged(TAction<BasePanel, BasePanel> action) => OnPanelChanged -= action;

        /// <summary>
        /// 切换语言
        /// </summary>
        internal void ChangedWord()
        {
            foreach (var item in panelDict.Values)
            {
                item.ChangedWord();
            }
        }
    }
}
