using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class AssetBundlesManager : MonoBehaviour
{
    private class AssetBundleInfo
    {
        public AssetBundle assetBundle;
        public float lastAccessTime;
        public int referenceCount;
    }
    [SerializeField]
    private Dictionary<string, AssetBundleInfo> loadedAssetBundles = new Dictionary<string, AssetBundleInfo>();
    public float autoUnloadTime = 30f;

    public static AssetBundlesManager Instance { get; private set; }

    private void OnEnable()
    {
        Instance = this;
    }

    public bool InitManifest(string manifestPath)
    {
        AssetBundle manifestBundle = AssetBundle.LoadFromFile(manifestPath);
        if (manifestBundle == null)
        {
            Debug.LogError("Failed to load AssetBundle Manifest: " + manifestPath);
            return false;
        }

        AssetBundleManifest manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        if (manifest == null)
        {
            Debug.LogError("Failed to load AssetBundle Manifest: " + manifestPath);
            return false;
        }

        string[] assetBundlePaths = manifest.GetAllAssetBundles();
        foreach (var path in assetBundlePaths)
        {
            Debug.Log("AssetBundle loaded: " + path);
        }

        manifestBundle.Unload(false);
        return true;
    }

    private void Update()
    {
        // Զճ30δֶͷŵAssetBundle
        List<string> keysToUnload = new List<string>();
        foreach (var kvp in loadedAssetBundles)
        {
            if (Time.realtimeSinceStartup - kvp.Value.lastAccessTime > autoUnloadTime)
            {
                if (kvp.Value.referenceCount <= 0)
                {
                    keysToUnload.Add(kvp.Key);
                }
            }
        }

        foreach (var key in keysToUnload)
        {
            UnloadAssetBundle(key);
        }
    }

    public T LoadAssetBundle<T>(string assetBundlePath) where T : Object
    {
        AssetBundleInfo assetBundleInfo;
        if (loadedAssetBundles.TryGetValue(assetBundlePath, out assetBundleInfo))
        {
            assetBundleInfo.lastAccessTime = Time.realtimeSinceStartup;
            assetBundleInfo.referenceCount++;
            //return assetBundleInfo.assetBundle.LoadAsset<T>;
            T[] assets_aches = assetBundleInfo.assetBundle.LoadAllAssets<T>();
            return assets_aches[0];
        }

        AssetBundle assetBundle = AssetBundle.LoadFromFile(assetBundlePath);
        if (assetBundle == null)
        {
            Debug.LogError("Failed to load AssetBundle: " + assetBundlePath);
            return null;
        }



        assetBundleInfo = new AssetBundleInfo
        {
            assetBundle = assetBundle,
            lastAccessTime = Time.realtimeSinceStartup,
            referenceCount = 1
        };
        loadedAssetBundles.Add(assetBundlePath, assetBundleInfo);
        T[] assets = assetBundle.LoadAllAssets<T>();
        return assets[0];
    }

    public void LoadAssetBundleAsync<T>(string assetBundlePath, System.Action<T> callback, System.Action<float> onProgress = null) where T : Object
    {
        StartCoroutine(LoadAssetBundleCoroutine(assetBundlePath, callback, onProgress));
    }

    private IEnumerator LoadAssetBundleCoroutine<T>(string assetBundlePath, System.Action<T> callback, System.Action<float> onProgress) where T : Object
    {
        assetBundlePath = assetBundlePath.Replace("\\", "/");
        string[] laodedAssetBundlePaths = new string[loadedAssetBundles.Count];
        loadedAssetBundles.Keys.CopyTo(laodedAssetBundlePaths, 0);
        foreach (var path in laodedAssetBundlePaths)
        {
            Debug.Log($"Loaded AssetBundle:{path}");
        }
        AssetBundleInfo assetBundleInfo;
        if (loadedAssetBundles.TryGetValue(assetBundlePath, out assetBundleInfo))
        {
            Debug.Log("AssetBundle loaded: " + assetBundlePath);
            assetBundleInfo.lastAccessTime = Time.realtimeSinceStartup;
            assetBundleInfo.referenceCount++;
            T[] assets_aches = assetBundleInfo.assetBundle.LoadAllAssets<T>();
            callback(assets_aches[0]);
            onProgress?.Invoke(1);
            yield break;
        }
        UnityWebRequest unityWebRequest = null;
        if (assetBundlePath.StartsWith("http://") || assetBundlePath.StartsWith("https://"))
        {
            unityWebRequest = UnityWebRequestAssetBundle.GetAssetBundle(assetBundlePath);
        }
        else
        {
            unityWebRequest = UnityWebRequestAssetBundle.GetAssetBundle("file://" + assetBundlePath);
        }

        if (unityWebRequest != null)
        {
            var operation = unityWebRequest.SendWebRequest();

            while (!operation.isDone)
            {
                onProgress?.Invoke(operation.progress);
                yield return null;
            }
            if (unityWebRequest.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError("Failed to load AssetBundle: " + assetBundlePath);
                yield break;
            }

            AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(unityWebRequest);
            if (assetBundle != null)
            {
                assetBundleInfo = new AssetBundleInfo
                {
                    assetBundle = assetBundle,
                    lastAccessTime = Time.realtimeSinceStartup,
                    referenceCount = 1,
                };
                loadedAssetBundles.Add(assetBundlePath, assetBundleInfo);
                Debug.Log("AssetBundle loaded: " + assetBundlePath);
                T[] assets = assetBundle.LoadAllAssets<T>();
                callback(assets[0]);
            }
            else
            {
                if (loadedAssetBundles.TryGetValue(assetBundlePath, out assetBundleInfo))
                {
                    Debug.Log("AssetBundle loaded: " + assetBundlePath);
                    assetBundleInfo.lastAccessTime = Time.realtimeSinceStartup;
                    assetBundleInfo.referenceCount++;
                    T[] assets_aches = assetBundleInfo.assetBundle.LoadAllAssets<T>();
                    callback(assets_aches[0]);
                }
                else
                {
                    Debug.LogError("Failed to load AssetBundle: " + assetBundlePath);
                }
            }
            onProgress?.Invoke(1);
        }
    }

    public void UnloadAssetBundle(string assetBundlePath)
    {
        assetBundlePath = assetBundlePath.Replace("\\", "/");
        AssetBundleInfo assetBundleInfo;
        if (loadedAssetBundles.TryGetValue(assetBundlePath, out assetBundleInfo))
        {
            assetBundleInfo.referenceCount--;
            if (assetBundleInfo.referenceCount <= 0)
            {
                assetBundleInfo.assetBundle.Unload(true);
                loadedAssetBundles.Remove(assetBundlePath);
                Debug.Log("AssetBundle unloaded: " + assetBundlePath);
            }
        }
        else
        {
            Debug.LogError("AssetBundle not found: " + assetBundlePath);
        }
    }

    private void OnDisable()
    {
        foreach (var kvp in loadedAssetBundles)
        {
            kvp.Value.assetBundle.Unload(true);
        }
        loadedAssetBundles.Clear();
    }
}
