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

namespace XGame.Editor.Asset
{
    public class AddressableBuildTask
    {
        /// <summary>
        /// 方便其它模块使用
        /// </summary>
        public static void GenManifest()
        {
            var task = new AddressableBuildTask();
            task.Run();
        }
        private IDictionary<AddressableClassify, AddressableInfoManifest> manifests;
        private AddressableInfoManifest backupManifest;
        private IDictionary<string, AddressableClassify> addressableNameMap;
        private IDictionary<long, AddressableClassify> addressableIdMap;
        private IDictionary<string, AddressableClassify> guidMap;

        private AddressableClassify[] queryOrder;
        public AddressableBuildTask()
        {
            manifests = new Dictionary<AddressableClassify, AddressableInfoManifest>();
            addressableNameMap = new Dictionary<string, AddressableClassify>();
            addressableIdMap = new Dictionary<long, AddressableClassify>();
            guidMap = new Dictionary<string, AddressableClassify>();
            queryOrder = new AddressableClassify[] { AddressableClassify.Product, AddressableClassify.BuiltIn, AddressableClassify.Tests };
        }
        private void Init()
        {
            LoadManifest();
            DisposeInvalidAssets();
            CollectAddressableAssets();
        }
        public void Run()
        {
            Init();
            Collect();
            Save();
        }
        private void Collect()
        {
            AddressableClassify[] classifys = { AddressableClassify.BuiltIn, AddressableClassify.Product, AddressableClassify.Tests };
            for (int i = 0; i < classifys.Length; i++)
            {
                var classify = classifys[i];
                string[] assetsRoots = AddressableHelper.GetAssetsRoots(classify);
                foreach (var assetsRoot in assetsRoots)
                {
                    var i18nName = string.Empty;
                    var langFlag = LanguageType.NONE;
                    if (classify == AddressableClassify.Product)
                    {
                        langFlag = AddressableHelper.GetLanguageTypeByAssetPath(assetsRoot);
                        if (langFlag != LanguageType.NONE)
                        {
                            i18nName = langFlag.ToString().ToLower();
                        }
                    }
                    FileUtil.FindFiles(assetsRoot, files =>
                    {
                        foreach (var file in files)
                        {
                            var path = FileUtil.ToRelativePath(file);// file.Substring(file.IndexOf("Assets/", StringComparison.Ordinal));
                            var guid = AssetDatabase.AssetPathToGUID(path);
                            if (ContainsGUID(guid))
                            {
                                //Debug.Log($"GUID Repeat. Path:{path}");
                                if (langFlag != LanguageType.NONE || AddressableHelper.IsLodAssetPath(path))
                                { //多语言或者LOD资源
                                    RefreshAssetInfoByGUID(guid, classify);
                                }
                                continue;
                            }


                            string fileName;
                            //取备份信息
                            if (TryGetBackupAssetInfoByGUID(guid, out var backupInfo))
                            {
                                fileName = backupInfo.addressableName;
                            }
                            else
                            {
                                fileName = AddressableHelper.GetFileName(path);
                                if (langFlag != LanguageType.NONE)
                                {
                                    fileName = $"{i18nName}_{fileName}";
                                }
                            }
                            if (ContainsName(fileName))
                            {
                                //二次校验
                                TryGetAssetInfoByName(fileName, out var lastAssetInfo);
                                var lastPath = lastAssetInfo.GetAssetPath();
                                string temp = string.Empty;
                                if (string.IsNullOrEmpty(lastPath))
                                {
                                    Debug.LogError($"Two assets have the same name. But one of the files is missing. Last {lastAssetInfo}. Next Path:{path}");
                                }
                                else if (path.Equals(lastPath))
                                {
                                    Debug.LogError($"Two assets have the same path. But the GUID is different.Last {lastAssetInfo}. Next Path:{path}");
                                }
                                else
                                {
                                    var ext = Path.GetExtension(path);
                                    if (!string.IsNullOrEmpty(ext) && !ext.Equals(Path.GetExtension(lastPath)))
                                    {
                                        //后缀不一样
                                        temp = ($"{fileName}{ext.Replace('.', '_')}").ToLower();
                                        //if (langFlag != LangFlag.NONE)
                                        //{
                                        //    temp = $"{i18nName}_{temp}";
                                        //}
                                        if (ContainsName(temp))
                                        {
                                            temp = string.Empty;
                                        }
                                    }
                                }
                                if (string.IsNullOrEmpty(temp))
                                {
                                    temp = ($"{fileName}_{guid.Substring(0, 8)}").ToLower();
                                    //if (langFlag != LangFlag.NONE)
                                    //{
                                    //    temp = $"{i18nName}_{temp}";
                                    //}
                                    if (ContainsName(temp))
                                    {
                                        temp = ($"{fileName}_{guid}").ToLower();
                                        //if (langFlag != LangFlag.NONE)
                                        //{
                                        //    temp = $"{i18nName}_{temp}";
                                        //}
                                    }
                                }
                                fileName = temp;
                            }
                            //addressableId使用guid+path，预防相同路径的情况
                            var isInResources = AddressableHelper.IsInResources(path, out var relativePath);
                            //var assetType = isInResources ? AddressableAssetType.Resources : AddressableAssetType.Default;
                            var assetInfo = new AssetInfo()
                            {
                                addressableId = Crc32.GetCrc32($"{guid}+{path}"),
                                addressableName = fileName,
                                assetGUID = guid,
                                //assetType = assetType,
                                relativePath = relativePath,
                            };
                            if (AddAssetInfo(assetInfo))
                            {
                                Debug.Log($"guid:{guid} name:{fileName}  path:{path}");
                            }
                        }
                    });
                }
            }
        }
        private void Save()
        {
            for (int i = 0; i < queryOrder.Length; i++)
            {
                if (manifests.TryGetValue(queryOrder[i], out var manifest))
                {
                    manifest.Save();
                }
            }
            backupManifest.Save();
        }
        public bool TryGetAssetInfoByName(string addressableName, out AssetInfo assetInfo)
        {
            if (addressableNameMap.TryGetValue(addressableName, out var classify))
            {
                if (manifests[classify].TryGetAssetInfoByName(addressableName, out var tempAsset))
                {
                    assetInfo = tempAsset;
                    return true;
                }
            }
            assetInfo = default;
            return false;
        }

