using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Core.AssetLoadTool.Asset;
using Fort23.Core;
using Fort23.UTool;
#if !COMBAT_SERVER

using UnityEngine;
using UnityEngine.Networking;
using Object = UnityEngine.Object;
using Utility;


public class AssetBundleLoadManager : Singleton<AssetBundleLoadManager>
{
    public BundleLoadType BundleLoadType;
    public string h5Url;
    public bool UnloadType = true;
    public bool stopUpdate;

    private string m_rootStreamingURL;

    public string RootStreamingURL
    {
        get { return m_rootStreamingURL; }
    }

    private string m_rootStreamingBundleURL;

    public string RootStreamingBundleURL
    {
        get { return m_rootStreamingBundleURL; }
    }

    private string m_rootPersistentBundleURL;

    public string RootPersistentBundleURL
    {
        get { return m_rootPersistentBundleURL; }
    }

    public string manifestName
    {
        get { return m_manifestName; }
    }

    private string m_manifestName;
    private string m_globalConfigName;
    private string m_buildNoName;
    private string m_assetConfigName;
    public float gcTime;
    public Map<string, AssetInfo> assetToBundleDict = new Map<string, AssetInfo>();
    private AssetBundleManifest assetBundleManifest = null;
    private int index = 0;
    private System.Action loadEndCallBack;


    public Map<AssetInfo, AssetLoadTaskBasic> m_currLoadAsset = new Map<AssetInfo, AssetLoadTaskBasic>();

    public Map<string, BundleLoadBasic> m_currLoadBundle = new Map<string, BundleLoadBasic>();
    public bool isSceneLoad;
    private List<BundleLoadBasic> bundleUnloadBuffer = new List<BundleLoadBasic>();

    public List<BundleLoadBasic> dependenciesBuffer = new List<BundleLoadBasic>();
    public bool isUnload;

    public System.Action<string> onLoadAsset;

    public AssetBundleLoadManager()
    {
        SetFileRoot();
    }

    public async CTask InitAssetsManager(System.Action loadEndCallBack)
    {
        // Ctask
        CTask cTask = CTask.Create(false);
        LogTool.Log("kaishijiazai asset");
        this.loadEndCallBack = delegate
        {
            cTask.SetResult();
            loadEndCallBack?.Invoke();
        };

        index = 0;
        //Load assetconfig file.
        LoadAssetConfig(null);
        //Load manifest file.
        LoadManifest();
        await cTask;
    }


    public void UnloadBundleBuffer()
    {
        LogTool.Log("卸载数据");
        for (int i = 0; i < bundleUnloadBuffer.Count; i++)
        {
            bundleUnloadBuffer[i].UnloadBundle();
        }

        bundleUnloadBuffer.Clear();
    }

    public void CallBackLoadEnd()
    {
        index++;
        if (index >= 2)
        {
            loadEndCallBack();
        }
    }

    private void SetFileRoot()
    {
        m_rootStreamingURL = Application.streamingAssetsPath;
        m_rootStreamingBundleURL = m_rootStreamingURL + "/Bundle/";
        m_rootPersistentBundleURL = Application.persistentDataPath + "/Bundle/";

#if UNITY_EDITOR
        m_assetConfigName = Application.streamingAssetsPath +
                            "/assetConfig.txt";
#elif UNITY_IPHONE
         m_rootStreamingURL = "file://" + m_rootStreamingURL;
        m_rootStreamingBundleURL = "file://" + m_rootStreamingBundleURL;
        m_assetConfigName = m_rootPersistentBundleURL +
                            "assetConfig.txt";
#else
        m_assetConfigName = m_rootPersistentBundleURL +
                            "assetConfig.txt";
#endif

        m_manifestName = "UnityBundle";
        //Temp path. When version update is ready, path will be persistentPath and streamingPath.

//        m_rootpersistentBundleURL = Application.persistentDataPath + "/BundlAsset/";
    }

    public void LoadAssetConfig(System.Action callBack)
    {
        DoLoadingAssetConfig(m_assetConfigName, callBack);
    }


