using XGame.Framework.Asset.Addressable;
using XGame.Framework.Asset.Addressable.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace XGame.Editor.Asset
{
    public static class AddressableInfosSoExt
    {
        #region AddressableAssetInfoManifest
        /// <summary>
        /// 编辑器扩展方法
        /// 返回manifest内已有数据
        /// </summary>
        /// <param name="manifest"></param>
        /// <returns></returns>
        public static List<AssetInfo> GetAssetInfos(this AddressableInfosSo manifest)
        {
            if (manifest != null && manifest.assetInfos != null)
            {
                return manifest.assetInfos.Distinct().ToList();
            }
            //var fileInfo = manifest.GetType().GetField("assetInfos", BindingFlags.NonPublic | BindingFlags.Instance);
            //if (fileInfo != null)
            //{
            //    var infos = (AssetInfo[])fileInfo.GetValue(manifest);
            //    if (infos != null)
            //    {
            //        return infos.Distinct().ToList();
            //    }
            //}
            return new List<AssetInfo>();
        }
        /// <summary>
        /// 返回以GUID做key的字典
        /// </summary>
        /// <param name="manifest"></param>
        /// <returns></returns>
        public static Dictionary<string, AssetInfo> GetAssetInfoMapWithGUID(this AddressableInfosSo manifest)
        {
            var map = new Dictionary<string, AssetInfo>();
            if (manifest != null && manifest.assetInfos != null)
            {
                foreach (var info in manifest.assetInfos)
                {
                    var guid = info.assetGUID;
                    if (!map.ContainsKey(guid))
                    {
                        map.Add(guid, info);
                    }
                    else
                    {
                        Debug.LogError($"AssetInfo repeated. Last:{map[guid]} Next:{info}");
                    }
                }
            }
            return map;
        }
        /// <summary>
        /// 返回以addressableName做key的字典
        /// </summary>
        /// <param name="manifest"></param>
        /// <returns></returns>
        public static Dictionary<string, AssetInfo> GetAssetInfoMapWithAddressableName(this AddressableInfosSo manifest)
        {
            var map = new Dictionary<string, AssetInfo>();
            if (manifest != null && manifest.assetInfos != null)
            {
                foreach (var info in manifest.assetInfos)
                {
                    map.Add(info.addressableName, info);
                }
            }
            return map;
        }
        /// <summary>
        /// 编辑器扩展方法
        /// 设置AddressableAssetInfo数组
        /// </summary>
        /// <param name="manifest"></param>
        /// <param name="assetInfos"></param>
        public static void SetAssetInfos(this AddressableInfosSo manifest, AssetInfo[] assetInfos)
        {
            if (manifest == null) return;
            if (assetInfos != null)
            {
                assetInfos = assetInfos.Distinct().ToArray();
                Array.Sort(assetInfos);
            }
            manifest.assetInfos = assetInfos;
            EditorUtility.SetDirty(manifest);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        /// <summary>
        /// 编辑器扩展方法
        /// 根据GUID查找addressableName
        /// </summary>
        /// <param name="manifest"></param>
        /// <param name="guid"></param>
        /// <param name="addressableName"></param>
        /// <returns></returns>
        public static bool TryGetAddressableNameByGUID(this AddressableInfosSo manifest, string guid, out string addressableName)
        {
            addressableName = string.Empty;
            if (manifest != null && manifest.assetInfos != null)
            {
                var index = Array.FindIndex(manifest.assetInfos, (info => info.assetGUID.Equals(guid)));
                if (index < 0)
                {
                    return false;
                }
                addressableName = manifest.assetInfos[index].addressableName;
            }
            return true;
        }

        /// <summary>
        /// 编辑器扩展方法
        /// 修改某个资源的addressableName
        /// </summary>
        /// <param name="manifest"></param>
        /// <param name="guid"></param>
        /// <param name="addressableName"></param>
        /// <param name="assetInfo"></param>
        /// <returns></returns>
        public static bool TryApplyAddressableName(this AddressableInfosSo manifest, string guid,
            string addressableName, out AssetInfo assetInfo)
        {
            var assetInfos = manifest.assetInfos;
            //转成小写
            addressableName = addressableName.ToLower();
            //检查重名
            var idxForName = Array.FindIndex(assetInfos, (info => info.addressableName.Equals(addressableName)));
            var idxForGUID = Array.FindIndex(assetInfos, (info => info.assetGUID.Equals(guid)));
            if (idxForName >= 0)
            {
                if (idxForGUID != idxForName)
                {
                    Debug.LogError($"AddressableName repeat. Please rename it. Name:{addressableName} Path:{AssetDatabase.GUIDToAssetPath(guid)}");
                }
                else
                {
                    Debug.Log($"Asset info hasn't changed.");
                }
                assetInfo = default;
                return false;
            }
            if (idxForGUID >= 0)
            {
                assetInfo = assetInfos[idxForGUID];
                assetInfo.addressableName = addressableName;
                assetInfos[idxForGUID] = assetInfo;
                //保存
                manifest.SetAssetInfos(assetInfos);
                Debug.Log($"Apply AddressableName Success. Path:{assetInfo.GetAssetPath()}  AddressableName:{addressableName}");
                return true;
            }
            Debug.LogError("Can't Find Asset.");
            assetInfo = default;
            return false;
        }
        /// <summary>
        /// 编辑器扩展方法
        /// 删除指定资源信息
        /// </summary>
        /// <param name="manifest"></param>
        /// <param name="guid"></param>
        /// <returns></returns>
        public static bool TryRemoveAssetByGUID(this AddressableInfosSo manifest, string guid)
        {
            if (manifest.assetInfos == null || manifest.assetInfos.Length == 0)
            {
                Debug.Log($"AddressableInfosSo is null. Name:{manifest.name}");
                return false;
            }
            var assetInfos = manifest.assetInfos.ToList();
            var idxForGUID = assetInfos.FindIndex((info => info.assetGUID.Equals(guid)));

            if (idxForGUID == -1)
            {
                Debug.Log($"Can't find assetInfo by GUID:{guid}");
                return false;
            }
            var assetInfo = assetInfos[idxForGUID];
            assetInfos.RemoveAt(idxForGUID);
            //保存
            manifest.SetAssetInfos(assetInfos.ToArray());
            //EditorUtility.SetDirty(manifest);
            //AssetDatabase.SaveAssets();
            //AssetDatabase.Refresh();
            Debug.Log($"RemoveAsset Success. {assetInfo}");
            return true;
        }

        public static bool RemoveAllInvalidAssets(this AddressableInfosSo manifest)
        {
            var assetInfos = manifest.assetInfos;
            if (assetInfos == null || assetInfos.Length == 0)
            {
                Debug.Log($"AddressableInfosSo is null. Name:{manifest.name}");
                return false;
            }
            var validAssetInfos = Array.FindAll(assetInfos, (info => AddressableHelper.IsValidPath(info.GetAssetPath())));
            if (assetInfos.Length == validAssetInfos.Length)
            {
                Debug.Log("No find invalid assets.");
                return false;
            }
            //保存
            manifest.SetAssetInfos(validAssetInfos);
            //EditorUtility.SetDirty(manifest);
            //AssetDatabase.SaveAssets();
            //AssetDatabase.Refresh();
            Debug.Log("RemoveAllInvalidAssets Success.");
            return true;
        }
        #endregion

        #region i18n 国际化/本地化/多语言
        public static void SetAddressableI18nInfos(this AddressableInfosSo manifest,
            AddressableI18nInfo[] i18nInfos, bool refresh = true)
        {
            if (manifest == null) return;
            manifest.i18nInfos = i18nInfos;
            if (refresh)
            {
                EditorUtility.SetDirty(manifest);
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
            }
        }
        #endregion

        #region LOD

        public static void SetAddressableLodInfos(this AddressableInfosSo manifest,
            AddressableLodInfo[] lodInfos, bool refresh = true)
        {
            if (manifest == null) return;
            manifest.lodInfos = lodInfos;
            if (refresh)
            {
                EditorUtility.SetDirty(manifest);
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
            }
        }

        #endregion

    }

}

