using System.Collections;
using System.Collections.Generic;
using System.Linq;

using UnityEditor;

using UnityEngine;
using UnityEngine.Networking;

public class LoadAssetBundle : EditorWindow
{
    private static string loadAssetName = "";
    private static string assetURL = "";
    private static List<(string name, string type)> availableAssetNames = new List<(string, string)>();

    private static string LoadProcess = "";

    private static UnityWebRequest request;

    private static bool loadingAsset = false;
    private static bool loadingData = false;

    private static IEnumerator loadingAssetProcess = null;
    private static IEnumerator loadingDataProcess = null;

    [MenuItem("Asset Bundle/Load Asset Bundle", priority = 29)]
    static void Init()
    {
        LoadAssetBundle window = EditorWindow.GetWindow(typeof(LoadAssetBundle)) as LoadAssetBundle;
        window.position = new Rect(Screen.width / 2, Screen.height / 2, 400, 150);
    }

    void OnGUI()
    {
        loadAssetName = EditorGUILayout.TextField("Target Asset(Optional):", loadAssetName);
        string targetAssetURL = EditorGUILayout.TextField("Asset bundle URL*:", assetURL);

        if (targetAssetURL != assetURL)
        {
            assetURL = targetAssetURL;
            availableAssetNames.Clear();
        }

        if (!string.IsNullOrEmpty(LoadProcess))
        {
            EditorGUILayout.LabelField(LoadProcess);
        }

        GUILayout.BeginHorizontal();
        if (loadingAsset || loadingData)
            GUI.enabled = false;
        if (GUILayout.Button("Clear"))
        {
            loadAssetName = "";
            assetURL = "";
            availableAssetNames.Clear();
        }
        if (GUILayout.Button("Get Data"))
        {
            if (!loadingAsset && !loadingData)
                loadingData = true;
        }
        if (GUILayout.Button("Load Asset"))
        {
            if (!loadingAsset && !loadingData)
                loadingAsset = true;
        }
        if (loadingAsset || loadingData)
            GUI.enabled = true;
        else GUI.enabled = false;
        if (GUILayout.Button("Abort"))
        {
            loadingAsset = false;
            loadingData = false;
            LoadProcess = "";
            if (request != null)
            {
                request.Abort();
                request.Dispose();
                request = null;
            }
        }
        GUI.enabled = true;
        GUILayout.EndHorizontal();

        if (availableAssetNames.Count > 0)
        {
            GUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Target Asset:");
            EditorGUILayout.LabelField("Asset Type:");
            GUILayout.EndHorizontal();
            for (int i = 0; i < availableAssetNames.Count; i++)
            {
                GUILayout.BeginHorizontal();
                EditorGUILayout.SelectableLabel(availableAssetNames[i].name);
                EditorGUILayout.SelectableLabel(availableAssetNames[i].type);
                GUILayout.EndHorizontal();
            }
        }
    }

    public void Update()
    {
        if (!loadingAsset)
        {
            if (loadingAssetProcess != null)
                loadingAssetProcess = null;
        }

        if (!loadingData)
        {
            if (loadingDataProcess != null)
                loadingDataProcess = null;
        }

        if (loadingAsset)
        {
            if (loadingAssetProcess == null)
            {
                loadingAssetProcess = LoadAsset(assetURL);
            }
            if (!loadingAssetProcess.MoveNext())
                loadingAsset = false;
        }
        if (loadingData)
        {
            if (loadingDataProcess == null)
            {
                loadingDataProcess = LoadData(assetURL);
            }
            if (!loadingDataProcess.MoveNext())
                loadingData = false;
        }
    }

    private IEnumerator LoadAsset(string url)
    {
        Debug.Log("Loading " + url + " ...");

        while (Caching.ready != true)
            yield return null;

        request = UnityWebRequestAssetBundle.GetAssetBundle(url);
        request.SendWebRequest();
        while (!request.isDone)
        {
            LoadProcess = "Downloading at " + request.downloadProgress * 100 + "%";
            yield return null;
        }
        if (request.error != null)
            Debug.LogError(request.error);

        AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(request);
        string[] assetContentNames = assetBundle.GetAllAssetNames();
        GameObject loadAsset;
        if (string.IsNullOrEmpty(loadAssetName.Trim()))
            loadAsset = (GameObject)assetBundle.LoadAsset(assetContentNames[0]);
        else
            loadAsset = (GameObject)assetBundle.LoadAsset(loadAssetName);

        if (loadAsset != null)
        {
            GameObject go = GameObject.Instantiate(loadAsset);
            ReApplyShaders.Start(go);
        }

        request.Dispose();
        request = null;

        yield return Resources.UnloadUnusedAssets();
        yield return assetBundle.UnloadAsync(false);
        assetBundle = null;
        LoadProcess = "";
    }

    private IEnumerator LoadData(string url)
    {
        Debug.Log("Loading " + url + " ...");
        availableAssetNames.Clear();

        while (Caching.ready != true)
            yield return null;

        request = UnityWebRequestAssetBundle.GetAssetBundle(url);
        request.SendWebRequest();
        while (!request.isDone)
        {
            LoadProcess = "Downloading at " + request.downloadProgress * 100 + "%";
            yield return null;
        }
        if (request.error != null)
            Debug.LogError(request.error);

        AssetBundle assetBundle = DownloadHandlerAssetBundle.GetContent(request);
        Object[] assets = assetBundle.LoadAllAssets();

        foreach (Object asset in assets)
        {
            availableAssetNames.Add((asset.name, asset.GetType().Name));
        }

        request.Dispose();
        request = null;

        yield return Resources.UnloadUnusedAssets();
        yield return assetBundle.UnloadAsync(false);
        assetBundle = null;
        LoadProcess = "";
    }
}