using XGame.Framework.i18n;
using XGame.Framework.Asset.Addressable;
using XGame.Framework.Asset.Addressable.Data;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;


namespace XGame.Editor.Asset
{
    public static partial class AddressableHelper
    {
        private static readonly AddressableClassify[] QueryOrder = { AddressableClassify.Product, AddressableClassify.BuiltIn, AddressableClassify.Tests };
        /// <summary>
        /// 检测AddressableId的唯一性
        /// </summary>
        //[MenuItem("Tools/AssetBundle/VerifyAddressableId")]
        public static void VerifyAddressableIdUniqueness()
        {
            var assetInfoMap = new Dictionary<long, AssetInfo>();
            VerifyAddressableIdUniqueness(LoadAssetManifest(AddressableClassify.BuiltIn), ref assetInfoMap);
            VerifyAddressableIdUniqueness(LoadAssetManifest(), ref assetInfoMap);
            VerifyAddressableIdUniqueness(LoadAssetManifest(AddressableClassify.Tests), ref assetInfoMap);
            Debug.Log("VerifyAddressableIdUniqueness completed.");
        }
        private static void VerifyAddressableIdUniqueness(AddressableInfosSo manifest, ref Dictionary<long, AssetInfo> assetInfoMap)
        {
            if (manifest == null || manifest.assetInfos == null)
            {
                //Debug.Log("Verify AddressableId Uniqueness. But can't find AddressableAssetInfoManifest.");
                return;
            }
            //key:addressableId
            ////var assetInfoMap = new Dictionary<long, AddressableAssetInfo>();
            foreach (var assetInfo in manifest.assetInfos)
            {
                if (assetInfoMap.ContainsKey(assetInfo.addressableId))
                {
                    Debug.LogError($"AddressableId repeat. Last:{assetInfoMap[assetInfo.addressableId]} Next:{assetInfo}");
                }
                else
                {
                    assetInfoMap.Add(assetInfo.addressableId, assetInfo);
                }
            }
        }
        
