using System;
using System.Collections.Generic;
using System.Linq;
using FairyGUI;
using NBC.Asset;
using UnityEngine;

namespace NBC
{
    public class UIManager : EventDispatcher
    {
        /// <summary>
        /// 所有UI
        /// </summary>
        private readonly Dictionary<string, IUIPanel> _uiArray = new Dictionary<string, IUIPanel>();

        private GGraph _modalLayer;
        private GRoot _uiRoot;

        private UIComponentLanguagePack _uiLanguageConfig;

        // 新增 Tween 配置
        private UIComponentTweenPack _uiTweenConfig;

        public void Start()
        {
            Log.Info("UI 模块初始化");
            _uiRoot = GRoot.inst;
            MonoManager.Inst.OnUpdate += Update;
            UICommand.Init(this);
        }

        public void Quit()
        {
            MonoManager.Inst.OnUpdate -= Update;
        }

        void Update()
        {
            UIRunner.Update();
            foreach (var panel in _uiArray.Values)
            {
                if (panel != null && panel.IsShowing)
                {
                    panel.Update();
                }
            }
        }

        #region 内部方法

        internal void ShowUI(string uiName, object param = null)
        {
            IUIPanel panel = GetUI(uiName);
            panel.SetData(param);
            if (panel.IsShowing)
            {
                panel.Refresh();
            }
            else
            {
                ApplyPanelRootTween(panel); // 根动效设置为 ShowAnim
                panel.Show();
            }
        }

        internal void RemoveUI(string uiName)
        {
            IUIPanel wind = GetUI(uiName);
            if (wind == null)
            {
                Log.Warning($"要删除的界面不存在:{uiName}");
                return;
            }

            if (!wind.IsDotDel)
            {
                wind.Dispose();
                _uiArray.Remove(uiName);
            }
        }

        private void CreateModalLayer()
        {
            var modalLayerColor = UIConfig.modalLayerColor;

            if (_modalLayer != null)
            {
                _modalLayer.onClick.Clear();
            }

            _modalLayer = new GGraph();
            _modalLayer.DrawRect(_uiRoot.width, _uiRoot.height, 0, Color.white,
                modalLayerColor);
            _modalLayer.AddRelation(_uiRoot, RelationType.Size);
            _modalLayer.name = _modalLayer.gameObjectName = "ModalLayer";
            _modalLayer.SetHome(_uiRoot);
        }

        #endregion

        #region 动画

        public void SetUITween<T>() where T : UIComponentTweenPack
        {
            _uiTweenConfig = Activator.CreateInstance<T>();
        }

        public void TryPlayComponentTween(GComponent component)
        {
            _uiTweenConfig?.TryPlayComponentTween(component);
        }

        public void TryPlayPanelTween(GComponent component)
        {
            _uiTweenConfig?.TryPlayPanelTween(component);
        }

        private void ApplyPanelRootTween(IUIPanel panel)
        {
            if (panel?.ContentPane == null || _uiTweenConfig == null) return;
            var url = panel.ContentPane.resourceURL;
            if (string.IsNullOrEmpty(url)) return;
            var tweenName = _uiTweenConfig.GetRootTween(url);
            if (string.IsNullOrEmpty(tweenName)) return;
            if (panel is not UIPanel upPanel) return; // 需要具体 UIPanel 才能设置 ShowAnim

            if (upPanel.ShowAnim != null) return;
            switch (tweenName)
            {
                case "Fade": upPanel.ShowAnim = UIPanelAnimation.GetFade(upPanel); break;
                case "Scale": upPanel.ShowAnim = UIPanelAnimation.GetCenterScaleBig(upPanel); break;
                case "Pop": upPanel.ShowAnim = UIPanelAnimation.GetCenterPopScaleFade(upPanel); break;
                case "SlideInL": upPanel.ShowAnim = UIPanelAnimation.GetLeftToSlideFade(upPanel); break;
                case "SlideInR": upPanel.ShowAnim = UIPanelAnimation.GetRightToSlideFade(upPanel); break;
                case "SlideInT": upPanel.ShowAnim = UIPanelAnimation.GetUpToSlideFade(upPanel); break;
                case "SlideInB": upPanel.ShowAnim = UIPanelAnimation.GetDownToSlideFade(upPanel); break;
                case "Bounce": upPanel.ShowAnim = UIPanelAnimation.GetBounceVertical(upPanel); break;
                case "Rotate": upPanel.ShowAnim = UIPanelAnimation.GetRotate(upPanel); break;
                case "Shake": upPanel.ShowAnim = UIPanelAnimation.GetShake(upPanel); break;
                default: break;
            }
        }

