﻿using System;
using System.Collections;
using UnityEngine;
using Object = UnityEngine.Object;

namespace JLGames.RocketDriver.Actions.Loaderx
{
    internal sealed class AbAssetLoader : BaseAssetLoader, IAssetLoader
    {
        private readonly LoaderBaseInfo m_BaseInfo;

        internal AbAssetLoader(LoaderBaseInfo baseInfo)
        {
            m_BaseInfo = baseInfo;
        }

        //同步资源加载------------------------------------------------------------

        public override T LoadAssetSync<T>(string assetPath, AssetBundle bundle)
        {
            if (string.IsNullOrEmpty(assetPath))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(assetPath);
            return bundle.LoadAsset<T>(fullPath);
        }

        public override T LoadAssetSyncFull<T>(string fullPath, AssetBundle bundle)
        {
            if (string.IsNullOrEmpty(fullPath))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            return bundle.LoadAsset<T>(fullPath);
        }

        //--子资源(全部)

        public Object[] LoadSubAssetsSync(string path, AssetBundle bundle)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(path);
            return bundle.LoadAssetWithSubAssets(fullPath);
        }

        public Object[] LoadSubAssetsSync(string path, Type type, AssetBundle bundle)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(path);
            return bundle.LoadAssetWithSubAssets(fullPath, type);
        }

        public T[] LoadSubAssetsSync<T>(string path, AssetBundle bundle) where T : Object
        {
            if (string.IsNullOrEmpty(path))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(path);
            return bundle.LoadAssetWithSubAssets<T>(fullPath);
        }

        //--子资源(名称)

        public Object LoadSubAssetSync(string path, string subName, AssetBundle ab)
        {
            var subAssets = LoadSubAssetsSync(path, ab);
            return Internal.FindAsset(subAssets, subName);
        }

        public Object LoadSubAssetSync(string path, string subName, Type type, AssetBundle ab)
        {
            var subAssets = LoadSubAssetsSync(path, type, ab);
            return Internal.FindAsset(subAssets, subName);
        }

        public T LoadSubAssetSync<T>(string path, string subName, AssetBundle ab) where T : Object
        {
            var subAssets = LoadSubAssetsSync<T>(path, ab);
            return Internal.FindAsset(subAssets, subName);
        }

        //--子资源(多个名称)

        public Object[] LoadSubAssetsSync(string path, string[] subNames, AssetBundle bundle)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == subNames)
            {
                throw LoaderErrors.ErrorSubPathEmpty;
            }

            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(path);
            var all = bundle.LoadAssetWithSubAssets(fullPath);
            return Internal.FindAssets(all, subNames);
        }

        public Object[] LoadSubAssetsSync(string path, string[] subNames, Type type, AssetBundle ab)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == subNames)
            {
                throw LoaderErrors.ErrorSubPathEmpty;
            }

            if (null == ab)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(path);
            var all = ab.LoadAssetWithSubAssets(fullPath);
            return Internal.FindAssets(all, subNames, type);
        }

        public T[] LoadSubAssetsSync<T>(string path, string[] subNames, AssetBundle bundle) where T : Object
        {
            if (string.IsNullOrEmpty(path))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == subNames)
            {
                throw LoaderErrors.ErrorSubPathEmpty;
            }

            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(path);
            var all = bundle.LoadAssetWithSubAssets<T>(fullPath);
            return Internal.FindAssets<T>(all, subNames);
        }

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

        public IEnumerator LoadAssetAsync<T>(string assetPath, AssetBundle bundle, LoaderDelegate.OnAssetLoaded<T> onAssetLoaded)
            where T : Object
        {
            if (string.IsNullOrEmpty(assetPath))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(assetPath);
//            DebugUtil.Log("LoadAssetAsync:", fullPath);
            var req = bundle.LoadAssetAsync<T>(fullPath);
            yield return req;
            if (req.isDone && req.asset != null)
            {
                Internal.ApplyAssetCallback(onAssetLoaded, req.asset as T, true);
            }
            else
            {
                Internal.ApplyAssetCallback(onAssetLoaded, null, false);
            }
        }

        public IEnumerator LoadMulitAssetAsync<T>(string[] assetPaths, AssetBundle bundle, LoaderDelegate.OnMultiAssetLoaded<T> onMultiAssetLoaded)
            where T : Object
        {
            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            if (null == assetPaths || 0 == assetPaths.Length)
            {
                Internal.ApplyMultiAssetCallback(onMultiAssetLoaded, null, false);
                yield break;
            }

            var req = bundle.LoadAllAssetsAsync<T>();
            yield return req;
            if (req.isDone && req.allAssets != null && req.allAssets.Length > 0)
            {
                var assets = new T[assetPaths.Length];
                for (var i = 0; i < assetPaths.Length; i++)
                {
                    var needName = m_BaseInfo.GetAssetRelativeFullPath(assetPaths[i]);
                    foreach (var o in req.allAssets)
                    {
                        if (o.name == needName && o.GetType() == typeof(T))
                        {
                            assets[i] = o as T;
                            break;
                        }
                    }
                }

                Internal.ApplyMultiAssetCallback(onMultiAssetLoaded, assets, true);
            }
            else
            {
                Internal.ApplyMultiAssetCallback(onMultiAssetLoaded, null, false);
            }
        }

        public IEnumerator LoadSubAssetsAsync<T>(string assetPath, AssetBundle buundle,
            LoaderDelegate.OnMultiAssetLoaded<T> onAssetsLoaded) where T : Object
        {
            if (string.IsNullOrEmpty(assetPath))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == buundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(assetPath);
//            DebugUtil.Log("LoadAssetAsync:", fullPath);
            var req = buundle.LoadAssetWithSubAssetsAsync<T>(fullPath);
            yield return req;
            if (req.isDone && req.asset != null)
            {
                var assets = req.allAssets;
                T[] rs = null;
                if (assets != null)
                {
                    rs = new T[assets.Length];
                    for (var index = 0; index < assets.Length; index++)
                    {
                        rs[index] = assets[index] as T;
                    }
                }

                Internal.ApplyMultiAssetCallback(onAssetsLoaded, rs, true);
            }
            else
            {
                Internal.ApplyMultiAssetCallback(onAssetsLoaded, null, false);
            }
        }

        public IEnumerator LoadSubAssetAsync<T>(string assetPath, string subName, AssetBundle bundle,
            LoaderDelegate.OnAssetLoaded<T> onAssetLoaded) where T : Object
        {
            if (string.IsNullOrEmpty(assetPath))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            if (null == bundle)
            {
                throw LoaderErrors.ErrorBundleNull;
            }

            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(assetPath);
//            DebugUtil.Log("LoadAssetAsync:", fullPath);
            var req = bundle.LoadAssetWithSubAssetsAsync<T>(fullPath);
            yield return req;
            if (req.isDone && req.asset != null)
            {
                var assets = req.allAssets;
                if (assets != null)
                {
                    for (var index = 0; index < assets.Length; index++)
                    {
                        if (assets[index].name == subName)
                        {
                            Internal.ApplyAssetCallback(onAssetLoaded, assets[index] as T, true);
                            yield break;
                        }
                    }
                }
            }

            Internal.ApplyAssetCallback(onAssetLoaded, null, false);
        }
    }
}