        /// <summary>
        /// 资源目录
        /// </summary>
        public static string[] GetAssetsRoots(AddressableClassify classify = AddressableClassify.Product)
        {
            var roots = new List<string>();
            switch (classify)
            {
                case AddressableClassify.BuiltIn:
                    if (Directory.Exists(PathDefine.BuiltInResourcesRelative))
                    {
                        roots.Add(PathDefine.BuiltInResourcesRelative);
                    }
                    break;
                case AddressableClassify.Tests:

                    if (Directory.Exists(PathDefine.TestsToAddressable))
                    {
                        roots.Add(PathDefine.TestsToAddressable);
                    }

                    if (Directory.Exists(PathDefine.BuiltInResTests))
                    {
                        roots.Add(PathDefine.BuiltInResTests);
                    }

                    break;
                default:
                    return FileUtil.GetProductAssetsRoots(true);
                    //{
                    //    if (Directory.Exists(PathDefine.ResAddressableRelative))
                    //    {
                    //        roots.Add(PathDefine.ResAddressableRelative);
                    //    }
                    //    if (Directory.Exists(PathDefine.ResourcesRelative))
                    //    {
                    //        roots.Add(PathDefine.ResourcesRelative);
                    //    }
                    //    if (Directory.Exists(PathDefine.I18nAssetsRelative))
                    //    {
                    //        var directorys = Directory.GetDirectories(PathDefine.I18nAssetsRelative, PathDefine.ResAddressableName, SearchOption.AllDirectories);
                    //        foreach(var directory in directorys)
                    //        {
                    //            roots.Add(directory.Replace("\\", "/"));
                    //        }
                    //    }
                    //}
                    //break;
            }
            return roots.ToArray();
        }
        public static bool TryAssetPathToClassify(string assetPath, out AddressableClassify classify)
        {
            classify = AddressableClassify.Product;
            if (string.IsNullOrEmpty(assetPath))
            {
                return false;
            }
            //assetPath = FileUtil.ToRelativePath(assetPath);
            if (IsValidPath(assetPath, AddressableClassify.Product))
            {
                //在 Res/Addressable || Resources 目录下
                classify = AddressableClassify.Product;
                return true;
            }
            if (IsValidPath(assetPath, AddressableClassify.BuiltIn))
            {
                //在Package Framework目录下
                classify = AddressableClassify.BuiltIn;
                return true;
            }
            if (IsValidPath(assetPath, AddressableClassify.Tests))
            {
                //在ResStatic目录下
                classify = AddressableClassify.Tests;
                return true;
            }
            return false;
        }
        public static LanguageType GetLanguageTypeByAssetPath(string assetPath)
        {
            if (string.IsNullOrEmpty(assetPath))
            {
                return LanguageType.NONE;
            }
            var match = i18nAssetRegex.Match(assetPath);
            if (match.Success)
            {
                var i18nName = match.Groups[1].Value;
                return LanguageUtils.ToLanguageType(i18nName);
            }
            return LanguageType.NONE;
        }
        /// <summary>
        /// i18n资源路径正则
        /// </summary>
        private static Regex i18nAssetRegex = new Regex(@"^Assets/i18n/(.+?)/Res/Addressable");
        /// <summary>
        /// 是否是国际化资源
        /// </summary>
        /// <param name="assetPath"></param>
        /// <returns></returns>
        public static bool IsI18nAssetPath(string assetPath)
        {
            if (string.IsNullOrEmpty(assetPath))
            {
                return false;
            }
            if (i18nAssetRegex.IsMatch(assetPath))
            {
                //在国际化资源目录下
                return true;
            }
            return false;
        }
        /// <summary>
        /// 检测路径是否是指定类型的资源路径
        /// </summary>
        /// <param name="assetPath"></param>
        /// <param name="classify"></param>
        /// <returns></returns>
        public static bool IsValidPath(string assetPath, AddressableClassify classify)
        {
            if (string.IsNullOrEmpty(assetPath))
            {
                return false;
            }
            switch (classify)
            {
                case AddressableClassify.BuiltIn:
                    if (assetPath.StartsWith(PathDefine.XGamePackageRelative))
                    {
                        //在Package Framework目录下
                        return true;
                    }
                    break;
                case AddressableClassify.Tests:
                    if (assetPath.StartsWith(PathDefine.TestsToAddressable) || assetPath.StartsWith(PathDefine.BuiltInResTests))
                    {
                        //在ResStatic目录下 或者在 在Package ResStatic目录下
                        return true;
                    }
                    break;
                default:
                    if (assetPath.StartsWith(PathDefine.ResAddressableRelative))
                    {
                        //在Res/Addressable目录下
                        return true;
                    }
                    if (assetPath.StartsWith(PathDefine.ResourcesRelative))
                    {
                        //在Resources目录下
                        return true;
                    }
                    if (IsI18nAssetPath(assetPath))
                    {
                        //在国际化资源目录下
                        return true;
                    }
                    break;
            }
            return false;
        }
        /// <summary>
        /// 检测一个资源路径是否有效
        /// 用于判断指定Asset是否可以生成AddressableName
        /// </summary>
        /// <param name="assetPath">使用Unity的相对路径</param>
        /// <returns></returns>
        public static bool IsValidPath(string assetPath)
        {
            if (string.IsNullOrEmpty(assetPath))
            {
                return false;
            }
            if (!File.Exists(assetPath))
            {
                Debug.LogWarning($"File can't find. Path:{assetPath}");
                return false;
            }
            assetPath = FileUtil.ToRelativePath(assetPath);

            if (IsValidPath(assetPath, AddressableClassify.Product))
            {
                //项目资源
                return true;
            }
            if (IsValidPath(assetPath, AddressableClassify.BuiltIn))
            {
                //在Package Framework目录下
                return true;
            }
            if (IsValidPath(assetPath, AddressableClassify.Tests))
            {
                //在ResStatic目录下
                return true;
            }
            return false;
        }

