using HybridCLR;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using LitJson;
using TMPro;
using UnityEngine.UI;

public class LoadDll : MonoBehaviour
{
    public GameObject EditorGame;
    static LoadDll instance;
    private void Awake()
    {
        instance = this;
    }
    void Start()
    {
        this.transform.SetParent(OpenXRCamera.Instance.head.transform);
        this.transform.localPosition = Vector3.zero;
        this.transform.localEulerAngles = Vector3.zero;
        //PlayerPrefs.DeleteAll();
#if ISLOCAL
        EditorGame.SetActive(true);
        this.gameObject.SetActive(false);
#else
        StartCoroutine(DownLoadAssets());
#endif

    }


    private static Dictionary<string, byte[]> s_assetDatas = new Dictionary<string, byte[]>();

    public static byte[] ReadBytesFromStreamingAssets(string dllName)
    {
        return s_assetDatas[dllName];
    }

    private string GetWebRequestPath(string asset)
    {
        var path = $"{Application.streamingAssetsPath}/{asset}";
        if (!path.Contains("://"))
        {
            path = "file://" + path;
        }
        return path;
    }
    private static List<string> AOTMetaAssemblyFiles { get; } = new List<string>()
    {
        "mscorlib.dll.bytes",
        "System.dll.bytes",
        "System.Core.dll.bytes",
        "UniTask.dll.bytes",
        "Minio.dll.bytes",
        "System.Runtime.CompilerServices.Unsafe.dll.bytes"
    };

    public Text text;
    public Text text2;

    public Slider slider;


    string HotUpdateScripts = "HotUpdateScripts";
    string HotUpdateAssets = "HotUpdateAssets";
    IEnumerator DownLoadAssets()
    {
        text.text = "正在获取网关数据";

        for (int i = 0; i < AOTMetaAssemblyFiles.Count; i++)
        {
            yield return DownLoadLocal(AOTMetaAssemblyFiles[i]);

        }
        slider.gameObject.SetActive(false);
        while (HttpSDKAction.Instance.jsonData==null || HttpSDKAction.Instance.jsonData=="")
        {
            yield return null;
        }
        JsonData data = new JsonData();
        string scUrl = "";
        string artUrl = "";
        try
        {
            data = JsonMapper.ToObject(HttpSDKAction.Instance.jsonData);

             scUrl = data[HotUpdateScripts].ToString();
             artUrl = data[HotUpdateAssets].ToString();



        }
        catch
        {
            
        }

        if(scUrl != "")
        {
            if (!bool.Parse(data["isHotUpdate"].ToString()))
            {
                text.text = "正在下载代码";
                yield return DownLoadAssets(scUrl, HotUpdateScripts, false);

                text.text = "正在下载配置";
                yield return DownLoadAssets(artUrl, HotUpdateAssets, false);

            }
            else if (PlayerPrefs.GetString("HotUpdateVersion") == data["HotUpdateVersion"].ToString())
            {
                text.text = "正在编译代码";
                string filePath = PlayerPrefs.GetString(HotUpdateScripts);
                Task<byte[]> Tb = File.ReadAllBytesAsync(filePath);
                yield return Tb;
                slider.gameObject.SetActive(false);
                Assembly.Load(Tb.Result);
                text.text = "正在解析配置";

                filePath = PlayerPrefs.GetString(HotUpdateAssets);
                Task<byte[]> Tb2 = File.ReadAllBytesAsync(filePath);
                yield return Tb2;

                text.text = "正在解析配置";
                slider.gameObject.SetActive(false);

                AssetBundleCreateRequest acr = AssetBundle.LoadFromMemoryAsync(Tb2.Result);

                while (!acr.isDone)
                {
                    text2.text = (acr.progress*100).ToString("F2") + "%";
                    slider.value = float.Parse((acr.progress ).ToString("F2"));
                    yield return null;
                }
                slider.gameObject.SetActive(true);

                AssetBundleRequest abr = acr.assetBundle.LoadAssetAsync<GameObject>("LocalAsset");
                text.text = "正在加载配置";
                while (!abr.isDone)
                {
                    text2.text = (abr.progress * 100).ToString("F2") + "%";
                    slider.value = float.Parse((abr.progress ).ToString("F2"));
                    yield return null;
                }
                copyGameObject(abr.asset);

                this.gameObject.SetActive(false);


            }
            else
            {


                text.text = "正在下载代码";
                yield return DownLoadAssets(scUrl, HotUpdateScripts);

                text.text = "正在下载配置";
                yield return DownLoadAssets(artUrl, HotUpdateAssets);
            }
        }
        else
        {
            text.text = "正在下载代码";
            yield return DownLoadAssets(scUrl, HotUpdateScripts, false);

            text.text = "正在下载配置";
            yield return DownLoadAssets(artUrl, HotUpdateAssets, false);

        }
    }

