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

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

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

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

        /// <summary>
        /// Load asset from bundle synchronously with relative path
        /// 使用相对路径从Bundle中加载资源
        /// </summary>
        /// <param name="assetPath">"Resources+ProjectBasePath"的相对路径</param>
        /// <param name="bundle"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public override T LoadAssetSync<T>(string assetPath, AssetBundle bundle)
        {
            if (string.IsNullOrEmpty(assetPath))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            assetPath = PathUtil.ClearExtension(assetPath);
            var fullPath = m_BaseInfo.GetAssetRelativeFullPath(assetPath);
//            Debug.Log($"Resource.LoadAssetSync:{fullPath}");
            return Resources.Load<T>(fullPath);
        }

        /// <summary>
        /// Load asset from bundle synchronously with full path
        /// 使用完整路径从Bundle中加载资源
        /// The full path：refers to the relative path after removing ProjectBasePath
        /// 完整路径：指的是去除ProjectBasePath后的相对路径
        /// </summary>
        /// <param name="fullPath">Resources的相对路径</param>
        /// <param name="bundle"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public override T LoadAssetSyncFull<T>(string fullPath, AssetBundle bundle)
        {
            if (string.IsNullOrEmpty(fullPath))
            {
                throw LoaderErrors.ErrorPathEmpty;
            }

            fullPath = PathUtil.ClearExtension(fullPath);
            return LoadAssetSync<T>(fullPath, bundle);
        }

        //--同步子资源(全部)

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

            path = PathUtil.ClearExtension(path);
            return Resources.LoadAll(path);
        }

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

            path = PathUtil.ClearExtension(path);
            return Resources.LoadAll(path, type);
        }

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

            path = PathUtil.ClearExtension(path);
            return Resources.LoadAll<T>(path);
        }

        //--同步子资源(名称)

        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 (null == subNames)
            {
                throw LoaderErrors.ErrorSubPathEmpty;
            }

            var all = LoadSubAssetsSync(path, bundle);
            return Internal.FindAssets(all, subNames);
        }

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

            var all = LoadSubAssetsSync(path, ab);
            return Internal.FindAssets(all, subNames, type);
        }

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

            var all = LoadSubAssetsSync<T>(path, bundle);
            return Internal.FindAssets(all, subNames);
        }

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

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

            var req = Resources.LoadAsync<T>(assetPath);
            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 assets = new T[assetPaths.Length];
            for (var i = 0; i < assets.Length; i++)
            {
                var req = Resources.LoadAsync<T>(assetPaths[i]);
                yield return req;
                if (req.isDone && req.asset != null)
                {
                    assets[i] = req.asset as T;
                }
            }

            Internal.ApplyMultiAssetCallback(onMultiAssetLoaded, assets, true);
        }

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

            var assets = Resources.LoadAll<T>(assetPath);
            if (assets != null)
            {
                var 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);
            }

            yield break;
        }

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

            var assets = Resources.LoadAll<T>(assetPath);
            if (assets != null)
            {
                for (var index = 0; index < assets.Length; index++)
                {
                    if (assets[index].name == subName)
                    {
                        Internal.ApplyAssetCallback(onAssetLoaded, assets[index], true);
                        yield break;
                    }
                }
            }

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