using XGame.Framework.Asyncs;
using XGame.Framework.Utils;
using UnityEngine;

namespace XGame.Framework.Asset
{
    /// <summary>
    /// AssetBundle的加载方式，需要先实现Bundle的Manifest管理
    /// </summary>
    internal partial class AssetBundleLoader
    {
        /// <summary>
        /// 创建从Repository获取Asset的异步
        /// Repository没缓存时则返回Null
        /// </summary>
        /// <param name="addressableName"></param>
        /// <returns></returns>
        AssetLoadFromCacheAsync CreateAssetFromCacheAsync(string addressableName)
        {
            var source = Repository.PopUnusedAsset(addressableName);
            if (source != null)
            {
                var assetAsync = new AssetLoadFromCacheAsync()
                {
                    AddressableName = addressableName,
                    Source = source,
                };
                return assetAsync;
            }
            return null;
        }
        ///// <summary>
        ///// 创建加载Asset的异步
        ///// </summary>
        ///// <param name="assetPath"></param>
        ///// <returns></returns>
        //AssetLoadFromBundleAsync CreateAssetLoadFromBundleAsync(string assetPath)
        //{
        //    var assetAsync = AsyncPool.GetAssetAsync(assetPath) as AssetLoadFromBundleAsync;
        //    if (assetAsync == null)
        //    {
        //        assetAsync = new AssetLoadFromBundleAsync
        //        {
        //            Path = assetPath
        //        };
        //        //记录当前加载的AssetPath
        //        LoadingAssets.Add(assetPath);
        //        assetAsync.On(OnAssetCompleted);
        //    }
        //    return assetAsync;
        //}
        /// <summary>
        /// 创建加载Bundle的异步
        /// </summary>
        /// <param name="bundleName"></param>
        /// <returns></returns>
        IAssetAsync CreateBundleAsync(string bundleName)
        {
            //var path = FileUtil.GetAssetBundlePath(bundleName);
            if (Repository.ContainsBundle(bundleName))
                return null;
            var assetAsync = AsyncPool.GetAssetAsync(bundleName);
            if (assetAsync != null)
                return assetAsync;
            AssetBundleCreateRequestAsync requestAsync = new AssetBundleCreateRequestAsync
            {
                Path = FileUtils.GetAssetBundlePath(bundleName),
                AddressableName = bundleName,
                Offset = GetBundleOffest(bundleName)
            };
            requestAsync.On(OnBundleCompleted);
            //AsyncPool.AddAsync(requestAsync);
            return requestAsync;
        }
        /// <summary>
        /// AssetBundleCreateRequestAsync的回调监听
        /// </summary>
        /// <param name="async"></param>
        void OnBundleCompleted(IAsync async)
        {
            if (async is IAssetAsync assetAsync)
            {
                var bundleName = assetAsync.AddressableName;
                var result = assetAsync.GetResult();
                var bundleAsset = Repository.GetBundle(bundleName);
                if (bundleAsset != null)
                {
                    //bundleAsset.Retain();
                    AssetsLog.Warn("Bundle load repeated. Name:{0} Last:{1} Next:{2}", bundleName, bundleAsset.Source.GetLongHashCode(), result?.GetLongHashCode());
                    return;
                }
                bundleAsset = AssetCreator.Create(bundleName, result) as BundleAsset;
                if (bundleAsset != null)
                {
                    Repository.AddBundle(bundleAsset);
                }
                else
                {
                    AssetsLog.Error("Load bundle failed. Bundle:{0}", bundleName);
                }
            }
        }
        /// <summary>
        /// AssetLoadFromBundleAsync的回调监听
        /// </summary>
        /// <param name="async"></param>
        void OnAssetCompleted(IAsync async)
        {
            if (async is AssetLoadFromBundleAsync assetAsync)
            {
                int assetHash = assetAsync.AssetHash;
                var assetName = assetAsync.AddressableName;
                //删除当前加载的AssetPath
                //LoadingAssets.Remove(assetPath);
                if (assetHash == 0)
                {
                    AssetsLog.Error($"AssetBundle load failed. Asset is null. Name:{assetName}");
                    return;
                }
                //记录hash
                if (!Repository.RegistAssetHash(assetHash, assetName))
                {
                    //发现重复的Hash记录，不需要再重复记录Bundle的引用计数
                    //出现重复的原因是异步加载Asset后又使用同步加载了同一个Asset
                    return;
                }

                if (TryGetBundleInfo(assetName, out string bundleName, out string[] dependencies))
                {
                    //增加依赖bundle的引用计数
                    //string bundlePath = FileUtil.GetAssetBundlePath(bundleName);
                    Repository.RetainBundle(bundleName);
                    if (dependencies != null)
                    {
                        foreach (var dep in dependencies)
                        {
                            //var depBundlePath = FileUtil.GetAssetBundlePath(dep);
                            Repository.RetainBundle(dep);
                        }
                    }
                }
            }

        }

        /// <summary>
        /// 异步加载scene的回调
        /// </summary>
        /// <param name="async"></param>
        void OnSceneComplete(IAsync async)
        {
            if (async is SceneLoadAsync sceneAsync)
            {
                var assetName = sceneAsync.AddressableName;
                if (TryGetBundleInfo(assetName, out string bundleName, out string[] dependencies))
                {
                    //sceneBundle在这里添加到Reponsitory
                    var sceneBundle = Repository.GetBundle(bundleName);
                    if (sceneBundle != null)
                    {
                        AssetsLog.Warn("Bundle load repeated. Name:{0} Last:{1}", bundleName, sceneBundle.Source.GetLongHashCode());
                        return;
                    }

                    //更新引用计数
                    Repository.RetainBundle(bundleName);
                    if (dependencies != null)
                    {
                        foreach (var dep in dependencies)
                        {
                            Repository.RetainBundle(dep);
                        }
                    }
                }
            }
        }

        AssetBundle GetAssetBundleByName(string bundleName)
        {
            var bundleAsset = Repository.GetBundle(bundleName);
            return bundleAsset?.Source as AssetBundle;
        }
    }
}
