using SC.XR.Unity.Module_InputSystem;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using TriLibCore;
using TriLibCore.Extensions;
using TriLibCore.Mappers;
using TriLibCore.Samples;
using TriLibCore.Utils;
using UnityEngine;
using UnityEngine.Rendering;

public class TemplateModel : BaseTemPlate
{
    private GameObject m_ModelObj = null;
    protected override void OnEnable()
    {
        base.OnEnable();
        if (GameManager.Instance.IsRuning && m_ModelObj == null)
        {
            Debug.Log("ExtractZipFile===>1");
            if (IsAB())
                LoadABModel();
            else
                TriLibModel();
        }
        else
        {
            if (m_ModelObj && m_ModelObj.GetComponent<Animation>())
            {
                Debug.Log("Animation===>1" + m_ModelObj.name);

                Animation _animation = m_ModelObj.GetComponent<Animation>();
                List<AnimationClip> _animations = _animation.GetAllAnimationClips();
                m_ModelObj.GetComponent<Animation>().Play(_animations[0].name, PlayMode.StopAll);
            }
        }
        if (this.gameObject.GetComponent<AudioSource>())
            this.gameObject.GetComponent<AudioSource>().Play();
    }

    private IEnumerator LoadModel()
    {
        yield return new WaitForSeconds(0.01f);
        if (GameManager.Instance.IsRuning && m_ModelObj == null)
        {
            //Debug.Log(Data.name);
            Debug.Log("DGJ ==>>   " + Data.localLoadPath);
            var ab = AssetBundle.LoadFromFileAsync(Data.localLoadPath);
            yield return ab;
            if (ab == null)
            {
                Debug.Log("Failed to load AssetBundle!");

            }
            else
            {
                var allab = ab.assetBundle.LoadAllAssetsAsync<GameObject>();
                yield return allab;
                var prefab = ab.assetBundle.LoadAssetAsync<GameObject>((allab.allAssets[0] as GameObject).name);

                yield return prefab;
                switch (prefab.asset.name)
                {
                    case "GHZ_OOBE_230721":

                        var objload = Resources.LoadAsync<GameObject>("GongYe");
                        yield return objload;
                        GameObject obj = null;
                        if (objload.asset is GameObject)
                        {
                            obj = objload.asset as GameObject;

                        }
                        if (obj == null)
                        {
                            Debug.LogError(" GHZ_OOBE_230721  物体加载失败,请查看是否导入相关Packages ");
                            obj = new GameObject();

                        }
                        m_ModelObj = GameObject.Instantiate(obj, transform);
                        m_ModelObj.name = "GongYe";

                        if (GameObject.Find("AudioManager") == null)
                        {
                            GameObject audio = Resources.Load<GameObject>("AudioManager");
                            if (audio == null)
                            {
                                Debug.LogError("  GHZ_OOBE_230721 Packages内AudioManager组件丢失");
                                audio = new GameObject();
                            }
                            GameObject Audio = GameObject.Instantiate(audio, transform);
                            Audio.name = "AudioManager";
                        }
                        break;

                    case "GHZ_XXXXXX_230721":

                        break;

                    default:
                        m_ModelObj = Instantiate(prefab.asset as GameObject, transform);
                        break;
                }



                //if (ab.LoadAllAssets<GameObject>()[0].name == "MRVideo")
                //m_ModelObj.AddComponent<MovieScreen>();

                gameObject.AddComponent<ManipulationHandler>();
                gameObject.AddComponent<BoundingBox>();
                gameObject.AddComponent<Patch_ModelController>();
                yield return new WaitForSeconds(0.3f);
                ab.assetBundle.Unload(false);
                HideCollider();
            }




            //var obj = DownloadManager.Instance.GetAbObj(Util.MD5Encrypt(Data.downloadPath));
            //if (obj != null)
            //{
            //    m_ModelObj = Instantiate(obj, transform);
            //    m_ModelObj.transform.localPosition = Vector3.zero;
            //    m_ModelObj.gameObject.SetActive(true);
            //}
        }
    }
    public void LoadModel(AssetBundle ab)
    {
        GameManager.Instance.StartCoroutine(LoadABModel(ab));
        //LoadABModel(ab);
    }
    private IEnumerator LoadABModel(AssetBundle ab)
    {
        if (ab == null)
        {
            Debug.Log("Failed to load AssetBundle!");

        }
        else
        {
            var allab = ab.LoadAllAssetsAsync<GameObject>();
            yield return allab;
            var prefab = ab.LoadAssetAsync<GameObject>((allab.allAssets[0] as GameObject).name);

            switch (prefab.asset.name)
            {
                case "GHZ_OOBE_230721":

                    var objload = Resources.LoadAsync<GameObject>("GongYe");
                    yield return objload;
                    GameObject obj = null;
                    if (objload.asset is GameObject)
                    {
                        obj = objload.asset as GameObject;

                    }
                    m_ModelObj = GameObject.Instantiate(obj, transform);
                    m_ModelObj.name = "GongYe";

                    if (GameObject.Find("AudioManager") == null)
                    {
                        GameObject audio = Resources.Load<GameObject>("AudioManager");
                        if (audio == null)
                        {
                            Debug.LogError("  GHZ_OOBE_230721 Packages内AudioManager组件丢失");
                            audio = new GameObject();
                        }
                        GameObject Audio = GameObject.Instantiate(audio, null);
                        Audio.name = "AudioManager";
                    }
                    break;

                case "GHZ_XXXXXX_230721":

                    break;

                default:
                    m_ModelObj = Instantiate(prefab.asset as GameObject, transform);
                    break;
            }



            //if (ab.LoadAllAssets<GameObject>()[0].name == "MRVideo")
            //m_ModelObj.AddComponent<MovieScreen>();

            gameObject.AddComponent<ManipulationHandler>();
            gameObject.AddComponent<BoundingBox>();
            // yield return new WaitForSeconds(0.3f);
            ab.Unload(false);
            HideCollider();
            ModelItem.isLoad = false;
        }
    }

