using XGame.Framework.Utils;
using XGame.Framework.Asset.Addressable;
using System;
using UnityEngine;

namespace XGame.Framework.Asset
{
    internal partial class LoaderBuilder
    {
        private LoaderType _loadType;
        private AssetBundle _mainbundle;
        private bool _isBundleEncrypt;
        public LoaderBuilder()
        {

#if UNITY_EDITOR
            var isSimluator = UnityEditor.EditorPrefs.GetBool(Define.SIMULATE_ASSETBUNDLE_EDITOR_KEY, true);
            _loadType = isSimluator ? LoaderType.AssetDatabase : LoaderType.AssetBundle;
#else
            _loadType = LoaderType.AssetBundle;
#endif
            InitMainbundle();
        }

        private void InitMainbundle()
        {
            if (_loadType == LoaderType.AssetBundle)
            {
#if UNITY_EDITOR
                InitMainBundleEditor();
#else
                _isBundleEncrypt = true;
                var bundlePath = FileUtils.GetAssetBundlePath(Define.MANIFEST_BUNDLE_FULLNAME);
                _mainbundle = AssetBundle.LoadFromFile(bundlePath, 0, Define.MANIFEST_BUNDLE_OFFSET);//"kcmanifest.bundle"
#endif
            }
        }
        private IAddressableManifest LoadAddressableManifest()
        {
            if (_loadType == LoaderType.AssetDatabase)
            {
#if UNITY_EDITOR
                return LoadAddressableManifestEditor();
#endif
            }
            else if (_loadType == LoaderType.AssetBundle)
            {
                var manifest = new CSharpAddressableManifest();
                if (_mainbundle != null)
                {
                    var builtInAssetSo = _mainbundle.LoadAsset<AddressableInfosSo>(Define.BUILTIN_ASSET_MANIFEST);
                    manifest.Init(builtInAssetSo);
                    var productAssetSo = _mainbundle.LoadAsset<AddressableInfosSo>(Define.PRODUCT_ASSET_MANIFEST);
                    manifest.Init(productAssetSo);
                }
                return manifest;
            }
            return null;
        }

        private IAssetLoader CreateLoader(LoaderType loaderType, IAddressableManifest addressableManifest)
        {
            IAssetLoader loader = null;

            switch (loaderType)
            {
                case LoaderType.AssetDatabase:
#if UNITY_EDITOR
                    loader = new AssetDatabaseLoader(addressableManifest as IAddressableEditorHandler);
#endif
                    break;
                case LoaderType.AssetBundle:
                    {
                        var bundlesSo = _mainbundle?.LoadAsset<AssetBundleInfosSo>(Define.ASSET_BUNDLE_MANIFEST) ?? null;//"KCAssetBundleManifest"
                        var bundleManifest = new CSharpAssetBundleManifest(bundlesSo);
                        var referencesSo = _mainbundle?.LoadAsset<AssetReferenceInfosSo>(Define.ASSET_REFERENCE_MANIFEST) ?? null;
                        var referenceManifest = new CSharpAssetReferencesManifest(referencesSo);
                        var sceneInfosSo = _mainbundle?.LoadAsset<SceneInfosSo>(Define.SCENE_BUNDLE_MANIFEST) ?? null;
                        var sceneInfosManifest = new CSharpSceneInfosManifest(sceneInfosSo);
                        loader = new AssetBundleLoader(bundleManifest, referenceManifest, sceneInfosManifest)
                        {
                            IsBundleEncrypt = _isBundleEncrypt
                        };
                    }
                    break;
                case LoaderType.Resources:
                    loader = new ResourcesLoader(addressableManifest);
                    break;
                case LoaderType.Binary:
                    loader = new BinaryLoader();
                    break;
            }

            return loader;
        }
        private void Release()
        {
            _mainbundle?.Unload(true);
            _mainbundle = null;
        }
        public IAssetLoader Build()
        {
            var addressableManifest = LoadAddressableManifest();

            var array = Enum.GetValues(typeof(LoaderType));
            var loaders = new IAssetLoader[array.Length];
            foreach (LoaderType enumVal in array)
            {
                if ((enumVal == LoaderType.AssetBundle && _loadType == LoaderType.AssetDatabase) ||
                    (enumVal == LoaderType.AssetDatabase && _loadType == LoaderType.AssetBundle))
                {//创建Loader时AssetDatabase和AssetBundle二选一
                    continue;
                }
                loaders[(int)enumVal] = CreateLoader(enumVal, addressableManifest);
            }
            var adapter = new AssetLoader(_loadType, loaders, addressableManifest);
            Release();
            return adapter;
        }
    }
}
