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

namespace XGame.Framework.Map
{
    public class MapModule : IMapModule, IUpdate, ILateUpdate, IMapContextSetter, IDisposable
    {
        private MapContext _context;
        private Transform _mapRoot;
        private IAssetModule _assetModule;
        /// <summary>
        /// 加载中的
        /// </summary>
        private Dictionary<string, IAsync> _loadingMap;
        /// <summary>
        /// 已打开的
        /// </summary>
        private Dictionary<string, IMapView> _openedMap;
        /// <summary>
        /// 已关闭的
        /// </summary>
        private Dictionary<string, IMapView> _closedMap;
        /// <summary>
        /// pdate 和 LateUpdate用
        /// </summary>
        private List<IMapView> _updates;

        public MapModule(IAssetModule assetModule, Transform root)
        {
            _assetModule = assetModule;
            _mapRoot = root;
            _loadingMap = new Dictionary<string, IAsync>();
            _openedMap = new Dictionary<string, IMapView>();
            _closedMap = new Dictionary<string, IMapView>();
            _updates = new List<IMapView>();
        }
        #region 接口实现
        public MapContext Context { get => _context; set => _context = value; }

        IAsync IMapModule.RunAsync(MapKey mapKey, object intent)
        {
            string key = mapKey;
            if (_loadingMap.ContainsKey(key))
            {
                return _loadingMap[key];
            }
            var asyncGroup = new AsyncGroup();
            if (_openedMap.ContainsKey(key))
            {
                Log.Warn($"重复打开地图:{key}");
            }
            else if (_closedMap.TryGetValue(key, out var closedView))
            { //已关闭的地图
                asyncGroup.On(_ =>
                {
                    _closedMap.Remove(key);
                    closedView.Behaviour.transform.SetAsLastSibling();
                    closedView.Enable(intent);
                    _openedMap.Add(key, closedView);
                });
            }
            else
            {
                _loadingMap.Add(key, asyncGroup);
                var loadAsync = _assetModule.LoadAsync<MapBehaviour>(key);
                loadAsync.Join(asyncGroup);
                loadAsync.On(_ =>
                {
                    _loadingMap.Remove(key);
                    var behaviour = loadAsync.Result;
                    if (behaviour == null)
                    {
                        Log.Error($"地图加载结果为空. MapKey:{key}");
                        return;
                    }
                    var view = Activator.CreateInstance(mapKey.MapViewType) as IMapView;
                    (view as IMapContextSetter).Context = _context.Clone();
                    view.Behaviour = behaviour;
                    behaviour.transform.SetParent(_mapRoot, false);
                    view.Enable(intent);
                    _openedMap.Add(key, view);
                });
            }
            asyncGroup.End();
            return asyncGroup;
        }
        void IMapModule.Close(MapKey mapKey, bool isDestroy)
        {
            if (mapKey == null)
                return;
            var key = mapKey.Key;
            if (_loadingMap.TryGetValue(key, out var async))
            {
                _loadingMap.Remove(key);
                async.RemoveAll();
                return;
            }
            if (_openedMap.TryGetValue(key, out var mapView))
            {
                _openedMap.Remove(key);
                mapView.Disable();
                if (isDestroy)
                {
                    DestroyView(mapView);
                }
                else
                {
                    _closedMap.Add(key, mapView);
                }
                return;
            }
            if (isDestroy && _closedMap.TryGetValue(key, out mapView))
            {
                _closedMap.Remove(key);
                DestroyView(mapView);
            }
        }

        IAsync IMapModule.Preload(MapKey mapKey)
        {
            var loadAsync = _assetModule.PreloadAsync<MapBehaviour>(mapKey);
            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)
            {
                DestroyView(uiview);
            }
            _closedMap.Clear();
            foreach (var uiview in _openedMap.Values)
            {
                DestroyView(uiview);
            }
            _openedMap.Clear();
            GameObject.Destroy(_mapRoot.gameObject);
            (_assetModule as IDisposable)?.Dispose();
            _assetModule = null;
            _context = null;
        }
        #endregion

        private void DestroyView(IMapView view)
        {
            var behaviour = view.Behaviour;
            (view as IDisposable).Dispose();
            _assetModule.Recycle(behaviour.gameObject, true);
        }
    }
}