    protected override void OnAwake()
    {
        base.OnAwake();
    }

    public override void SetData(MaterialObjValue value, long updateTime)
    {

        base.SetData(value, updateTime);
        //if (gameObject.GetComponent<Collider>() != null)
        //{
        //    Destroy(gameObject.GetComponent<Collider>());
        //}
        //下载列表中加入数据
        if (!GameManager.Instance.IsRuning || Data == null)
        {
            //   DownloadManager.Instance.AddDownloadData(Data);


            DownLoadMaterial data = new DownLoadMaterial();
            this.Data = data;
            data.name = value.name;
            data.downLoadPath = value.DownloadPath;
            data.localLoadPath = Application.persistentDataPath + "/Material/" + Path.GetFileName(value.DownloadPath);
            data.updataTime = updateTime;//GameManager.Instance.m_SceneValue.updateTime;
            data.type = "3";
            MsgHandler.AddListener(value.DownloadPath, HandleMsg);
            DownloadResManager.Instance.DownLoad(data);
            Debug.Log(" SetData " + updateTime);
        }
        else
        {

            if (IsAB())
                LoadABModel();
            else
                TriLibModel();
            //AssetBundle ab = AssetBundle.LoadFromFile(Data.localLoadPath);
            //if (ab == null)
            //{
            //    Debug.Log("Failed to load AssetBundle!");
            //    return;
            //}
            //var prefab = ab.LoadAsset<GameObject>(ab.LoadAllAssets<GameObject>()[0].name);
            //m_ModelObj = Instantiate(prefab, transform);
            //ab.Unload(false);

            //gameObject.AddComponent<ManipulationHandler>();
            //gameObject.AddComponent<BoundingBox>();
            //var obj = DownloadManager.Instance.GetAbObj(Util.MD5Encrypt(Data.downloadPath));
            //if (obj != null)
            //{
            //    m_ModelObj = Instantiate(obj, transform);
            //    m_ModelObj.transform.localPosition = Vector3.zero;
            //    m_ModelObj.gameObject.SetActive(true);
            //}

        }

    }