    public IEnumerator DownLoadLocal(string name)
    {
        slider.gameObject.SetActive(true);



        UnityWebRequest www = UnityWebRequest.Get(GetWebRequestPath(name));
        www.SendWebRequest();
        while (!www.isDone)
        {
            text2.text = (www.downloadProgress * 100).ToString("F2") + "%";
            slider.value = float.Parse((www.downloadProgress).ToString("F2"));
            yield return null;
        }

#if UNITY_2020_1_OR_NEWER
        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(www.error);
        }
#else
        if (www.isHttpError || www.isNetworkError)
        {
            Debug.Log(www.error);
        }
#endif

        HomologousImageMode mode = HomologousImageMode.SuperSet;
        LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(www.downloadHandler.data, mode);
        Debug.Log($"LoadMetadataForAOTAssembly:{name}. mode:{mode} ret:{err}");
    }

     public IEnumerator DownLoadAssets(string dllPath,string name,bool isRemote=true)
    {
        slider.gameObject.SetActive(true);

        if(!isRemote)
        {
            dllPath = GetWebRequestPath(name);
        }


        UnityWebRequest www = UnityWebRequest.Get(dllPath);
        www.SendWebRequest();
        while (!www.isDone)
        {
            text2.text = (www.downloadProgress * 100).ToString("F2") + "%";
            slider.value = float.Parse((www.downloadProgress ).ToString("F2"));
            yield return null;
        }

#if UNITY_2020_1_OR_NEWER
        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(www.error);
        }
#else
        if (www.isHttpError || www.isNetworkError)
        {
            Debug.Log(www.error);
        }
#endif
        else
        {

            if(name == HotUpdateScripts)
            {
                text.text = "正在编译代码";
                slider.gameObject.SetActive(false);
                Assembly.Load(www.downloadHandler.data);

                string fileName = HotUpdateScripts;
                if (!Directory.Exists(Application.persistentDataPath + "/HotUpdate"))
                    Directory.CreateDirectory(Application.persistentDataPath + "/HotUpdate" );

                string filePathname = Application.persistentDataPath + "/HotUpdate/" + fileName;
                //  if (File.Exists(filePathname))
                //      File.Delete(filePathname);
                File.WriteAllBytes(filePathname, www.downloadHandler.data);
                PlayerPrefs.SetString(HotUpdateScripts, filePathname);
            }
            else
            {

                text.text = "正在解析配置";
                slider.gameObject.SetActive(false);

                AssetBundleCreateRequest acr = AssetBundle.LoadFromMemoryAsync(www.downloadHandler.data);

                while (!acr.isDone)
                {
                    text2.text = (acr.progress * 100).ToString("F2") + "%";
                    slider.value = float.Parse((acr.progress ).ToString("F2"));
                    yield return null;
                }
                slider.gameObject.SetActive(true);

                AssetBundleRequest abr = acr.assetBundle.LoadAssetAsync<GameObject>("LocalAsset");
                text.text = "正在加载配置";
                while (!abr.isDone)
                {
                    text2.text = (abr.progress * 100).ToString("F2") + "%";
                    slider.value = float.Parse((abr.progress ).ToString("F2"));
                    yield return null;
                }
                copyGameObject(abr.asset);

                this.gameObject.SetActive(false);

                string fileName = HotUpdateAssets;
                if (!Directory.Exists(Application.persistentDataPath + "/HotUpdate"))
                    Directory.CreateDirectory(Application.persistentDataPath + "/HotUpdate");

                string filePathname = Application.persistentDataPath + "/HotUpdate/" + fileName;
                //  if (File.Exists(filePathname))
                //      File.Delete(filePathname);
                File.WriteAllBytes(filePathname, www.downloadHandler.data);
                PlayerPrefs.SetString(HotUpdateAssets, filePathname);
            }

        }

    }


    void copyGameObject(UnityEngine.Object o)
    {
        Instantiate(o);
    }

    private static Assembly _hotUpdateAss;

    /// <summary>
    /// 为aot assembly加载原始metadata, 这个代码放aot或者热更新都行。
    /// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行
    /// </summary>
    private static void LoadMetadataForAOTAssemblies()
    {
        /// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。
        /// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误
        /// 
        HomologousImageMode mode = HomologousImageMode.SuperSet;
        foreach (var aotDllName in AOTMetaAssemblyFiles)
        {
            byte[] dllBytes = ReadBytesFromStreamingAssets(aotDllName);
            // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
            LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, mode);
            Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");
        }
    }


    void StartGame()
    {
        //  LoadMetadataForAOTAssemblies();
        /*
#if !UNITY_EDITOR
        _hotUpdateAss = Assembly.Load(ReadBytesFromStreamingAssets("HotUpdate.dll.bytes"));
#else
        _hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "HotUpdate");
#endif
        */
        // Type entryType = _hotUpdateAss.GetType("Entry");
        //   entryType.GetMethod("Start").Invoke(null, null);

    }


 }