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

namespace Thousandto.Launcher.ExternalLibs
{
    /// <summary>
    /// 场景地图区域数据
    /// </summary>
    public class SceneAssetsDiscriptFile : MonoBehaviour
    {
        #region//私有变量
        private int _multiLevel = 0;
        private List<string> _listMeshPath = new List<string>();
        private List<string> _listCombinMeshPath = new List<string>();
        //texture路径字典
        private List<string> _listTexName = new List<string>();
        private List<Transform> _transList = new List<Transform>();
        //材质球属性字典
        private Dictionary<string, MatAssetsProperty> _dicMatProperty = new Dictionary<string, MatAssetsProperty>();
        //mesh合并数据
        //private Dictionary<int, List<CombinData>> _dicCombinData = new Dictionary<int, List<CombinData>>();

        private List<RefrenceSize> _refrenceList = new List<RefrenceSize>();
        private List<Texture> _cacheSceneTexs = new List<Texture>();

        private SceneMultiTexScript _multiTexScript = null;
        //场景纹理multi等级数据块
        float[] _multiLevels = null;
        #endregion

        #region//公共变量
        //格子行列(这里默认行列相等)
        //public int RowCol = 0;
        public int[] RC = null;
        //格子宽
        public int[] CW = null;
        //public int CelWidth = 30;
        //地图最小坐标
        public Vector2 Min = Vector2.zero;
        //地图最大坐标
        public Vector2 Max = Vector2.zero;
        public RegionPart[] PBig = null;
        public RegionPart[] PMidle = null;
        public RegionPart[] PSmall = null;
        //所有物件纹理的路径
        public string[] TexNames = null;
        //所有物件mesh的路径
        //public string[] MeshPaths = null;
        //合并后的mesh路径
        //public string[] CombinMeshPath = null;
        //所有物件mat属性
        public MatAssetsProperty[] MatP_Dic = null;

        public static bool IsShowLine = true;    //是否显示划线


        #endregion

        #region// MonoBehaviour重载函数
        private void Start()
        {
            //Core编译会报错,先屏蔽掉 dinghuaqiang
            //Code.Center.SceneRestoreProxy.SetSceneRestoreHandle();
            RestoreMats();
        }

        private void OnDestroy()
        {
            //移除特效贴图
            SceneRestoreRunTimeUtils.ReleaseTexture();
#if !UNITY_EDITOR
            //移除场景贴图
            for (int i = 0; i < _cacheSceneTexs.Count; i++)
            {
                Resources.UnloadAsset(_cacheSceneTexs[i]);
                _cacheSceneTexs[i] = null;
            }
            _cacheSceneTexs.Clear();
#endif
            //干掉材质球
            var enumer = _dicSceneMat.GetEnumerator();
            try
            {
                while (enumer.MoveNext())
                {
                    var mat = enumer.Current.Value;
                    if (mat != null)
                    {
                        SceneRestoreRunTimeUtils.FreeMaterial(mat);
                    }
                }
            }
            finally {
                enumer.Dispose();
            }
        }
#endregion

#region//公共接口
        private Dictionary<int, Material> _dicSceneMat = new Dictionary<int, Material>();
        public void RestoreMats()
        {
            if (MatP_Dic != null && MatP_Dic.Length > 0)
            {
                SetParts(PBig);
                SetParts(PMidle);
                SetParts(PSmall);
            }
        }
        private void SetParts(RegionPart[] parts)
        {
            for (int i = 0; i < parts.Length; i++)
            {
                SetPartRender(parts[i]);
            }
        }
        private void SetPartRender(RegionPart part)
        {
            if (part == null)
                return;
            for (int i = 0; i < part.Descripts.Length; i++)
            {
                var descrip = part.Descripts[i];
                if (descrip.Trans != null)
                {
                    if (descrip.MatsData != null && descrip.MatsData.Length > 0)
                    {
                        SetMaterial(descrip.MatsData, descrip.Trans, descrip.RdType);
                    }
                }

            }
        }