        #endregion

        public void OpenUI<T>(object param = null)
        {
            Type type = typeof(T);

            OpenUI(type.Name, type, param);
        }

        public void OpenUI(Type type, object param = null)
        {
            OpenUI(type.Name, type, param);
        }

        public void OpenUI<T>(string uiName, object param = null,
            Action<IUIPanel> callback = null)
        {
            Type type = typeof(T);
            OpenUI(uiName, type, param, callback);
        }

        public void OpenUI(string uiName, Type type, object param = null,
            Action<IUIPanel> callback = null)
        {
            UICommand.GetCmd(UICmdType.Show).SetUIData(type, uiName, param).SetCallback(callback).Run();
        }

        internal void AddUI(string uiName, IUIPanel panel)
        {
            if (_uiArray.ContainsKey(uiName))
            {
                Log.Error("AddUI重复添加");
            }

            _uiArray.Add(uiName, panel);
        }

        public T GetUI<T>() where T : class
        {
            IUIPanel wind = null;
            Type type = typeof(T);
            var uiName = type.Name;
            foreach (var name in _uiArray.Keys)
            {
                if (name != uiName) continue;
                wind = _uiArray[name];
                break;
            }

            return wind as T;
        }

        public IUIPanel GetUI(Type type)
        {
            return GetUI(type.Name);
        }

        public IUIPanel GetUI(string uiName)
        {
            IUIPanel wind = null;
            foreach (var name in _uiArray.Keys)
            {
                if (name != uiName) continue;
                wind = _uiArray[name];
                break;
            }

            return wind;
        }

        public IUIPanel[] GetAllUI()
        {
            return _uiArray.Values.ToArray();
        }

        public List<string> GetAllUIName()
        {
            return _uiArray.Keys.ToList();
        }

        public void HideUI(Type type)
        {
            HideUI(type.Name);
        }

        public void HideUI<T>()
        {
            Type type = typeof(T);
            HideUI(type.Name);
        }

        public void HideUI(string uiName)
        {
            UICommand.GetCmd(UICmdType.Hide).SetUIData(null, uiName, null).Run();
        }


        /// <summary>
        /// 隐藏所有窗口
        /// </summary>
        public void HideAllUI(bool isDotDel = false)
        {
            var names = GetAllUIName();
            foreach (var uiName in names)
            {
                IUIPanel panel = GetUI(uiName);
                if (panel.IsShowing)
                {
                    if (!panel.IsDotDel || isDotDel)
                    {
                        HideUI(uiName);
                    }
                }
            }
        }

        /// <summary>
        /// 删除所有打开的窗口
        /// </summary>
        public void DeleteAllUI()
        {
            var names = GetAllUIName();
            foreach (var uiName in names)
            {
                DestroyUI(uiName);
            }
        }

        public void DestroyUI<T>()
        {
            Type type = typeof(T);
            DestroyUI(type.Name);
        }

        public void DestroyUI(Type type)
        {
            DestroyUI(type.Name);
        }

        public void DestroyUI(string uiName)
        {
            UICommand.GetCmd(UICmdType.Del).SetUIData(null, uiName, null).Run();
        }