        public bool TryGetBackupAssetInfoByGUID(string guid, out AssetInfo assetInfo)
        {
            if (backupManifest.TryGetAssetInfoByGUID(guid, out var tempAsset))
            {
                assetInfo = tempAsset;
                return true;
            }
            assetInfo = default;
            return false;
        }
        private bool ContainsName(string addressableName)
        {
            if (addressableNameMap.ContainsKey(addressableName))
            {
                return true;
            }
            //for (int i = 0; i < queryOrder.Length; i++)
            //{
            //    if (manifests.TryGetValue(queryOrder[i], out var manifest))
            //    {
            //        if (manifest.ContainsName(addressableName))
            //        {
            //            return true;
            //        }
            //    }
            //}
            return false;
        }
        private bool ContainsGUID(string guid)
        {
            if (guidMap.ContainsKey(guid))
            {
                return true;
            }
            //for (int i = 0; i < queryOrder.Length; i++)
            //{
            //    if (manifests.TryGetValue(queryOrder[i], out var manifest))
            //    {
            //        if (manifest.ContainsGUID(guid))
            //        {
            //            return true;
            //        }
            //    }
            //}
            return false;
        }
        private void RefreshAssetInfoByGUID(string guid, AddressableClassify classify)
        {
            if (manifests.TryGetValue(classify, out var manifest))
            {
                manifest.RefreshAssetInfoByGUID(guid);
            }
        }
        private bool AddAssetInfo(AssetInfo assetInfo)
        {
            var assetPath = assetInfo.GetAssetPath();
            if (AddressableHelper.TryAssetPathToClassify(assetPath, out var classify))
            {
                if (manifests.TryGetValue(classify, out var manifest))
                {
                    if (manifest.AddAssetInfo(assetInfo))
                    {
                        AddAddressableName(assetInfo.addressableName, classify);
                        AddAddressableId(assetInfo.addressableId, classify);
                        AddAssetGUID(assetInfo.assetGUID, classify);
                        return true;
                    }
                }
            }
            return false;
        }

        private void LoadManifest()
        {
            for (int i = 0; i < queryOrder.Length; i++)
            {
                var classify = queryOrder[i];
                var manifest = CreateManifest(classify);
                if (manifest != null)
                    manifests.Add(classify, manifest);
            }

            backupManifest = CreateManifest(AddressableClassify.Backup);
        }
        private AddressableInfoManifest CreateManifest(AddressableClassify classify)
        {
            var manifest = AddressableHelper.LoadOrCreateManifest(classify);
            if (manifest != null)
            {
                var adapter = new AddressableInfoManifest(manifest, classify);
                return adapter;
            }
            return null;
        }
        private void DisposeInvalidAssets()
        {
            for (int i = 0; i < queryOrder.Length; i++)
            {
                if (manifests.TryGetValue(queryOrder[i], out var manifest))
                {
                    manifest.DisposeInvalidAssets(AddAssetInfo);
                }
            }
        }
        private void CollectAddressableAssets()
        {
            addressableNameMap.Clear();
            addressableIdMap.Clear();
            guidMap.Clear();

            for (int i = 0; i < queryOrder.Length; i++)
            {
                if (manifests.TryGetValue(queryOrder[i], out var manifest))
                {
                    manifest.CollectAddressableAssets(ref addressableNameMap, ref addressableIdMap, ref guidMap);
                }
            }
        }
        private void AddAddressableName(string addressableName, AddressableClassify classify)
        {
            if (addressableNameMap.ContainsKey(addressableName))
            {
                addressableNameMap[addressableName] = classify;
            }
            else
            {
                addressableNameMap.Add(addressableName, classify);
            }
        }
        private void AddAssetGUID(string guid, AddressableClassify classify)
        {
            if (guidMap.ContainsKey(guid))
            {
                guidMap[guid] = classify;
            }
            else
            {
                guidMap.Add(guid, classify);
            }
        }
        private void AddAddressableId(long id, AddressableClassify classify)
        {
            if (addressableIdMap.ContainsKey(id))
            {
                addressableIdMap[id] = classify;
            }
            else
            {
                addressableIdMap.Add(id, classify);
            }
        }


    }
}