    private void DoLoadingAssetConfig(string url, System.Action callBack)
    {
        assetToBundleDict.Clear();

        if (BundleLoadType != BundleLoadType.H5 && File.Exists(url))
        {
            Debug.Log("URL:" + url);
            string data = File.ReadAllText(url);
            LoadPackedInfo(data, callBack);
        }
        else
        {
            // url = m_rootStreamingURL +
            if (BundleLoadType != BundleLoadType.H5)
            {
                url = m_rootStreamingBundleURL + "assetConfig.txt";
            }
            else
            {
                url = h5Url + "assetConfig.txt";
            }

            Debug.Log("URL22:" + url);
            Uri uri = new Uri(url);
            UnityWebRequest unityWebRequest = UnityWebRequest.Get(uri);
            UnityWebRequestAsyncOperation webRequestAsyncOperation = unityWebRequest.SendWebRequest();
            webRequestAsyncOperation.completed += delegate(AsyncOperation operation)
            {
                if (!string.IsNullOrEmpty(webRequestAsyncOperation.webRequest.downloadHandler.error))
                {
                    LogTool.Error(Application.streamingAssetsPath + "m_assetConfigName buchunzai" + m_assetConfigName);
                    LogTool.Error(webRequestAsyncOperation.webRequest.downloadHandler.error);
                }
                else
                {
                    LoadPackedInfo(webRequestAsyncOperation.webRequest.downloadHandler.text, callBack);
                }
            };
        }

        return;
    }

    private void LoadPackedInfo(string json, System.Action callBack)
    {
        // Debug.Log(json);
        AllPackedAssetsInfo allPackedInfo = JsonManager.FromJson<AllPackedAssetsInfo>(json);
        Debug.Log(allPackedInfo != null);
        Debug.Log(allPackedInfo.assetsList.Count);
        for (int i = 0; i < allPackedInfo.assetsList.Count; i++)
        {
            AssetInfo assetInfo = allPackedInfo.assetsList[i];
            if (assetInfo != null)
            {
                assetToBundleDict.Add(assetInfo.name, assetInfo);
            }
        }

        if (callBack != null)
            callBack();
        CallBackLoadEnd();
    }


    private void LoadManifest()
    {
        DoLoadingManifest();
    }

    private void DoLoadingManifest()
    {
        string url = RootPersistentBundleURL + m_manifestName;
        if (BundleLoadType!=BundleLoadType.H5&&!File.Exists(url))
        {
            url = Application.streamingAssetsPath + "/Bundle/" + m_manifestName;
        }


        if (BundleLoadType == BundleLoadType.LocalAsset)
        {
            CallBackLoadEnd();
            return;
        }

        if (BundleLoadType == BundleLoadType.H5)
        {
            url=h5Url+m_manifestName;
        }

        Debug.Log(url);
        UnityWebRequest webRequest=  UnityWebRequestAssetBundle.GetAssetBundle(url);
        UnityWebRequestAsyncOperation webRequestAsyncOperation= webRequest.SendWebRequest();
        // AssetBundleCreateRequest bundlReq = AssetBundle.LoadFromFileAsync(url);
        webRequestAsyncOperation.completed += delegate(AsyncOperation operation)
        {
            DownloadHandlerAssetBundle downloadHandler= webRequest.downloadHandler as DownloadHandlerAssetBundle;
            assetBundleManifest = downloadHandler.assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            if (assetBundleManifest != null)
            {
                LogTool.Log("AssetBundleManifest jizaiwancheng");
            }

            downloadHandler.assetBundle.Unload(false);
            CallBackLoadEnd();
        };
    }

    public string[] GetBundleDependencies(string bundleName)
    {
        if (assetBundleManifest == null)
        {
            return null;
        }

        return assetBundleManifest.GetDirectDependencies(bundleName);
    }

    public async CTask<AssetHandle> LoadAssetAsyncTask<T>(string assetName,
        System.Action<AssetHandle> callBack = null, Clock clock = null, bool isUseSynchronous = false) where T : Object
    {
        onLoadAsset?.Invoke(assetName);
        //临时使用到007的bundle加载，现在这个bundel卸载有遗漏，后面有时间了在改
        CTask task = CTask.Create(false);
        AssetHandle obj = null;
        LoadAssetAsync<T>(assetName, delegate(AssetHandle o, object o1)
        {
            if (o != null)
            {
                obj = o;
            }

            task.SetResult();
        }, clock, isUseSynchronous);

        await task;
        // TODO 暂时去掉，不知道会不会有影响
        // await TimerComponent.Instance.WaitFrameAsync();
        callBack?.Invoke(obj);
        return obj;
    }

    private void LoadAssetAsync<T>(string assetName, System.Action<AssetHandle, object> callBack, Clock clock = null,
        object userData = null, bool isUseSynchronous = false) where T : Object
    {
        if (!assetToBundleDict.TryGetValue(assetName, out AssetInfo assetInfo))
        {
            callBack?.Invoke(null, userData);
            Debug.LogWarning("没找到资源" + assetName);
            return;
        }

