using XGame.Framework.Asset;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System.Linq;
using System.Text.RegularExpressions;
using System;
using System.IO;
using XGame.Framework.Asset.Addressable.Data;
using XGame.Editor.Asset;
using XGame.Editor.Build.AssetBundles;

namespace XGame.Editor.Build
{
    /// <summary>
    /// 该类主要是给提供给编辑器快速查询Addressable/Assetbundle信息用
    /// 使用前必须保证AssetbundleMainfest已经存在
    /// 该类实例会产生大量的缓存数据，注意释放问题
    /// </summary>
    public class ProductAssetsContext: IDisposable
    {
        private Dictionary<string, AssetInfo> _addressableAssetMap;
        private Dictionary<string, string> _addressableToGuidMap;

        #region Assetbundle
        private Dictionary<string, AssetBundleBackupInfo> _abBackupInfoMap;
        private Dictionary<uint, string> _bundleIdToNameMap;
        private Dictionary<string, string> _assetNameToBundleNameMap;
        private Dictionary<string, string[]> _abDependenciesMap;
        private Dictionary<string, HashSet<string>> _bundleReferencesMap;
        #endregion

        /// <summary>
        /// 海报资源的标签
        /// </summary>
        public static readonly string PlacardTag = "/placard/";
        /// <summary>
        /// 内置资源的标签
        /// </summary>
        public string[] InnerAssetsTags = new string[] { "/XGame/", "/launch/", PlacardTag };

        private IAssetsCustomHandler _customHandler;

        private bool IsOnlySplitCustomPackageBundles => _customHandler?.IsOnlySplitCustomPackageBundles ?? false;

        public bool Init()
        {
            var addressableManifest = AddressableHelper.LoadAssetManifest();
            if (addressableManifest == null)
            {
                Debug.LogError($"找不到 AddressableAssetInfoManifest.");
                return false;
            }
            _addressableAssetMap = addressableManifest.GetAssetInfoMapWithGUID();
            _addressableToGuidMap = new Dictionary<string, string>();
            foreach (var keyValue in _addressableAssetMap)
            {
                _addressableToGuidMap.Add(keyValue.Value.addressableName, keyValue.Key);
            }
            if (!InitAssetBundles())
            {
                return false;
            }
            InitCustomHandler();
            return true;
        }
        private bool InitAssetBundles()
        {
            var abManifest = AssetBundleBackupManifest.Load();
            if (abManifest == null || abManifest.bundleInfos == null || abManifest.bundleInfos.Length == 0)
                return false;
            _abBackupInfoMap = new Dictionary<string, AssetBundleBackupInfo>();
            _bundleIdToNameMap = new Dictionary<uint, string>();
            _assetNameToBundleNameMap = new Dictionary<string, string>();
            _abDependenciesMap = new Dictionary<string, string[]>();
            _bundleReferencesMap = new Dictionary<string, HashSet<string>>();
            foreach (var item in abManifest.bundleInfos)
            {
                var bundleName = item.FullName;
                var bundleId = item.bundleId;
                _abBackupInfoMap.Add(bundleName, item);
                _bundleIdToNameMap.Add(bundleId, bundleName);
                foreach(var asset in item.assets)
                {
                    _assetNameToBundleNameMap.Add(asset, bundleName);
                }
            }
            return true;
        }
        private void InitCustomHandler()
        {
            var handlerType = typeof(IAssetsCustomHandler);
            var assembly = System.Reflection.Assembly.GetAssembly(handlerType);
            var handlerImplType = Array.Find(assembly.GetTypes(), type => type != handlerType && handlerType.IsAssignableFrom(type));
            //var editorName = "XGame.Editor";
            //var handlerImplType = AppDomain.CurrentDomain.GetAssemblies()
            //    .First(assembly => assembly.GetName().Name.Equals(editorName))
            //    .GetTypes().First(type => type != handlerType && handlerType.IsAssignableFrom(type));
            if (handlerImplType != null)
            {
                _customHandler = Activator.CreateInstance(handlerImplType) as IAssetsCustomHandler;
                Debug.Log($"AssetsControl: IAssetsCustomHandler {handlerImplType.FullName} if1");
            }
            else
            {
                var assemblies = AppDomain.CurrentDomain.GetAssemblies();
                foreach (var variable in assemblies)
                {
                    // 仅扫描Editor关键字的程序集
                    if (!variable.FullName.Contains("Editor"))
                    {
                        continue;
                    }

                    handlerImplType = Array.Find(variable.GetTypes(), type => type != handlerType && handlerType.IsAssignableFrom(type));
                    if (handlerImplType != null)
                    {
                        _customHandler = Activator.CreateInstance(handlerImplType) as IAssetsCustomHandler;
                        Debug.Log($"AssetsControl: IAssetsCustomHandler {handlerImplType.FullName} if2");
                        return;
                    }
                }
                Debug.Log("没有找到 IAssetsCustomHandler 的实现类。");
            }
        }

        public string GuidToAddressableName(string guid)
        {
            if (_addressableAssetMap.ContainsKey(guid))
            {
                return _addressableAssetMap[guid].addressableName;
            }
            return string.Empty;
        }
        public string AddressableNameToGuid(string addressableName)
        {
            _addressableToGuidMap.TryGetValue(addressableName, out var guid);
            return guid;
        }
        public string AddressableToBundleName(string addressableName)
        {
            _assetNameToBundleNameMap.TryGetValue(addressableName, out var bundleName);
            return bundleName;
        }

