using XGame.Framework.i18n;
using System;
using System.Collections.Generic;
using XGame.Framework.Quality;
using XGame.Framework.Asyncs;

namespace XGame.Framework.Asset
{
    public sealed partial class AssetManager : IAssetManager, IAsyncListener, IAssetCacheHandle
    {
        private enum OperateState : byte
        {
            None = 0,
            Prepare,
            Start,
            //End,
        }


        AssetRepository Repository { set; get; }
        Dictionary<string, IAssetAsync> AssetAsyncMap { set; get; }
        private List<IAsync> LoadingAsyncs { set; get; }
        IAssetLoader Loader { set; get; }
        IAddressableHandle AddressableHandler { set; get; }

        private LanguageType _languageType;
        private XQualityLevel _quality;

        private IAsync _disposeAsync;
        private bool _isDispose;

        private OperateState _unloadunusedOp;
        public AssetManager()
        {
            Repository = new AssetRepository();
            AssetAsyncMap = new Dictionary<string, IAssetAsync>();
            LoadingAsyncs = new List<IAsync>();
            //AsyncPool = new AssetAsyncPool(new AssetAsyncAgentBuilder());
            //AsyncPool.AgentLimit = 10;
            Loader = new LoaderBuilder().Build();
            AddressableHandler = Loader as IAddressableHandle;
            _isDispose = false;
            _unloadunusedOp = OperateState.None;
        }

        TResult IAssetManager.LoadSync<TResult>(string addressableName)
        {
            if (_isDispose) return default;
            addressableName = AddressableHandler.ConvertAddressableName(new ConvertOptions(){
                addressableName = addressableName,
                quality = _quality,
                langType = _languageType
            }); //addressableName?.ToLower();
            var result = Repository.Clone(addressableName);
            if (result != null)
            {
                return result.Convert<TResult>(addressableName);
            }
            result = Loader.LoadSync<TResult>(addressableName);
            if (result != null)
            {
                var asset = AssetCreator.Create(addressableName, result);
                Repository.AddAsset(asset);
                result = Repository.Clone(addressableName);
                return result.Convert<TResult>(addressableName);
            }
            return default;
        }
        IAssetLoadAsync<TResult> IAssetManager.LoadAsync<TResult>(string addressableName)
        {
            if (_isDispose) return default;
            addressableName = AddressableHandler.ConvertAddressableName(new ConvertOptions()
            {
                addressableName = addressableName,
                quality = _quality,
                langType = _languageType
            }); //addressableName?.ToLower();

            IAssetAsync assetAsync = null;
            if (!Repository.ContainsAsset(addressableName))
            { //仓库中没找到资源
                //先取未完成的async
                if (!AssetAsyncMap.TryGetValue(addressableName, out assetAsync))
                {
                    assetAsync = Loader.LoadAsync<TResult>(addressableName);//未加载
                    if (assetAsync != null)
                    {
                        AssetAsyncMap.Add(assetAsync.AddressableName, assetAsync);
                        assetAsync.On(OnAssetAsyncCompleted);
                        //这里多做一个监听，且order要保证该监听在Async的最后执行
                        assetAsync.On(this, int.MaxValue);
                    }
                }
            }
            //
            var loadAsync = new AssetLoadAsync<TResult>(addressableName, assetAsync, this);
            LoadingAsyncs.Add(loadAsync);
            return loadAsync;
        }
        void IAssetManager.Recycle(object obj)
        {
            Repository.Recycle(obj);
        }
        void IAssetManager.StopAsync<TResult>(IAssetLoadAsync<TResult> async)
        {
            //这里只能停止业务的监听事件，不能停止AssetAsync的事件
            async.RemoveAll();
            //((AssetResultAsync<TResult>)async).StopAsync();
        }

        void IAssetManager.UnloadUnusedAssets()
        {
            if (_unloadunusedOp != OperateState.None)
                return;
            if (AssetAsyncMap.Count <= 0)
            {
                InnerUnloadUnusedAssets();
            }
            else
            {
                _unloadunusedOp = OperateState.Prepare;
            }
        }