    private void HandleMsg(Msg msg)
    {
        Debug.Log("DGJ   TemplateModel ");

        if (msg.Value != null)
        {
            if (IsAB())
                LoadABModel();
            else
                TriLibModel();
        }
        else
        {
            InstantiateCommand Command = new InstantiateCommand(
               InstantiateSystem.Instance.BlueObject.WarningPopUp,
               InstantiateSystem.Instance.BlueObject.NetErrorText);
            CommandSystem.Instance.Send(Command);
            Debug.LogError("  模型下载失败 ");
        }


    }

    private bool IsAB()
    {
        bool finish = false;

        string fileName = Path.GetFileName(Data.localLoadPath);
        Debug.Log("HJJ   fileName===>" + fileName);
        if (fileName.Contains(".ghb") || !fileName.Contains("."))
        {
            finish = true;
        }

        return finish;
    }

    private void LoadABModel()
    {

        GameManager.Instance.StartCoroutine(LoadABModelNew());
        /**/
    }
  public  static Dictionary<string, GameObject> loadPathstatic = new Dictionary<string, GameObject>();
    public static Dictionary<string, bool> loadPathstaticbool = new Dictionary<string, bool>();
    public static Dictionary<string, string> loadPathstaticstr = new Dictionary<string, string>();
    private IEnumerator LoadABModelNew()
    {
        /*
        AssetBundleCreateRequest ab = AssetBundle.LoadFromFileAsync(Data.localLoadPath);
        yield return ab;
        if (ab.assetBundle == null)
        {
            Debug.Log("Failed to load AssetBundle!");
            yield return null;
        }
        else
        {
            AssetBundleRequest golist = ab.assetBundle.LoadAllAssetsAsync<GameObject>();
            yield return golist;

            AssetBundleRequest assetrequest = ab.assetBundle.LoadAssetAsync<GameObject>(golist.allAssets[0].name);
            yield return assetrequest;
            GameObject prefab = (GameObject)assetrequest.asset;
            m_ModelObj = Instantiate(prefab, transform);
            ab.assetBundle.Unload(false);

            ManipulationHandler manipulation = gameObject.AddComponent<ManipulationHandler>();
            manipulation.enabled = false;
            BoundingBox boundingBox = gameObject.AddComponent<BoundingBox>();
            boundingBox.enabled = false;

        }*/

        Debug.Log("ghb加载===》" + Data.localLoadPath);


        if (loadPathstaticbool.ContainsKey(Data.localLoadPath))
        {
            bool isload = false;
            while (!isload)
            {
                var allab = AssetBundle.GetAllLoadedAssetBundles();
                yield return allab;
                foreach (var a in allab)
                {
                    if (loadPathstatic.ContainsKey(a.name))
                    {
                        GameObject prefab = (GameObject)loadPathstatic[a.name];
                        m_ModelObj = Instantiate(prefab, transform);
                        m_ModelObj.SetActive(true);
                        //Destroy(prefab);
                        ManipulationHandler manipulation = gameObject.AddComponent<ManipulationHandler>();
                        manipulation.enabled = false;
                        BoundingBox boundingBox = gameObject.AddComponent<BoundingBox>();
                        boundingBox.enabled = false;
                        isload = true;
                    }
                }

                yield return null;
            }
            yield return null;
        }
        else
        {
            loadPathstaticbool.Add(Data.localLoadPath,true);
            AssetBundleCreateRequest ab=null;
                ab = AssetBundle.LoadFromFileAsync(Data.localLoadPath);
                yield return ab;
                if (ab.assetBundle == null)
                {
                    bool isload = false;
                    while (!isload)
                    {
                        var allab = AssetBundle.GetAllLoadedAssetBundles();
                        yield return allab;
                        foreach (var a in allab)
                        {
                            if (loadPathstatic.ContainsKey(a.name))
                            {
                                GameObject prefab = (GameObject)loadPathstatic[a.name];
                                m_ModelObj = Instantiate(prefab, transform);
                                m_ModelObj.SetActive(true);
                                //Destroy(prefab);
                                ManipulationHandler manipulation = gameObject.AddComponent<ManipulationHandler>();
                                manipulation.enabled = false;
                                BoundingBox boundingBox = gameObject.AddComponent<BoundingBox>();
                                boundingBox.enabled = false;
                                isload = true;
                            }
                        }

                        yield return null;
                    }
                    yield return null;
                }
                else
            {
                loadPathstaticstr.Add(Data.localLoadPath, ab.assetBundle.name);
                AssetBundleRequest golist = ab.assetBundle.LoadAllAssetsAsync<GameObject>();
                    yield return golist;
                    Debug.Log("ghb加载==1=》" + golist.allAssets[0].name);
                    AssetBundleRequest assetrequest = ab.assetBundle.LoadAssetAsync<GameObject>(golist.allAssets[0].name);
                    yield return assetrequest;
                    Debug.Log("ghb加载===2》" + (assetrequest.asset.name));
                    loadPathstatic.Add(ab.assetBundle.name, (GameObject)assetrequest.asset);
                    GameObject prefab = (GameObject)assetrequest.asset;
                    m_ModelObj = Instantiate(prefab, transform);
                    GameObject prefabasset = (GameObject)assetrequest.asset;
                    prefabasset.SetActive(false);
                    loadPathstatic.Add(ab.assetBundle.name, prefabasset);
                  //  ab.assetBundle.Unload(true);

                    ManipulationHandler manipulation = gameObject.AddComponent<ManipulationHandler>();
                    manipulation.enabled = false;
                    BoundingBox boundingBox = gameObject.AddComponent<BoundingBox>();
                    boundingBox.enabled = false;

                }
        }
    }
    /// <summary>
    /// 解压
    /// </summary>
    /// <param name="zipFilePath">压缩文件路径</param>
    /// <param name="extractPath">解压路径</param>
    public bool ExtractZipFile(string zipFilePath)
    {
        if(!zipFilePath.Contains(".zip"))
        {
            return false;
        }
        Debug.Log("ExtractZipFile===>1");
        using (ZipArchive archive = ZipFile.OpenRead(zipFilePath))
        {
            foreach (ZipArchiveEntry entry in archive.Entries)
            {
                Debug.Log("ExtractZipFile==FullName=>2" + entry.FullName);
                if (entry.FullName.Contains("GHZPointCloud"))
                {


                    return true;

                }
            }


        }
        return false;
    }

