using XGame.Editor.Asset;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace XGame.Editor.Build.AssetBundles
{
    public class DepBundleCollector
    {
        private BundleContext _context;

        public DepBundleCollector(BundleContext context)
        {
            _context = context;
        }

        /// <summary>
        /// 收集ResStatic目录下被引用的资源
        /// </summary>
        /// <param name="assetBundleBuilds"></param>
        /// <param name="filePaths"></param>
        public void Collect()
        {
            //<assetPath, List<bundleName>>
            var refBundlesMap = new Dictionary<string, HashSet<long>>();
            foreach (var item in _context.bundleDataMap)
            {
                if (item.Value.isTextureBundle)
                {
                    continue;
                }
                var assetDependencies = _context.GetDependencies(item.Value.bundleId, item.Value.assetNames);
                foreach (var dependency in assetDependencies)
                {
                    if (_context.bundleAssetPaths.Contains(dependency) || Asset.FileUtil.IsFileIgnore(dependency))
                        continue;
                    if (dependency.Contains(_context.ResStaticDir))
                    {
                        if (dependency.Contains(_context.UiPrefabDir) && dependency.EndsWith(_context.PrefabExt, StringComparison.OrdinalIgnoreCase))
                        {
                            //忽略ResStatic下的UI预制
                            continue;
                        }
                    }
                    else if (dependency.StartsWith(PathDefine.PackageRelative, StringComparison.OrdinalIgnoreCase))
                    {
                        if (dependency.EndsWith(_context.PrefabExt, StringComparison.OrdinalIgnoreCase))
                        {
                            //忽略预制体文件
                            //Debug.LogWarning($"Bundle:{build.Value.bundleId} 依赖了Editor或者Resources资源. dependency:{dependency}");
                            continue;
                        }
                    }
                    else
                    {
                        //if (dependency.StartsWith(PathDefine.ResourcesRelative, StringComparison.OrdinalIgnoreCase))
                        //{
                        //    Debug.LogWarning($"Bundle:{build.Value.bundleId} 依赖了Resources资源. dependency:{dependency}");
                        //}
                        continue;
                    }
                    if (!refBundlesMap.TryGetValue(dependency, out var bundles))
                    {
                        bundles = new HashSet<long>();
                        refBundlesMap.Add(dependency, bundles);
                    }
                    if (!bundles.Contains(item.Value.bundleId))
                    {
                        bundles.Add(item.Value.bundleId);
                    }
                    //Debug.Log($"ResStatic dependency :{dependency} dir:{dir}");
                }
            }
            //<assetPath, bundleNames>
            var bundleNamesMap = new Dictionary<string, string>();
            foreach (var item in refBundlesMap)
            {
                //只被单个bundle引用的，不需要单独打包bundle
                if (item.Value.Count < 2) continue;
                var str = string.Join('_', item.Value);
                bundleNamesMap.Add(item.Key, str);
            }
            var groups = bundleNamesMap.GroupBy(p => p.Value);
            //由于AssetBundle的资源重名只认资源文件名，因此这里做好重名检测
            //用于排序,减少二次分包的次数
            var assetPaths = new List<string>();
            var fileNames = new HashSet<string>();
            foreach (var group in groups)
            {
                //先取出所有assetPath
                foreach (var item in group)
                {
                    assetPaths.Add(item.Key);
                }
                //排序
                assetPaths.Sort((a, b) => string.Compare(a, b, StringComparison.OrdinalIgnoreCase));
                //是否重名
                var isNameSake = false;
                foreach (var assetPath in assetPaths)
                {
                    var fileName = Path.GetFileName(assetPath);
                    if (!fileNames.Add(fileName))
                    {
                        //有重名
                        isNameSake = true;
                        break;
                    }
                }
                if (isNameSake)
                {
                    var depAssetsMap = AssetsGroupByDependencies(assetPaths);
                    //生成依赖包，bundleName由引用的BundleId拼接而成
                    var firstKey = "0";
                    var assets = depAssetsMap[firstKey];
                    var bundleBuild = _context.AddRawAssetBundle(assets, group.Key, true);
                    //var bundleBuild = new AssetBundleData(group.Key, KCDefine.BUNDLE_VARIANT, assets, assets);
                    //_context.bundleBuildMap.TryAdd(bundleBuild);
                    depAssetsMap.Remove(firstKey);
                    foreach (var item in depAssetsMap)
                    {
                        var bundleName = $"{bundleBuild.bundleId}_{item.Key}";
                        assets = item.Value;
                        _context.AddRawAssetBundle(assets, bundleName, true);
                        //var depBundle = new AssetBundleData(bundleName, KCDefine.BUNDLE_VARIANT, assets, assets);
                        //_context.bundleBuildMap.TryAdd(depBundle);
                    }
                }
                else
                {
                    //生成依赖包，bundleName由引用的BundleId拼接而成
                    var assets = assetPaths.ToArray();
                    _context.AddRawAssetBundle(assets, group.Key, true);
                    //var bundleBuild = new AssetBundleData(group.Key, KCDefine.BUNDLE_VARIANT, assets, assets);
                    //_context.bundleBuildMap.TryAdd(bundleBuild);
                }
                assetPaths.Clear();
                fileNames.Clear();
            }
        }
        /// <summary>
        /// Assets根据依赖关系二次分组
        /// 返回<groupId, assetPath[]>
        /// </summary>
        /// <param name="assetPaths"></param>
        /// <returns></returns>
        private Dictionary<string, string[]> AssetsGroupByDependencies(List<string> assetPaths)
        {
            var result = new Dictionary<string, string[]>();
            var assetDependencies = new Dictionary<string, string[]>();
            var dependencies = new List<string>();
            //先收集assetPaths之间的依赖信息
            foreach (var assetPath in assetPaths)
            {
                var deps = AssetDatabase.GetDependencies(assetPath, true);
                foreach (var dep in deps)
                {
                    if (!assetPath.Equals(dep) && assetPaths.Contains(dep))
                    {
                        dependencies.Add(dep);
                    }
                }
                assetDependencies.Add(assetPath, dependencies.ToArray());
                dependencies.Clear();
            }
            var assetGroupMap = new Dictionary<string, int>();
            var pendingPaths = new List<string>();
            foreach (var item in assetDependencies)
            {
                if (item.Value.Length > 0)
                {
                    pendingPaths.Add(item.Key);
                }
                else
                {
                    //没有依赖的资源，直接保存到assetGroupMap
                    assetGroupMap.Add(item.Key, 0);
                }
            }
            var groupId = 1;
            var tempPaths = new List<string>();
            var fileNames = new HashSet<string>();
            //递归查询
            while (pendingPaths.Count > 0)
            {
                foreach (var assetPath in pendingPaths)
                {
                    var isTrue = true;
                    foreach (var dep in assetDependencies[assetPath])
                    {
                        if (!assetGroupMap.ContainsKey(dep))
                        {
                            isTrue = false;
                            break;
                        }
                    }
                    if (isTrue)
                    {
                        //assetPath依赖的资源都有分组记录
                        tempPaths.Add(assetPath);
                    }
                }
                if (tempPaths.Count > 0)
                {
                    //新增分组
                    foreach (var assetPath in tempPaths)
                    {
                        pendingPaths.Remove(assetPath);
                        assetGroupMap.Add(assetPath, groupId);
                    }
                    groupId += 1;
                    tempPaths.Clear();
                }
                else
                {
                    //有互相依赖的资源，直接归为同一个分组，这里面可能有重名的资源
                    //由CheckAssetsNameRepeat方法统一报错处理
                    var isNameSake = false;
                    foreach (var assetPath in pendingPaths)
                    {
                        var fileName = Path.GetFileName(assetPath);
                        if (!fileNames.Add(fileName))
                        {
                            //有重名资源
                            isNameSake = true;
                            break;
                        }
                    }
                    if (isNameSake)
                    {
                        BuildLog.Error($"DepAssetbundle Group Error: 存在同名文件且Asset之间互相依赖。");
                        foreach (var assetPath in pendingPaths)
                        {
                            BuildLog.Error($"Error File:{assetPath}");
                        }
                    }
                    result.Add(groupId.ToString(), pendingPaths.ToArray());
                    pendingPaths.Clear();
                    fileNames.Clear();
                }
            }
            var groups = assetGroupMap.GroupBy(item => item.Value);
            foreach (var group in groups)
            {
                foreach (var item in group)
                {
                    var assetPath = item.Key;
                    var fileName = Path.GetFileName(assetPath);
                    if (fileNames.Add(fileName))
                    {
                        tempPaths.Add(assetPath);
                    }
                    else
                    {
                        //有同名文件，该文件直接单独打包
                        var guid = AssetDatabase.AssetPathToGUID(assetPath);
                        result.Add($"{item.Value}_{guid}", new string[] { assetPath });
                    }
                }
                if (tempPaths.Count > 0)
                {
                    result.Add(group.Key.ToString(), tempPaths.ToArray());
                }
                else
                {
                    BuildLog.Error($"DepAssetbundle Group Error: GroupId:{group.Key} Count:{group.Count()} 分组数据为空。");
                }
                tempPaths.Clear();
                fileNames.Clear();
            }
            return result;
        }
    }
}
