﻿using System;
using System.Collections;
using JLGames.RocketDriver.Actions.Utils;
using JLGames.RocketDriver.CSharp.Utils;
using UnityEngine;
using UnityEngine.Networking;
using Object = UnityEngine.Object;

namespace JLGames.RocketDriver.Actions.Loaderx
{
    /// <summary>
    /// 注意：
    /// Assetbundle在没有被unload时，无法重新加载同一个Assetbundle
    /// 这里针对以上情况进行了兼容处理，可同时调用下载
    /// </summary>
    internal sealed class AbLoader : LoaderBase, ILoader
    {
        internal AbLoader()
        {
            m_BaseInfo = new LoaderBaseInfo();
            m_BundleLoader = new AbBundleLoader(m_BaseInfo);
            m_AssetLoader = new AbAssetLoader(m_BaseInfo);
        }

        public void InitLoader(LoaderSettings settings)
        {
            m_OriginalSettings = settings;
            var abSetting = settings.DefaultBundleSetting;
            SetBaseUri(abSetting.RequestBaseUrl, abSetting.ProjectBasePath);

            CacheInstance.CacheManager.SetHistorySize(abSetting.HistorySize);
            CacheInstance.CacheManager.SetVersionSize(abSetting.VersionSize);
            CacheInstance.CacheManager.SetDisableCache(!abSetting.EnableCache);
            if (abSetting.EnableCache)
            {
                SetCacheSetting(abSetting.CacheName, abSetting.CachePath);
            }

            var mono = LoaderManager.Mono;
            if (abSetting.AssetReleaseMode == BundleReleaseMode.Time)
            {
                mono.GetComponent<LoaderMonoBehaviour>()
                    .StartTimeReleaseAction(abSetting.AssetReleaseTimeInterval);
            }
            else if (abSetting.AssetReleaseMode == BundleReleaseMode.Counter)
            {
                mono.GetComponent<LoaderMonoBehaviour>()
                    .StartCounterReleaseAction(abSetting.AssetReleaseCounterInterval);
            }
        }

        public void SetBaseUri(string baseReqUri, string baseLocUri)
        {
            if (string.IsNullOrEmpty(baseReqUri) || string.IsNullOrEmpty(baseLocUri))
            {
                throw LoaderErrors.ErrorUriEmpty;
            }

            m_BaseInfo.SetBaseReqUri(UnityPathUtil.CombineUnityPath(baseReqUri, LoaderDefine.PlatformName));
            m_BaseInfo.SetBaseLocUri(baseLocUri);
        }

        public void SetCacheSetting(string cacheName, string cachePath)
        {
            if (string.IsNullOrEmpty(cacheName))
            {
                throw LoaderErrors.ErrorCachePathEmpty;
            }

            if (!string.IsNullOrEmpty(cachePath))
            {
                cachePath = UnityPathUtil.Format2UnityPath(cachePath);
                if (!cachePath.EndsWith("/"))
                {
                    cachePath = cachePath + "/";
                }
            }

            m_BaseInfo.SetCacheName(cacheName);
            m_BaseInfo.SetCachePath(cachePath);
        }

        //多层异步资源加载------------------------------------------------------------

        public IEnumerator LoadAssetAsync<T>(string bundleName, string assetPath,
            LoaderDelegate.OnAssetWithBundleLoaded<T> onLoaded,
            bool autoRelease = true, bool unloadObjects = false) where T : Object
        {
            if (string.IsNullOrEmpty(bundleName) || string.IsNullOrEmpty(assetPath))
            {
                throw LoaderErrors.ErrorNameEmpty;
            }

            if (!UnderVersionCache)
            {
                yield break;
            }

            var dep = m_BundleLoader.BundleVersion.GetDependencies(bundleName);
            var names = ArrayUtil.MergeArray(dep, bundleName);

            BundleRef bundleRef = null;

            if (names.Length == 1)
            {
                yield return LoaderManager.Mono.StartCoroutine(LoadBundleAsync(names[0], (@ref, suc) =>
                {
                    if (suc)
                    {
                        bundleRef = @ref;
                        bundleRef.SetTempBundle();
                    }
                }, autoRelease, unloadObjects));

                if (null == bundleRef)
                {
                    Internal.ApplyAssetWithBundleCallback(onLoaded, null, null, false);
                    yield break;
                }

                yield return LoaderManager.Mono.StartCoroutine(LoadAssetAsync<T>(assetPath, bundleRef.Bundle,
                    ((asset, suc) => { Internal.ApplyAssetWithBundleCallback(onLoaded, bundleRef, asset, suc); })));
                bundleRef.ReleaseTemp();
            }
            else
            {
                BundleRef[] bundleRefs = null;
                yield return LoaderManager.Mono.StartCoroutine(LoadMultiBundleAsync(names, (refs, suc) =>
                {
                    if (suc)
                    {
                        foreach (var @ref in refs)
                        {
                            @ref.SetTempBundle();
                        }

                        bundleRefs = refs;
                        bundleRef = refs[refs.Length - 1];
                    }
                }, autoRelease, unloadObjects));

                if (null == bundleRef)
                {
                    Internal.ApplyAssetWithBundleCallback(onLoaded, null, null, false);
                    yield break;
                }

                yield return LoaderManager.Mono.StartCoroutine(LoadAssetAsync<T>(assetPath, bundleRef.Bundle,
                    (asset, suc) => { Internal.ApplyAssetWithBundleCallback(onLoaded, bundleRef, asset, suc); }));

                for (var index = bundleRefs.Length - 1; index >= 0; index--)
                {
                    bundleRefs[index].ReleaseTemp();
                }
            }
        }
    }

    internal struct AssetBundleLoaderRequest : IDisposable
    {
        public string BundleName;
        public UnityWebRequest WebRequest;
        public AssetBundleCreateRequest FileRequest;
        public CachedAssetBundle Cached;
        public bool OnCaching;

        public void Dispose()
        {
            WebRequest?.Dispose();
        }
    }
}