    public static float[] bytesToFloat(byte[] byteArray)//byte[]数组转化为AudioClip可读取的float[]类型
    {
        float[] sounddata = new float[byteArray.Length / 2];
        for (int i = 0; i < sounddata.Length; i++)
        {
            sounddata[i] = bytesToFloat(byteArray[i * 2], byteArray[i * 2 + 1]);
        }
        return sounddata;
    }

    static float bytesToFloat(byte firstByte, byte secondByte)
    {
        // convert two bytes to one short (little endian)
        //小端和大端顺序要调整
        short s;
        if (BitConverter.IsLittleEndian)
            s = (short)((secondByte << 8) | firstByte);
        else
            s = (short)((firstByte << 8) | secondByte);
        // convert to range from -1 to (just below) 1
        return s / 32768.0F;
    }
    public byte[] readbytes(Stream stream)
    {

        using (Stream fs = stream)
        {
            byte[] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, bytes.Length);
            fs.Close();
            return bytes;
        }
    }
    public void TriLibModel()
    {
        if(m_ModelObj)
        {
            return;
        }

        Debug.Log("模型加载完成TriLibModel" + Data.downLoadPath);

        if (false)//
        {

        }
        else
        {
            AssetLoaderOptions AssetLoaderOptions = AssetLoader.CreateDefaultLoaderOptions();
            if (ExtractZipFile(Data.localLoadPath)) 
            {
                AssetLoaderOptions.LoadPointClouds = true;
            }
            else
            {
                AssetLoaderOptions.LoadPointClouds = false;
            }

                AssetLoaderOptions.TextureMappers = new TextureMapper[] { ScriptableObject.CreateInstance<FilePickerTextureMapper>() };
           
            if (!(AssetLoaderOptions.ExternalDataMapper is FilePickerExternalDataMapper))
            {
                AssetLoaderOptions.ExternalDataMapper = ScriptableObject.CreateInstance<FilePickerExternalDataMapper>();
            }
            if (AssetLoaderOptions.LoadPointClouds)
            {
                Debug.Log("模型加载完成TriLibModel" + AssetLoaderOptions.LoadPointClouds);
            AssetLoader.LoadModelFromFile(Data.localLoadPath, (AssetLoaderContext ac) => {

                    Debug.Log("模型加载完成");
            }, (AssetLoaderContext ac) => {
                Debug.Log("载材质加完成");
                HandlePointClouds(ac);
                //  ac.RootGameObject.transform.position = Camera.main.transform.forward;
                ManipulationHandler manipulation = gameObject.AddComponent<ManipulationHandler>();
                manipulation.enabled = false;
                BoundingBox boundingBox = gameObject.AddComponent<BoundingBox>();
                boundingBox.enabled = false;
                 ac.RootGameObject.SetActive(false);

                if (m_ModelObj && m_ModelObj.GetComponent<Animation>())
                {
                    Debug.Log("Animation===>1" + m_ModelObj.name);

                    Animation _animation = m_ModelObj.GetComponent<Animation>();
                    List<AnimationClip> _animations = _animation.GetAllAnimationClips();
                    m_ModelObj.GetComponent<Animation>().Play(_animations[0].name, PlayMode.StopAll);
                }
                if (this.gameObject.GetComponent<BoxCollider>())
                {
                    this.gameObject.GetComponent<BoxCollider>().size = Vector3.one * 0.4f;
                }

            }, (AssetLoaderContext ac, float f) => {

                Debug.Log("加载中==》" + f);
            }, (IContextualizedError error) => {

                Debug.Log("加载失败" + error);
            }, null, AssetLoaderOptions);

            }
            else
            {

            try
            {
                TriLibLocalLoad.Load(Data.localLoadPath, (AssetLoaderContext ac) => {
                
                }, (AssetLoaderContext ac) => {
                    Debug.Log("载材质加完成");
                        Bounds bounds = GetAllBounds.GetRendererBounds(ac.RootGameObject);
                        GameObject obj = new GameObject("Test");
                        obj.transform.position = bounds.center;
                        obj.transform.SetParent(ac.RootGameObject.transform);
                        float bizhi = 0.4f / bounds.size.x;
                        if(bizhi==float.NaN || bizhi == float.PositiveInfinity || bizhi == float.NegativeInfinity)
                        { bizhi = 1; }

                        ac.RootGameObject.transform.localScale = Vector3.one * bizhi;
                        ac.RootGameObject.transform.SetParent(this.transform.parent);
                        Vector3 v3local = (Vector3.zero - obj.transform.position);
                        ac.RootGameObject.transform.SetParent(this.transform);
                        ac.RootGameObject.transform.localPosition = v3local;
                        ac.RootGameObject.transform.localScale = ac.RootGameObject.transform.localScale * this.transform.localScale.x;
                        ac.RootGameObject.transform.localEulerAngles = Vector3.zero;
                        ac.RootGameObject.SetActive(true);

                        //  ac.RootGameObject.transform.position = Camera.main.transform.forward;
                        m_ModelObj = Instantiate(ac.RootGameObject, transform);
                        ManipulationHandler manipulation = gameObject.AddComponent<ManipulationHandler>();
                        manipulation.enabled = false;
                        BoundingBox boundingBox = gameObject.AddComponent<BoundingBox>();
                        boundingBox.enabled = false;
                        ac.RootGameObject.SetActive(false);

                        if (m_ModelObj && m_ModelObj.GetComponent<Animation>())
                        {
                            Debug.Log("Animation===>1" + m_ModelObj.name);

                            Animation _animation = m_ModelObj.GetComponent<Animation>();
                            List<AnimationClip> _animations = _animation.GetAllAnimationClips();
                            m_ModelObj.GetComponent<Animation>().Play(_animations[0].name, PlayMode.StopAll);
                        }
                        if (this.gameObject.GetComponent<BoxCollider>())
                        {
                            this.gameObject.GetComponent<BoxCollider>().size = Vector3.one * 0.4f;
                        }
                }, (AssetLoaderContext ac, float f) => {

                    Debug.Log("加载中==》" + f);
                }, (IContextualizedError error) => {

                    Debug.Log("加载失败" + error);
                },null, AssetLoaderOptions);
            }
            catch
            {
                Debug.Log("加载失败" + Data.localLoadPath);
                }
            }
        }
    }
    /// <summary>Handles Point Clouds rendering.</summary>
    /// <param name="assetLoaderContext">The Asset Loader Context reference. Asset Loader Context contains the Model loading data.</param>
    private void HandlePointClouds(AssetLoaderContext assetLoaderContext)
    {
        Material material = null;
        foreach (var gameObject in assetLoaderContext.GameObjects.Values)
        {
            m_ModelObj = Instantiate(gameObject, transform);
            if (m_ModelObj.TryGetComponent<MeshFilter>(out var meshFilter))
            {
                var points = meshFilter.sharedMesh.vertices;
                var colors = meshFilter.sharedMesh.colors32;
                if (colors == null || colors.Length != points.Length)
                {
                    colors = new Color32[points.Length];
                    for (var i = 0; i < colors.Length; i++)
                    {
                        colors[i] = Color.white;
                    }
                }
                if (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Direct3D11 && SystemInfo.graphicsDeviceType != GraphicsDeviceType.Direct3D12)
                {
                    UnityEngine.Debug.Log("graphicsDeviceTypegraphicsDeviceTypegraphicsDeviceType" + SystemInfo.graphicsDeviceType);
                    var mesh = new Mesh();
                    mesh.indexFormat = IndexFormat.UInt32;
                    mesh.SetVertices(points);
                    mesh.SetColors(colors);
                    mesh.SetIndices(
                        Enumerable.Range(0, points.Length).ToArray(),
                        MeshTopology.Points, 0
                    );
                    mesh.UploadMeshData(!assetLoaderContext.Options.ReadEnabled);
                    meshFilter.sharedMesh = mesh;
                    var meshRenderer = m_ModelObj.AddComponent<MeshRenderer>();
                    var materials = new Material[meshFilter.sharedMesh.subMeshCount];
                    if (material == null)
                    {
                        material = new Material(Shader.Find("Hidden/PointCloud_GL"));
                    }
                    for (var i = 0; i < materials.Length; i++)
                    {
                        materials[i] = material;
                    }
                    meshRenderer.materials = materials;
                }
                else
                {
                    var pointCloudRenderer = m_ModelObj.AddComponent<PointCloudRenderer>();
                    var data = ScriptableObject.CreateInstance<PointCloudData>();
                    data.Initialize(points, colors);
                    pointCloudRenderer.sourceData = data;
                    pointCloudRenderer.destroyData = true;
                    pointCloudRenderer.pointSize = 0.01f;
                    assetLoaderContext.Allocations.Add(data);
                }
            }
        }
    }
    public override void HideCollider()
    {
        base.HideCollider();
    }
}