        IAsync IAssetManager.LoadSceneBundle(string sceneName)
        {
            if (_isDispose || string.IsNullOrEmpty(sceneName)) return default;
            sceneName = sceneName.ToLower();
            IAssetAsync bundleAsync = null;
            if (!Repository.ContainsAsset(sceneName))
            { //仓库中没找到资源
                //先取未完成的async
                if (!AssetAsyncMap.TryGetValue(sceneName, out bundleAsync))
                {
                    bundleAsync = Loader.LoadSceneBundleAsync(sceneName);//未加载
                    if (bundleAsync != null)
                    {
                        AssetAsyncMap.Add(bundleAsync.AddressableName, bundleAsync);
                        bundleAsync.On(OnAssetAsyncCompleted);
                        //这里多做一个监听，且order要保证该监听在Async的最后执行
                        bundleAsync.On(this, int.MaxValue);
                    }
                }
            }
            return bundleAsync;
        }

        void IAssetManager.UnLoadSceneBundle(string sceneName)
        {
            Loader.UnLoadSceneBundle(sceneName);
        }

        private void InnerUnloadUnusedAssets()
        {
            _unloadunusedOp = OperateState.Start;
            Repository.UnloadUnusedAssets(((assetPath, source) =>
            {
                Loader.Unload(assetPath, source);
            }));
            Loader.UnloadUnusedAssets();
            _unloadunusedOp = OperateState.None;
        }

        //void IDisposable.Dispose()
        //{
        //    //AsyncPool.Dispose();
        //    Repository.Dispose();
        //    (Loader as IDisposable)?.Dispose();
        //    Loader = null;
        //    AssetAsyncMap.Clear();
        //}

        IAsync IAssetManager.Dispose()
        {
            var async = new ManagerDisposeAsync();
            _isDispose = true;
            if (AssetAsyncMap.Count == 0)
            {
                InnerDispose();
                async.Completed();
                return async;
            }
            _disposeAsync = async;
            return _disposeAsync;
        }
        private void InnerDispose()
        {
            Repository.Dispose();
            (Loader as IDisposable)?.Dispose();
            Loader = null;
            AddressableHandler = null;
            AssetAsyncMap.Clear();
            for(var  i = LoadingAsyncs.Count - 1; i >= 0; i--)
            {
                LoadingAsyncs[i].RemoveAll();
            }
            LoadingAsyncs.Clear();
            _disposeAsync = null;
            Monitor.AssetsMonitor.Dispose();
        }
        private void SetLangueType(LanguageType langType)
        {
            _languageType = langType;
        }

        private void SetQuality(XQualityLevel quality)
        {
            _quality = quality;
        }
        /// <summary>
        /// 转换AddressableName
        /// 会根据游戏当前语言、品质等级返回对应的AddressableName
        /// </summary>
        /// <param name="addressableName"></param>
        /// <returns></returns>
        string IAssetManager.ConvertAddressableName(string addressableName)
        {
            return AddressableHandler?.ConvertAddressableName(new ConvertOptions()
            {
                addressableName = addressableName,
                quality = _quality,
                langType = _languageType,
            }) ?? addressableName;
        }
        object IAssetCacheHandle.GetAssetFromCache(string addressableName)
        {
            return Repository.Clone(addressableName);
        }

        void IAssetCacheHandle.ReleaseAsync(IAsync async)
        {
            LoadingAsyncs.Remove(async);
        }
        void IAssetCacheHandle.SetPreloadTag(string addressableName, bool isPreload)
        {
            Repository.SetPreloadSign(addressableName, isPreload);
        }

        #region 内部函数
        /// <summary>
        /// 该监听回调需要保证在IAssetAsync的Completed最后回调
        /// 用于释放资源或者Dispose
        /// </summary>
        /// <param name="aAsync"></param>
        void IAsyncListener.OnAsyncCompleted(IAsync aAsync)
        {
            if (AssetAsyncMap.Count <= 0)
            {
                if (_unloadunusedOp != OperateState.None)
                {
                    InnerUnloadUnusedAssets();
                }
                if (_isDispose)
                {
                    var async = _disposeAsync;
                    InnerDispose();
                    (async as Async)?.Completed();
                }
            }
        }

        private void OnAssetAsyncCompleted(IAsync async)
        {
            if (async is IAssetAsync assetAsync)
            {
                AssetAsyncMap.Remove(assetAsync.AddressableName);

                var result = assetAsync.GetResult();
                if (result != null)
                {
                    var asset = AssetCreator.Create(assetAsync.AddressableName, result);
                    Repository.AddAsset(asset);
                }
            }
        }
        #endregion

    }
}