        LoadAssetCallBackData loadAssetCallBackData = new LoadAssetCallBackData();
        loadAssetCallBackData.loadEndCallBack = callBack;
        loadAssetCallBackData.userData = userData;
        loadAssetCallBackData.Clock = clock;
        loadAssetCallBackData.isUseSynchronous = isUseSynchronous;
        AssetLoadTaskBasic assetLoad = null;
        if (!m_currLoadAsset.TryGetValue(assetInfo, out assetLoad))
        {
            assetLoad = CreateAssetTaskBasic();
            assetLoad.InitAsset<T>(assetInfo, UnloadType, loadAssetCallBackData);
            m_currLoadAsset.Add(assetInfo, assetLoad);
        }
        else
        {
            assetLoad.AddCallBack<T>(loadAssetCallBackData);
        }
    }

    protected AssetLoadTaskBasic CreateAssetTaskBasic()
    {
        switch (BundleLoadType)
        {
            case BundleLoadType.LocalAsset:
                return new LocalAssetLoadTask();
                break;
            case BundleLoadType.LocalBundle:
                return new BundleAssetLoadTask();
                break;
            case BundleLoadType.H5:
                return new BundleAssetLoadTask();
                break;
        }

        LogTool.Error("加载模式不存在" + BundleLoadType);
        return null;
    }

    protected BundleLoadBasic CreateBundleTaskBasic()
    {
        switch (BundleLoadType)
        {
            case BundleLoadType.LocalAsset:
                break;
            case BundleLoadType.LocalBundle:
                return new LocalBundleLoadTask();
                break;
            case BundleLoadType.H5:
                return new H5BundleLoadTask();
                break;
        }

        LogTool.Error("加载模式不存在" + BundleLoadType);
        return null;
    }

    public BundleLoadBasic AddBundleTask(string bundleName, System.Action<BundleLoadBasic, object> callBack,
        LoadTaskBasic loadTaskBasic)
    {
        BundleLoadBasic bundleLoadTask = null;
        if (m_currLoadBundle.ContainsKey(bundleName))
        {
            bundleLoadTask = m_currLoadBundle[bundleName];
        }

        if (bundleLoadTask == null)
        {
            bundleLoadTask = CreateBundleTaskBasic();
            //AssetInfo bundleInfo = assetToBundleDict[assetName];
            m_currLoadBundle.Add(bundleName, bundleLoadTask);
            bundleLoadTask.InitBundle(bundleName, UnloadType, callBack);
            bundleLoadTask.AddOwnTask(loadTaskBasic);
        }
        else
        {
            bundleLoadTask.AddOwnTask(loadTaskBasic);
            bundleLoadTask.AddCallBack(callBack);
        }

        return bundleLoadTask;
    }


    public string GetBudnleInfo()
    {
        return $"当前拥有资源数：{m_currLoadAsset.Count}    bundle数：{m_currLoadBundle.Count}";
    }

    public void UpdateBundle()
    {
        if (stopUpdate)
            return;
        BundleLoadBasic[] depend = dependenciesBuffer.ToArray();
        for (int i = 0; i < depend.Length; i++)
        {
            if (depend[i].AwaitDependenceLoadEnd())
            {
                dependenciesBuffer.Remove(depend[i]);
            }
        }

        bool isShowDebug = Input.GetKeyUp(KeyCode.K);

        int count = 0;
        for (m_currLoadAsset.Begin(); m_currLoadAsset.Next();)
        {
            if (isShowDebug)
            {
                Debug.Log(m_currLoadAsset.Key.name + "____" + m_currLoadAsset.Value.HandCount);
            }

            count += m_currLoadAsset.Value.HandCount;
            m_currLoadAsset.Value.Update();
        }

        if (isShowDebug)
        {
            Debug.Log($"当前拥有资源数：{count}    bundle数：{m_currLoadBundle.Count}");
        }
    }


    public void RemoveAssetTask(AssetInfo assetInfo)
    {
        if (m_currLoadAsset.ContainsKey(assetInfo))
        {
            m_currLoadAsset.Remove(assetInfo);
        }
    }

    public void RemoveBundleTask(BundleLoadBasic budnleLoadTask)
    {
        if (m_currLoadBundle.ContainsKey(budnleLoadTask.bundleName))
        {
            m_currLoadBundle.Remove(budnleLoadTask.bundleName);
        }
    }

    public void ClearUnusedBundles()
    {
    }

    public bool IsAssetInfo(string assetName)
    {
        return false;
    }
}
#endif