        private void SetMaterial(MatrialAssetData[] dataArray, Transform trans, RendererType type)
        {
            var trailIndex = -1;
            Material[] mats = new Material[dataArray.Length];
            for (int i = 0; i < dataArray.Length; i++)
            {
                Material mat = null;
                if (!_dicSceneMat.TryGetValue(dataArray[i].Index, out mat))
                {
                    mat = RestoreMaterail(dataArray[i]);
                    _dicSceneMat.Add(dataArray[i].Index, mat);
                }
                if(dataArray[i].IsTrail)
                {
                    trailIndex = i;
                }
                mats[i] = mat;
            }
            switch (type)
            {
                case RendererType.MeshRenderer:
                    {
                        MeshRenderer mRd = trans.GetComponent<MeshRenderer>();
                        mRd.sharedMaterials = mats;
                    }
                    break;
                case RendererType.SkinMesh:
                    {
                        SkinnedMeshRenderer sRd = trans.GetComponent<SkinnedMeshRenderer>();
                        sRd.sharedMaterials = mats;
                    }
                    break;
                case RendererType.ParticleSystemRenderer:
                    {
                        ParticleSystemRenderer pRd = trans.GetComponent<ParticleSystemRenderer>();
                        if(trailIndex >= 0)
                        {
                            pRd.sharedMaterials = mats;
                            Material mat = null;
                            if (_dicSceneMat.TryGetValue(dataArray[trailIndex].Index, out mat))
                            {
                                pRd.trailMaterial = mat;
                            }
                        }
                        pRd.sharedMaterials = mats;
                    }
                    break;
                case RendererType.TrailRender:
                    {
                        TrailRenderer tRd = trans.GetComponent<TrailRenderer>();
                        tRd.sharedMaterials = mats;
                    }
                    break;
            }
        }
        private Material RestoreMaterail(MatrialAssetData data)
        {
            if (data == null)
                return null;
            if (data.Index == -1)
                return null;
            MatAssetsProperty property = GetMatProperty(data.Index);
            if (property == null)
                return null;
            Shader sh = ShaderFactory.Find(property.ShaderName);
            if (sh == null)
            {
                Debug.LogError("RestoreMaterial:not find shader;;" + property.ShaderName);
                return null;
            }

            Material mat = SceneRestoreRunTimeUtils.NewMaterial(sh);

            //设置需要动态加载的纹理
            if (property.TexIndexs != null)
            {
                //_isMatLoadFinished = false;

                for (int i = 0; i < property.TexIndexs.Length; i++)
                {
                    Texture tex = null;
                    //if (property.TexIndexs[i].MultiIndex != null && property.TexIndexs[i].MultiIndex.Length > 0)
                    //{
                    //    var length = property.TexIndexs[i].MultiIndex.Length;
                    //    for (int m = 0; m < length; m++)
                    //    {
                    //        var multiData = property.TexIndexs[i].MultiIndex[m];
                    //        if (_multiLevels == null)
                    //        {
                    //            _multiLevels = GonbestGMemory.AllocFloatBlock("SceneMultiLevel", 1);
                    //        }
                    //        _multiLevel = (int)_multiLevels[0];
                    //        //_multiLevel = 3;
                    //        if (_multiLevel == multiData.MultiIndex)
                    //        {
                    //            if (_multiTexScript == null)
                    //            {
                    //                _multiTexScript = GetMultiTexScript();
                    //            }
                    //            if(multiData.Index< _multiTexScript.MultiTexs.Length)
                    //                tex = _multiTexScript.MultiTexs[multiData.Index];
                    //        }
                    //    }
                    //}
                    //else
                    //{
                    //    tex = property.TexIndexs[i].tex;
                    //}
                    tex = property.TexIndexs[i].tex;
                    if (property.TexIndexs[i].Index == -1)
                    {
                       mat.SetTexture(property.TexIndexs[i].Name, tex);
                        _cacheSceneTexs.Add(tex);
                    }
                    else
                    {
                        string texName = property.TexIndexs[i].Name;
                        string texPath = GetTexturePath(property.TexIndexs[i].Index);
#if FUNCELL_LAUNCHER
                        SceneRestoreRunTimeUtils.SetTexture(texPath, texName, (t)=> {
                            mat.SetTexture(texName, t);
                        });
#else
#if UNITY_EDITOR
                        texPath = ConstDefines.CN_RAW_VFX_TEXTURE_DIR + texPath;
                        tex = UnityEditor.AssetDatabase.LoadAssetAtPath(texPath, typeof(Texture)) as Texture;
                        mat.SetTexture(property.TexIndexs[i].Name, tex);
#endif
#endif
                    }
                    mat.SetTextureOffset(property.TexIndexs[i].Name, property.TexOffset[i]);
                    mat.SetTextureScale(property.TexIndexs[i].Name, property.TexScale[i]);
                }
            }

            //设置四元值
            if (property.Vec != null)
            {
                for (int i = 0; i < property.Vec.Length; i++)
                {
                    mat.SetVector(property.Vec[i].Name, property.Vec[i].Value);
                }
            }

            //设置颜色
            if (property.Color != null)
            {
                for (int i = 0; i < property.Color.Length; i++)
                {
                    mat.SetColor(property.Color[i].Name, property.Color[i].Value);
                }
            }

            //设置float值
            if (property.Float != null)
            {
                for (int i = 0; i < property.Float.Length; i++)
                {
                    mat.SetFloat(property.Float[i].Name, property.Float[i].Value);
                }
            }
            //设置renderQueen
            if (property.Rdq == 0)
            {
                mat.renderQueue = sh.renderQueue;
            }
            else
            {
                mat.renderQueue = property.Rdq;
            }
            return mat;
        }