        public void BringToFront(IUIPanel uiPanel)
        {
            var uiRoot = GRoot.inst;
            var contentPane = uiPanel.ContentPane;
            if (contentPane.parent != uiRoot)
            {
                Log.Error("不在root内，无法置顶==");
                return;
            }

            var cnt = uiRoot.numChildren;
            var i = 0;
            if (_modalLayer != null && _modalLayer.parent != null && !uiPanel.IsModal)
            {
                i = uiRoot.GetChildIndex(_modalLayer);
            }
            else
            {
                i = cnt - 1;
            }

            if (i >= 0)
            {
                uiRoot.SetChildIndex(contentPane, i);
            }
        }

        public bool IsTop(IUIPanel uiPanel)
        {
            var parent = uiPanel.ContentPane.parent;
            if (parent == null) return false;
            var sortingOrder = uiPanel.ContentPane.sortingOrder;
            var maxIndex = -1;
            var panels = _uiArray.Values;
            foreach (var panel in panels)
            {
                if (panel.IsShowing && panel.ContentPane.sortingOrder == sortingOrder)
                {
                    //只判断同层级的
                    var index = parent.GetChildIndex(panel.ContentPane);
                    if (index > maxIndex)
                    {
                        maxIndex = index;
                    }
                }
            }

            var uiIndex = parent.GetChildIndex(uiPanel.ContentPane);
            return uiIndex >= maxIndex;
        }

        public void AdjustModalLayer()
        {
            if (_modalLayer == null || _modalLayer.isDisposed)
            {
                CreateModalLayer();
            }

            var showDic = new Dictionary<GObject, IUIPanel>();
            var panels = _uiArray.Values;
            foreach (var panel in panels)
            {
                if (panel.IsShowing)
                {
                    showDic[panel.ContentPane] = panel;
                }
            }

            var cnt = _uiRoot.numChildren;
            for (var i = cnt - 1; i >= 0; i--)
            {
                var g = _uiRoot.GetChildAt(i);
                if (showDic.TryGetValue(g, out var panel))
                {
                    if (panel.IsModal)
                    {
                        if (_modalLayer.parent == null)
                            _uiRoot.AddChildAt(_modalLayer, i);
                        else
                        {
                            _uiRoot.SetChildIndexBefore(_modalLayer, i);
                        }

                        return;
                    }
                }
            }

            if (_modalLayer != null && _modalLayer.parent != null)
            {
                _uiRoot.RemoveChild(_modalLayer);
            }
        }

        public bool IsOpen(string uiName)
        {
            IUIPanel wind = GetUI(uiName);
            return wind != null && wind.IsShowing;
        }

        public void AddPackage(string assetPath)
        {
            AddPackage(UIConst.UIPackRootUrl, assetPath);
        }

        public void AddPackage(string root, string assetPath)
        {
            var path = root + assetPath;
            if (path.StartsWith("Assets/"))
            {
                UIPackage.AddPackage(path, (string name, string extension, Type type,
                    out DestroyMethod method) =>
                {
                    method = DestroyMethod.None;
                    var pro = Assets.LoadAsset(name.Replace("\\", "/") + extension, type);
                    return pro?.Asset;
                });
            }
            else
            {
                UIPackage.AddPackage(path);
            }
            // UIPackage.AddPackage(path);
        }

        public void OpenSafeArea()
        {
            UIConst.OpenSafeArea = true;
        }

        public void SetSafeArea(Rect rect)
        {
            UIConst.SafeArea = rect;
        }

        public Rect GetSafeArea()
        {
            return UIConst.SafeArea;
        }


        public void SetUILanguage<T>() where T : UIComponentLanguagePack
        {
            _uiLanguageConfig = Activator.CreateInstance<T>();
        }

        public void TrySetComponentLanguage(GComponent component)
        {
            _uiLanguageConfig.TrySetComponentLanguage(component);
        }

        public void TrySetPanelLanguage(GComponent component)
        {
            _uiLanguageConfig.TrySetPanelLanguage(component);
        }
    }
}