using System;
using System.Collections.Generic;
using UnityEngine;
using XGame.Framework.Asset;
using XGame.Framework.Asyncs;
using XGame.Framework.Interfaces;

namespace XGame.Framework.UI
{
    public class UIModule : IUIModule, IUpdate, ILateUpdate, IUIContextSetter, IDisposable, IUIAssetModuleCreator
    {
        private UIContext _context;
        private IUITree _uitree;
        private IAssetModule _assetModule;
        /// <summary>
        /// 加载中的
        /// </summary>
        private Dictionary<string, IAsync> _loadingMap;
        /// <summary>
        /// 已打开的UI
        /// </summary>
        private Dictionary<string, IUIView> _openedMap;
        /// <summary>
        /// 已关闭的UI
        /// </summary>
        private Dictionary<string, IUIView> _closedMap;
        /// <summary>
        /// Update 和 LateUpdate用
        /// </summary>
        private List<IUIView> _updates;
        public UIModule(IAssetModule assetModule, IUITree uitree)
        {
            _assetModule = assetModule;
            _uitree = uitree;
            _loadingMap = new Dictionary<string, IAsync>();
            _openedMap = new Dictionary<string, IUIView>();
            _closedMap = new Dictionary<string, IUIView>();
            _updates = new List<IUIView>();
        }
        public UIContext Context { get => _context; set => _context = value; }
        #region 接口实现
        Camera IUIModule.Camera => _uitree.Camera;


        Canvas IUIModule.GetCanvas(UILayer layer)
        {
            return _uitree.GetCanvas(layer);
        }

        IAsync IUIModule.OpenAsync(UIKey uikey, object intent)
        {
            string key = uikey;
            if (_loadingMap.ContainsKey(key))
            {
                return _loadingMap[key];
            }
            var asyncGroup = new AsyncGroup();
            if (_openedMap.ContainsKey(key))
            {
                Log.Warn($"重复开启UI:{key}");
            }
            else if (_closedMap.TryGetValue(key, out var closedView))
            { // 已关闭的UI
                asyncGroup.On(_ =>
                {
                    _closedMap.Remove(key);
                    _uitree.SetAsLastSibling(closedView.Panel);
                    closedView.Enable(intent);
                    _openedMap.Add(key, closedView);
                });
            }
            else
            {
                _loadingMap.Add(key, asyncGroup);
                var loadAsync = _assetModule.LoadAsync<UIPanel>(key);
                loadAsync.Join(asyncGroup);
                loadAsync.On(_ =>
                {
                    _loadingMap.Remove(key);
                    var panel = loadAsync.Result;
                    if (panel == null)
                    {
                        Log.Error($"UI加载结果为空. UIKey:{key}");
                        return;
                    }
                    var view = Activator.CreateInstance(uikey.UIViewType) as IUIView;
                    var context = _context.Clone();
                    (context as IUIViewAdapter).Key = uikey;
                    (view as UIView).Init(context, panel);
                    _uitree.AddPanel(panel);
                    view.Enable(intent);
                    _openedMap.Add(key, view);
                });
            }
            asyncGroup.End();
            return asyncGroup;
        }
        void IUIModule.Close(UIKey uikey, bool isDestroy)
        {
            var key = uikey.Key;
            if (_loadingMap.TryGetValue(key, out var async))
            {
                _loadingMap.Remove(key);
                async.RemoveAll();
                return;
            }
            if (_openedMap.TryGetValue(key, out var uiView))
            {
                _openedMap.Remove(key);
                uiView.Disable();
                if (isDestroy)
                {
                   DestroyUIView(uiView);
                }
                else
                {
                    _closedMap.Add(key, uiView);
                }
                return;
            }
            if (isDestroy && _closedMap.TryGetValue(key, out uiView))
            {
                _closedMap.Remove(key);
                DestroyUIView(uiView);
            }
        }
        IAsync IUIModule.Preload(UIKey uikey)
        {
            var loadAsync = _assetModule.PreloadAsync<UIPanel>(uikey);
            return loadAsync;
        }

        void IUpdate.Update(int millisecond)
        {
            if (_openedMap.Count == 0)
                return;
            _updates.Clear();
            _updates.AddRange(_openedMap.Values);
            for(var i = 0; i < _updates.Count;)
            {
                var view = _updates[i];
                view.Update(millisecond);
                if (view.Active)
                {
                    i++;
                }
                else
                {
                    _updates.RemoveAt(i);
                }
            }
        }

        void ILateUpdate.LateUpdate(int millisecond)
        {
            if (_updates.Count == 0)
                return;
            foreach (var uiview in _updates)
            {
                uiview.LateUpdate(millisecond);
            }
            _updates.Clear();
        }

        void IDisposable.Dispose()
        {
            _updates.Clear();
            foreach (var async in _loadingMap.Values)
            {
                async.RemoveAll();
            }
            _loadingMap.Clear();
            foreach (var uiview in _closedMap.Values)
            {
                DestroyUIView(uiview);
            }
            _closedMap.Clear();
            foreach (var uiview in _openedMap.Values)
            {
                DestroyUIView(uiview);
            }
            _openedMap.Clear();
            (_uitree as IDisposable)?.Dispose();
            (_assetModule as IDisposable)?.Dispose();
            _assetModule = null;
            _context = null;
        }

        IUIAssetModule IUIAssetModuleCreator.Create(UIContext context)
        {
            return new UIAssetModule(context);
        }
        #endregion

        #region 内部函数
        private void DestroyUIView(IUIView view)
        {
            var uiPanel = view.Panel as UIPanel;
            (view as IDisposable).Dispose();
            _assetModule.Recycle(uiPanel.gameObject, true);
        }
        #endregion
    }
}