        public void Initialized()
        {
            RC = new int[(int)CellType.Count];
            for (int i = 0; i < (int)CellType.Count; i++)
            {
                RC[i] = 1;
            }
            CW = new int[(int)CellType.Count];
            CW[0] = (int)CellWideType.Wide_0;
            CW[1] = (int)CellWideType.Wide_1;
            CW[2] = (int)CellWideType.Wide_2;

            RefrenceSize size1 = new RefrenceSize(CellType.Level_0, RefrenceSize.RootType.Big, 45, int.MaxValue);
            RefrenceSize size2 = new RefrenceSize(CellType.Level_1, RefrenceSize.RootType.Mid, 3, 45);
            RefrenceSize size3 = new RefrenceSize(CellType.Level_2, RefrenceSize.RootType.Small, 0, 3);
            _refrenceList.Add(size1);
            _refrenceList.Add(size2);
            _refrenceList.Add(size3);
        }
        public void SetRegion(Vector2 min, Vector3 max, CellType type)
        {
            RC[(int)type] = 1;
            Min = min;
            Max = max;
            float wide = max.x - min.x;
            float high = max.y - min.y;
            float celWide = wide / RC[(int)type];
            SetPart(celWide, wide, type);
            celWide = wide / RC[(int)type];
            float celHigh = high / RC[(int)type];
            int count = (int)Mathf.Pow(RC[(int)type], 2);
            var parts = NewParts(type, count);
            for (int i = 0; i < count; i++)
            {
                RegionPart part = new RegionPart(i, RC[(int)type], celWide, celHigh, Min);
                parts[i] = part;
            }
        }
        public int GetTexturePathIndex(string name, string path)
        {
            int index = 0;
            if (path.Contains(ConstDefines.CN_RAW_VFX_TEXTURE_DIR))
            {
                path = path.Replace(ConstDefines.CN_RAW_VFX_TEXTURE_DIR, "");
            }
            if (_listTexName.Contains(path))
            {
                for (int i = 0; i < _listTexName.Count; i++)
                {
                    if (string.Equals(_listTexName[i], path))
                        return i;
                }
            }
            else
            {
                _listTexName.Add(path);
                return _listTexName.Count - 1;
            }
            return index;
        }
        public void ConvertTexPath()
        {
            TexNames = _listTexName.ToArray();
            _listTexName.Clear();
            _listTexName = null;
        }

        public string GetTexturePath(int index)
        {
            if (index <= TexNames.Length - 1)
            {
                return TexNames[index];
            }
            return string.Empty;
        }

        public void ConvertMeshPath()
        {
            //MeshPaths = _listMeshPath.ToArray();
        }

        public void ConvertCombinMeshPath()
        {
            //CombinMeshPath = _listCombinMeshPath.ToArray();
        }

        public int GetMeshPathIndex(string path)
        {
            int index = _listMeshPath.IndexOf(path);
            if(index < 0)
            {
                _listMeshPath.Add(path);
                return _listMeshPath.Count - 1;
            }
            return index;
        }

        public string GetMeshPath(int index)
        {
            //if (MeshPaths !=null && index < MeshPaths.Length)
            //{
            //    return MeshPaths[index];
            //}
            return string.Empty;
        }

        //获取合并后mesh 的路径索引
        public int GetCombinMeshPathIndex(string path)
        {
            int index = _listCombinMeshPath.IndexOf(path);
            if (index < 0)
            {
                _listCombinMeshPath.Add(path);
                return _listCombinMeshPath.Count - 1;
            }
            return index;
        }