        public static bool IsInResources(string assetPath, out string relativePath)
        {
            relativePath = string.Empty;
            if (string.IsNullOrEmpty(assetPath))
            {
                return false;
            }
            if (!File.Exists(assetPath))
            {
                Debug.LogWarning($"File can't find. Path:{assetPath}");
                return false;
            }
            //项目资源
            assetPath = FileUtil.ToRelativePath(assetPath);
            var resRelative = $"{PathDefine.ResourcesRelative}/";
            if (assetPath.StartsWith(resRelative))
            {
                //在Resources目录下
                relativePath = assetPath.Substring(resRelative.Length);
                relativePath = relativePath.Replace(Path.GetExtension(relativePath), "");
                //Debug.LogWarning($"assetPath: {assetPath} GetDirectoryName: {Path.GetDirectoryName(assetPath)}  ResourcesPath: {resRelative} file:{Path.GetFileNameWithoutExtension(assetPath)} relativePath:{relativePath}");
                return true;
            }
            //包内资源
            var pkgResources = $"{PathDefine.BuiltInResourcesRelative}/";
            if (assetPath.StartsWith(pkgResources))
            {
                //在Resources目录下
                relativePath = assetPath.Substring(pkgResources.Length);
                relativePath = relativePath.Replace(Path.GetExtension(relativePath), "");
                //Debug.LogWarning($"assetPath: {assetPath} GetDirectoryName: {Path.GetDirectoryName(assetPath)}  ResourcesPath: {pkgResources} file:{Path.GetFileNameWithoutExtension(assetPath)} relativePath:{relativePath}");
                return true;
            }
            return false;
        }
        /// <summary>
        /// 取文件名
        /// 若名字为数字，则加上父文件夹名
        /// </summary>
        /// <param name="assetPath"></param>
        /// <returns></returns>
        public static string GetFileName(string assetPath)
        {
            if (string.IsNullOrEmpty(assetPath))
                return string.Empty;
            var fileName = Path.GetFileNameWithoutExtension(assetPath);
            // ReSharper disable once UnusedVariable
            if (FileUtil.IsNumberic(fileName, out var result))
            {
                fileName = $"{FileUtil.GetDirectoryName(assetPath, false)}_{fileName}";
            }
            //删除空格，将'.'转为'_'，然后转小写
            fileName = fileName.Replace(" ", "").Replace('.', '_').ToLower();
            return fileName;
        }
        public static string GetFileNameIncludeI18n(string assetPath)
        {
            var i18nName = string.Empty;
            var langFlag = GetLanguageTypeByAssetPath(assetPath);
            if (langFlag != LanguageType.NONE)
            {
                i18nName = langFlag.ToString().ToLower();
            }
            var fileName = GetFileName(assetPath);
            if (langFlag != LanguageType.NONE)
            {
                fileName = $"{i18nName}_{fileName}";
            }
            return fileName;
        }
        /// <summary>
        /// GUID转AddressableName
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public static string GUIDToName(string guid)
        {
            var addressableName = string.Empty;
            if (!string.IsNullOrEmpty(guid))
            {
                var assetPath = AssetDatabase.GUIDToAssetPath(guid);
                if (TryAssetPathToClassify(assetPath, out var classify))
                {
                    LoadAssetManifest(classify)?.TryGetAddressableNameByGUID(guid, out addressableName);
                }

            }
            return addressableName;
        }
        /// <summary>
        /// AssetPath转AddressableName
        /// </summary>
        /// <param name="assetPath"></param>
        /// <returns></returns>
        public static string AssetPathToName(string assetPath)
        {
            var addressableName = string.Empty;
            if (TryAssetPathToClassify(assetPath, out var classify))
            {
                var guid = AssetDatabase.AssetPathToGUID(assetPath);
                LoadAssetManifest(classify)?.TryGetAddressableNameByGUID(guid, out addressableName);
            }
            return addressableName;
        }
        /// <summary>
        /// AddressableName转AssetPath
        /// </summary>
        /// <param name="addressableName"></param>
        /// <returns></returns>
        public static string NameToAssetPath(string addressableName)
        {
            if (!string.IsNullOrEmpty(addressableName))
                addressableName = addressableName.ToLower();
            for (int i = 0; i < QueryOrder.Length; i++)
            {
                var assetPath = NameToAssetPath(addressableName, QueryOrder[i]);
                if (!string.IsNullOrEmpty(assetPath))
                {
                    return assetPath;
                }
            }
            return string.Empty;
        }
        private static string NameToAssetPath(string addressableName, AddressableClassify classify)
        {
            var manifest = LoadAssetManifest(classify);
            if (manifest != null && manifest.assetInfos != null)
            {
                var assetInfos = manifest.assetInfos;
                var index = System.Array.FindIndex(assetInfos, (info => info.addressableName.Equals(addressableName.ToLower())));
                if (index >= 0)
                {
                    return assetInfos[index].GetAssetPath();
                }
            }
            return string.Empty;
        }
        /// <summary>
        /// LoadAsset
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="addressableName"></param>
        /// <returns></returns>
        public static T LoadAssetByName<T>(string addressableName) where T : Object
        {
            var assetPath = NameToAssetPath(addressableName);
            if (string.IsNullOrEmpty(assetPath))
            {
                return default(T);
            }
            return AssetDatabase.LoadAssetAtPath<T>(assetPath);
        }

        /// <summary>
        /// 加载源资源(非克隆对象)
        /// </summary>
        /// <param name="addressableName"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T LoadMainAssetByName<T>(string addressableName) where T : Object
        {
            var assetPath = NameToAssetPath(addressableName);
            if (string.IsNullOrEmpty(assetPath))
            {
                return default(T);
            }
            return AssetDatabase.LoadMainAssetAtPath(assetPath) as T;
        }

        public static bool IsValidName(string addressableName)
        {
            var assetPath = NameToAssetPath(addressableName);
            return string.IsNullOrEmpty(assetPath) == false;
        }
        /// <summary>
        /// 根据assetPath判断是否LOD资源
        /// </summary>
        /// <param name="assetPath"></param>
        /// <returns></returns>
        internal static bool IsLodAssetPath(string assetPath)
        {
            if (string.IsNullOrEmpty(assetPath)) return false;
            var fileName = Path.GetFileNameWithoutExtension(assetPath).ToLower();
            return fileName.EndsWith(PathDefine.LodHigh) || fileName.EndsWith(PathDefine.LodLow);
        }

    }

}