        public HashSet<string> GetBundleReferences(string bundleName)
        {
            if (_bundleReferencesMap.TryGetValue(bundleName, out var references))
            {
                return references;
            }
            references = new HashSet<string>();
            if (!_abBackupInfoMap.TryGetValue(bundleName, out var bundle))
            {
                return references;
            }
            var bundleId = bundle.bundleId;
            foreach(var item in _abBackupInfoMap)
            {
                var bundleInfo = item.Value;
                if (bundleInfo.bundleId == bundleId)
                {
                    continue;
                }
                if (bundleInfo.DependenciesCount > 0)
                {
                    foreach(var depId in bundleInfo.dependencies)
                    {
                        if (depId == bundleId)
                        {
                            references.Add(item.Key);
                            break;
                        }
                    }
                }
            }
            _bundleReferencesMap.Add(bundleName, references);
            return references;
        }
        /// <summary>
        /// 收集海报的bundle
        /// </summary>
        /// <returns></returns>
        public HashSet<string> CollectPlacardBundles()
        {
            return CollectInnerBundles(true);
        }
        /// <summary>
        /// 收集所有内置的AssetBundle信息
        /// </summary>
        /// <param name="customPackageBundles"></param>
        /// <returns></returns>
        public HashSet<string> CollectInnerBundles(HashSet<string> customPackageBundles = null)
        {
            return CollectInnerBundles(false, customPackageBundles);
        }
        public string[] GetDependenciesByBundleName(string assetBundleName)
        {
            if (string.IsNullOrEmpty(assetBundleName))
            {
                return null;
            }
            if (_abDependenciesMap.TryGetValue(assetBundleName, out string[] dependencies))
            {
                return dependencies;
            }
            if (_abBackupInfoMap.TryGetValue(assetBundleName, out var bundleInfo))
            {
                int count = bundleInfo.DependenciesCount;
                if (count > 0)
                {
                    dependencies = new string[count];
                    for (var index = 0; index < count; index++)
                    {
                        var depId = bundleInfo.dependencies[index];
                        dependencies[index] = _bundleIdToNameMap[depId];
                    }
                }
                _abDependenciesMap.Add(assetBundleName, dependencies);
            }
            return dependencies;
        }
        /// <summary>
        /// 收集所有内置的AssetBundle信息
        /// </summary>
        /// <param name="isPlacard">是否只收集海报资源</param>
        /// <param name="customPackageBundles">分包资源的bundleFullName列表</param>
        /// <returns></returns>
        private HashSet<string> CollectInnerBundles(bool isPlacard, HashSet<string> customPackageBundles = null)
        {
            //ResStatic下的依赖包至少会被两个AB包依赖
            //Regex rawBundleReg = new Regex(@"(^\d+)_(\d+)");
            var names = new HashSet<string>();
            //manifest
            names.Add(Define.MANIFEST_BUNDLE_FULLNAME);
            //识别所有bundle是否是内置资源
            
            foreach (var item in _abBackupInfoMap)
            {
                var bundle = item.Value;
                var fullName = item.Key;
                if (!names.Contains(fullName))
                {
                    var isInner = false;
                    if (bundle.bundleType == AssetBundleType.Dependency)
                    { // 是ResStatic下的依赖包
                        foreach (var assetPath in bundle.assets)
                        {
                            if (IsInnerAsset(assetPath, isPlacard))
                            {
                                isInner = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        // 只分离分包资源且该ab不在分包的Assetbunle列表，则该ab保留在包内
                        isInner = isPlacard == false && IsOnlySplitCustomPackageBundles &&
                            customPackageBundles != null && customPackageBundles.Contains(fullName) == false;
                        if (!isInner)
                        {
                            string assetPath;
                            if (_addressableToGuidMap.TryGetValue(bundle.assets[0], out var assetGuid))
                            {
                                assetPath = AssetDatabase.GUIDToAssetPath(assetGuid);
                            }
                            else
                            { // ResStatic的图集资源
                                assetPath = bundle.assets[0];
                            }
                            //其它内置资源，通过文件夹标签识别
                            if (IsInnerAsset(assetPath, isPlacard))
                            {
                                isInner = true;
                            }
                        }
                    }
                    if (isInner)
                    {
                        names.Add(fullName);
                        Debug.Log($"Inner Bundle:{bundle.nameOrGuid} Name:{fullName}");
                        if (bundle.DependenciesCount > 0)
                        {
                            names.UnionWith(GetDependenciesByBundleName(fullName));
                        }
                    }
                }
            }
            var paths = names.ToArray();
            var bundleOutputPath = PathDefine.AssetBundleOutputPath;
            var result = new HashSet<string>();
            for (int i = 0; i < paths.Length; i++)
            {
                result.Add(Path.Combine(bundleOutputPath, paths[i]).Replace("\\", "/"));
            }
            return result;
        }
        /// <summary>
        /// 判断一个资源是否是内置资源
        /// </summary>
        /// <param name="path"></param>
        /// <param name="isPlacard"></param>
        /// <returns></returns>
        private bool IsInnerAsset(string path, bool isPlacard)
        {
            var lowerPath = path.ToLower();
            if (isPlacard)
            {
                return lowerPath.Contains(PlacardTag);
            }
            var innerAssetsTags = InnerAssetsTags;
            foreach (var tag in innerAssetsTags)
            {
                if (lowerPath.Contains(tag))
                {
                    return true;
                }
            }
            return _customHandler != null && _customHandler.IsInnerAsset(path);
        }

        void IDisposable.Dispose()
        {
            _addressableAssetMap?.Clear();
            _addressableAssetMap = null;
            _abBackupInfoMap?.Clear();
            _bundleIdToNameMap?.Clear();
            _assetNameToBundleNameMap?.Clear();
            _abDependenciesMap?.Clear();
        }
    }

}