        //获取合并后的mesh路径
        public string GetCombinMeshPath(int index)
        {
            //if (CombinMeshPath != null && index < CombinMeshPath.Length)
            //{
            //    return CombinMeshPath[index];
            //}
            return string.Empty;
        }

        //获取物件的index
        public int GetObjIndex(Transform trans)
        {
            int index = -1;
            if (trans == null)
                return index;

            index = _transList.IndexOf(trans);
            if (index < 0)
            {
                _transList.Add(trans);
                return _transList.Count - 1;
            }
            return index;
        }

        public int GetMatPropertyIndex(MatAssetsProperty property)
        {
            var name = property.name;
            int index = 0;
            var enumer = _dicMatProperty.GetEnumerator();
            try
            {
                //shander  参数是设置相等
                bool isEqual = true;
                //是否找到同名shander或者 ReName的同名shander
                bool isFind = false;
                while (enumer.MoveNext())
                {
                    if (string.Equals(enumer.Current.Key, name) || enumer.Current.Key.Contains(string.Format("{0}_ReName", name)))//
                    {
                        isEqual = true;
                        isFind = true;
                        MatAssetsProperty mp = enumer.Current.Value;
                        for (int i = 0; i < mp.Vec.Length; i++)
                        {
                            if (mp.Vec.Length != property.Vec.Length)
                                isEqual = false;
                            else
                            {
                                if (!string.Equals(mp.Vec[i].Name, property.Vec[i].Name))
                                    isEqual = false;
                                if (mp.Vec[i].Value != property.Vec[i].Value)
                                    isEqual = false;
                            }
                        }
                        if (mp.TexIndexs.Length != property.TexIndexs.Length)
                            isEqual = false;
                        else
                        {
                            for (int i = 0; i < mp.TexIndexs.Length; i++)
                            {
                                if (mp.TexIndexs[i].tex != property.TexIndexs[i].tex)
                                    isEqual = false;
                                else
                                {
                                    if (mp.TexIndexs[i].tex == null)
                                    {
                                        if (mp.TexIndexs[i].Index != property.TexIndexs[i].Index)
                                            isEqual = false;
                                    }
                                }
                            }
                        }
                        for (int i = 0; i < mp.Color.Length; i++)
                        {
                            if (mp.Color.Length != property.Color.Length)
                                isEqual = false;
                            else
                            {
                                if (!string.Equals(mp.Color[i].Name, property.Color[i].Name))
                                    isEqual = false;
                                if (mp.Color[i].Value != property.Color[i].Value)
                                    isEqual = false;
                            }
                        }
                        for (int i = 0; i < mp.Float.Length; i++)
                        {
                            if (mp.Float.Length != property.Float.Length)
                                isEqual = false;
                            else
                            {
                                if (!string.Equals(mp.Float[i].Name, property.Float[i].Name))
                                    isEqual = false;
                                if (mp.Float[i].Value != property.Float[i].Value)
                                    isEqual = false;
                            }
                        }
                        for (int i = 0; i < mp.TexOffset.Length; i++)
                        {
                            if (mp.TexOffset.Length != property.TexOffset.Length)
                                isEqual = false;
                            else
                            {
                                if (mp.TexOffset[i] != property.TexOffset[i])
                                    isEqual = false;
                            }
                        }
                        for (int i = 0; i < mp.TexScale.Length; i++)
                        {
                            if (mp.TexScale.Length != property.TexScale.Length)
                                isEqual = false;
                            else
                            {
                                if (mp.TexScale[i] != property.TexScale[i])
                                    isEqual = false;
                            }
                        }
                        if (mp.Rdq != property.Rdq)
                        {
                            isEqual = false;
                        }
                        if (isEqual)
                        {
                            //如果找到想的设置参数的shader 直接返回索引
                            return index;
                        }
                    }
                    index += 1;
                }
                if (isFind)
                {
                    if (!isEqual)
                    {
                        //如果shader设置不相等  添加进Dic 重置名字
                        string key = string.Format("{0}_ReName_{1}", name, _dicMatProperty.Count - 1);
                        _dicMatProperty[key] = property;
                        property.name = "";
                        return _dicMatProperty.Count - 1;
                    }
                }
                else
                {
                    //如果没有找到 直接添加进dic
                    _dicMatProperty[name] = property;
                    property.name = "";
                    return _dicMatProperty.Count - 1;
                }
            }
            finally
            {
                enumer.Dispose();
            }
            return -1;
        }

        public MatAssetsProperty GetMatProperty(int index)
        {
            if (MatP_Dic != null && index < MatP_Dic.Length)
            {
                return MatP_Dic[index];
            }
            return null;
        }

        public void ConvertMatProperty()
        {
            List<MatAssetsProperty> list = new List<MatAssetsProperty>();
            var enumer = _dicMatProperty.GetEnumerator();
            try
            {
                while (enumer.MoveNext())
                {
                    list.Add(enumer.Current.Value);
                }
            }
            finally
            {
                enumer.Dispose();
            }
            MatP_Dic = list.ToArray();
            _dicMatProperty.Clear();
            _dicMatProperty = null;
        }
        public RegionPart[] GetParts(CellType type)
        {
            RegionPart[] parts = null;
            switch (type)
            {
                case CellType.Level_0:
                    parts = PBig;
                    break;
                case CellType.Level_1:
                    parts = PMidle;
                    break;
                case CellType.Level_2:
                    parts = PSmall;
                    break;
            }
            return parts;
        }

        public RefrenceSize GetRefSize(CellType type)
        {
            for (int i = 0; i < _refrenceList.Count; i++)
            {
                if (_refrenceList[i].Type == type)
                    return _refrenceList[i];
            }
            return null;
        }

        public SceneMultiTexScript GetMultiTexScript()
        {
            if (_multiTexScript == null)
            {
                _multiTexScript = transform.GetComponent<SceneMultiTexScript>();
            }
            return _multiTexScript;
        }
#endregion

#region//私有函数
        private void SetPart(float celWide, float wide, CellType type)
        {
            if (celWide > CW[(int)type])
            {
                RC[(int)type] += 1;
                celWide = wide / RC[(int)type];
                SetPart(celWide, wide, type);
            }
        }
        private RegionPart[] NewParts(CellType type, int count)
        {
            switch (type)
            {
                case CellType.Level_0:
                    return PBig = new RegionPart[count];
                case CellType.Level_1:
                    return PMidle = new RegionPart[count];
                case CellType.Level_2:
                    return PSmall = new RegionPart[count];
            }
            return null;
        }

        private void OnDrawGizmos()
        {
            if (!IsShowLine)
                return;
            CellType type = CellType.Level_2;
            Gizmos.color = Color.red;
            var parts = GetParts(type);
            if (parts == null || RC == null || RC.Length < 3)
                return;
            int tolCl = parts.Length / RC[2];           //总行数
            int tolRl = RC[2];           //总列数 
            for (int i = 0; i < tolCl; i++)
            {
                Gizmos.DrawLine(parts[i * RC[2]].GetMin() + new Vector3(0f, 27, 0f), parts[i * RC[2] + (RC[2] - 1)].GetMin() +
                    new Vector3(parts[i * RC[2] + (RC[2] - 1)].GetBounds().size.x, 27f, 0f));
            }
            Gizmos.DrawLine(parts[(tolCl - 1) * RC[2]].GetMin() + new Vector3(0f, 27f, parts[(tolCl - 1) * RC[2]].GetBounds().size.z),
                parts[(tolCl - 1) * RC[2] + (RC[2] - 1)].GetMax() + new Vector3(0f, 27, 0f));
            Gizmos.color = Color.blue;
            for (int i = 0; i < tolRl; i++)
            {
                Gizmos.DrawLine(parts[i].GetMin() + new Vector3(0f, 27, 0f), parts[RC[2] * (tolRl - 1) + i].GetMin() + new Vector3(0f, 27f, parts[RC[2] * (tolRl - 1) + i].GetBounds().size.z));
            }
            Gizmos.DrawLine(parts[tolRl - 1].GetMin() + new Vector3(parts[tolRl - 1].GetBounds().size.x, 27f, 0f)
                , parts[RC[2] * (tolRl - 1) + (tolRl - 1)].GetMax() + new Vector3(0f, 27, 0f));
            Gizmos.color = Color.blue;
            //Gizmos.DrawCube(Parts[0].Center, new Vector3(Parts[0].Bounds.size.x, 0f, Parts[0].Bounds.size.z));
            Gizmos.DrawCube(new Vector3(Min.x, 10, Min.y), new Vector3(10, 10, 10));
            Gizmos.color = Color.green;
            Gizmos.DrawCube(new Vector3(Max.x, 10, Max.y), new Vector3(10, 10, 10));
        }
#endregion
    }
}