using System;
using System.Collections.Generic;
using System.IO;
using Fort23.Core;
using Fort23.Mono;
using Fort23.UTool;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI.PackgTool;
using Utility;

namespace Fort23.Editor
{
    public class AssetBundleEditor
    {
        private static readonly string buildConfigPath = "Assets/Bundles/BuildConfig.prefab";
        private static readonly string assetConfigName = "assetConfig.txt";

        private static readonly Dictionary<Material, int> _allMaterial = new();
        private static readonly Dictionary<Shader, int> _allShader = new();
        private static readonly Dictionary<Texture, int> _allTexture = new();
        private static readonly string[] _ignoreExtensionName = { ".meta", ".tpsheet" };

        private static AllPackedAssetsInfo allPackedAssetsInfo;

        private static Dictionary<string, AssetInfo> allAssset = new Dictionary<string, AssetInfo>();

        private static bool IsEditor;

        [MenuItem("AssetBundles/标记资源")]
        public static void BuildAllBundle()
        {
            BuildAllBundle(EditorUserBuildSettings.activeBuildTarget, true);
        }

        public static void BuildAllBundle(BuildTarget target, bool isEditor = false)
        {
            IsEditor = isEditor;
            List<string> notSceneAssets = new List<string>();
            // string hotfixDllSrcDir = BuildConfig.GetHotFixDllsOutputDirByTarget(target);
            // string tempDir = BuildConfig.GetAssetBundleTempDirByTarget(target);
            // if (!System.IO.Directory.Exists(tempDir))
            // {
            //     Directory.CreateDirectory(tempDir);
            // }
            //
            // foreach (var dll in BuildConfig.HotUpdateAssemblies)
            // {
            //     string dllPath = $"{hotfixDllSrcDir}/{dll}";
            //     string dllBytesPath = $"{tempDir}/{dll}.bytes";
            //     File.Copy(dllPath, dllBytesPath, true);
            //     notSceneAssets.Add(dllBytesPath);
            // }

            // AssetDatabase.SaveAssets();
            // AssetDatabase.Refresh();

            allPackedAssetsInfo = new AllPackedAssetsInfo();
            allPackedAssetsInfo.assetsList = new List<AssetInfo>();
            allAssset.Clear();
            // UnMarkAllAssets();
            _allMaterial.Clear();
            _allShader.Clear();
            _allTexture.Clear();
            var config = AssetDatabase.LoadAssetAtPath<GameObject>(buildConfigPath);
            foreach (var referenceCollectorData in config.GetComponent<ReferenceCollector>().data)
            {
                // 如果是文件夹，则把文件夹下面所有文件单独MarkAssetToBundle
                // 如果不是文件夹，则表示一个assetBundle, 直接用key当gameObject的assetBundleName

                if (referenceCollectorData.gameObject is TextAsset)
                {
                    MarkAssetToBundle(referenceCollectorData.gameObject as TextAsset);
                }
                else
                {
                    MarkAssetToBundle(referenceCollectorData);
                }
            }


            foreach (var material in _allMaterial.Keys)
            {
                Shader shader = material.shader;
                MarkAssetToBundle(AssetDatabase.GetAssetPath(shader), "fb010shader");
                if (_allMaterial[material] > 1)
                {
                    MarkAssetToBundle(AssetDatabase.GetAssetPath(material), material.name);
                }
            }

            for (int i = 0; i < notSceneAssets.Count; i++)
            {
                MarkAssetToBundle(notSceneAssets[i], "codedata");
            }

            var count = 0;
            foreach (var texture in _allTexture.Keys)
                if (_allTexture[texture] > 1)
                {
                    count++;
                    MarkAssetToBundle(AssetDatabase.GetAssetPath(texture), texture.name + "_t" + count, true);
                }

            // var gameRuntimeConfig = Resources.Load<GameRuntimeConfig>("GameRuntimeConfig");
            var fold = string.Format(BuildEditor.buildFolder, BuildEditor.GetPlatformType(),
                $"{1}.{1}.{1}");
            var assetConfigPath = fold + assetConfigName;
            if (!Directory.Exists(fold)) Directory.CreateDirectory(fold + "/");

            var assetBundleConfigPath = Path.Combine(PathHelper.AppResPath, "assetConfig.txt");
            var assetJsonData = JsonUtility.ToJson(allPackedAssetsInfo);
            Debug.Log(assetBundleConfigPath);
            File.WriteAllText(assetBundleConfigPath, assetJsonData);

            File.WriteAllText(assetConfigPath, assetJsonData);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            LogTool.Log("所有资源标记完成！");
        }

        private static void MarkAssetToBundle(TextAsset textAsset)
        {
            string data = textAsset.text;
            TextrueJson textrueJson = JsonUtility.FromJson<TextrueJson>(data);
            if (textrueJson != null)
            {
                for (int i = 0; i < textrueJson.newTextureJson.Count; i++)
                {
                    NewTextrueJson newTextrueJson = textrueJson.newTextureJson[i];
                    string path = "Assets/Art/UIAssets" + newTextrueJson.filePath;
                    // TextureImporter importer =  (TextureImporter) TextureImporter.GetAtPath(path);
                    // importer.spriteImportMode = SpriteImportMode.Single;
                    // importer.assetBundleName = "";
                    // AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
                    // AssetDatabase.Refresh();
                    MarkAssetToBundle(path, newTextrueJson.textrueName);
                }
            }
        }

        private static void MarkAssetToBundle(ReferenceCollectorData referenceCollectorData)
        {
            var path = AssetDatabase.GetAssetPath(referenceCollectorData.gameObject);
            if (Directory.Exists(path))
            {
                if (referenceCollectorData.isAssetBundle)
                {
                    MarkAssetToBundle(path, referenceCollectorData.key);
                }
                else
                {
                    var direction = new DirectoryInfo(path);
                    var files = direction.GetFiles("*", SearchOption.AllDirectories);
                    for (var i = 0; i < files.Length; i++)
                    {
                        if (Ignore(files[i].Name)) continue;

                        MarkAssetToBundle(files[i].FullName, files[i].Name);
                        // var assetPath = files[i].FullName.Substring(files[i].FullName.IndexOf("Asset"));
                        // var importer = AssetImporter.GetAtPath(assetPath);
                        // if (importer == null) continue;
                        //
                        // importer.assetBundleName = ValidBundleName(files[i].Name);
                        // var assetInfo = new AssetInfo();
                        // assetInfo.bundle = importer.assetBundleName;
                        // assetInfo.name = Path.GetFileName(Application.dataPath + "/" + assetPath);
                        // allPackedAssetsInfo.assetsList.Add(assetInfo);
                    }
                }
            }
            else
            {
                try
                {
                    MarkAssetToBundle(path, referenceCollectorData.key);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            }
        }


        private static void MarkAssetToBundle(string fullPath, string name, bool isTextrue = false)
        {
            fullPath = fullPath.Replace("\\", "/");
            var assetPath = fullPath.Replace(Application.dataPath, "Assets");
            // Debug.Log(assetPath);
            var importer = AssetImporter.GetAtPath(assetPath);
            if (importer != null)
            {
                string fileName = Path.GetFileName(Application.dataPath + "/" + assetPath);
                if (allAssset.ContainsKey(fileName))
                {
                    return;
                }

                string bundelName = ValidBundleName(name);
                if (!IsEditor)
                {
                    if (!isTextrue)
                    {
                        var go = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
                        if (go != null) MaterialSetting(go);

                        var material = AssetDatabase.LoadAssetAtPath<Material>(assetPath);

                        if (material != null) MaterialSetting(material);
                    }

                    importer.assetBundleName = bundelName;
                }

                var assetInfo = new AssetInfo();
                assetInfo.bundle = bundelName;
                assetInfo.name = fileName;
                assetInfo.localPath = assetPath;
                // if (allAssset.ContainsKey(assetInfo.name))
                // {
                //     throw new Exception(
                //         $"重复的资源名:{assetInfo.name}_path___ {assetPath} 和  {allAssset[assetInfo.name].localPath}");
                // }

                allAssset.Add(assetInfo.name, assetInfo);
                allPackedAssetsInfo.assetsList.Add(assetInfo);
            }
        }

        private static string ValidBundleName(string bundleName)
        {
            if (bundleName.Contains(".")) bundleName = bundleName.Split('.')[0];

            if (bundleName.Contains(" ")) bundleName = bundleName.Replace(" ", "_");
            if (bundleName.Contains("%")) bundleName = bundleName.Replace("%", "_bfh");

            return bundleName.ToLower();
        }

        private static bool Ignore(string bundleName)
        {
            foreach (var extensionName in _ignoreExtensionName)
                if (bundleName.EndsWith(extensionName))
                    return true;

            return false;
        }

        // [MenuItem("AssetBundles/库", priority = -100)]
        [MenuItem("AssetBundles/删除标记(慎点)", priority = -101)]
        private static void UnMarkAllAssets()
        {
            var bundleNames = AssetDatabase.GetAllAssetBundleNames();
            for (var i = 0; i < bundleNames.Length; i++)
            {
                string[] allPath = AssetDatabase.GetAssetPathsFromAssetBundle(bundleNames[i]);
                for (int j = 0; j < allPath.Length; j++)
                {
                    var importer = AssetImporter.GetAtPath(allPath[j]);
                    importer.assetBundleName = null;
                }

                AssetDatabase.RemoveAssetBundleName(bundleNames[i], true);
            }

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            LogTool.Log("删除所有资源标记完成！");
        }

        private static void MaterialSetting(GameObject go)
        {
            if (IsEditor)
            {
                return;
            }

            var renderer = go.GetComponentsInChildren<Renderer>(true);
            var isAlater = false;
            if (renderer != null)
                for (var i = 0; i < renderer.Length; i++)
                {
                    var isRendAlater = false;
                    var sharedMaterials = renderer[i].sharedMaterials;

                    if (sharedMaterials != null)
                        for (var j = 0; j < sharedMaterials.Length; j++)
                        {
                            var material = sharedMaterials[j];
                            if (material != null)
                            {
                                if (AssetDatabase.GetAssetPath(material).Contains("builtin"))
                                {
                                    if ("Default-ParticleSystem" == material.name ||
                                        "Default-Particle" == material.name || "Default-Material" == material.name)
                                    {
                                        isRendAlater = true;
                                        isAlater = true;
                                        sharedMaterials[j] = null;
                                        continue;
                                    }

                                    if ("Sprites-Default" == material.name)
                                    {
                                        // TODO 需要修改
                                        var sd = AssetDatabase.LoadAssetAtPath<Material>(
                                            @"Assets\RawBundles\Mat\Sprites-Default.mat");
                                        sharedMaterials[j] = sd;
                                    }
                                }

                                if (_allMaterial.ContainsKey(material))
                                    _allMaterial[material]++;
                                else
                                    _allMaterial.Add(material, 1);
                            }
                        }

                    if (isRendAlater) renderer[i].sharedMaterials = sharedMaterials;
                }

            if (isAlater) EditorUtility.SetDirty(go);
        }

        private static void MaterialSetting(Material material)
        {
            if (IsEditor)
            {
                return;
            }

            if (material != null)
            {
                var shader = material.shader;
                for (var i = 0; i < ShaderUtil.GetPropertyCount(shader); i++)
                    if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.TexEnv)
                    {
                        var propertyname = ShaderUtil.GetPropertyName(shader, i);
                        var texture = material.GetTexture(propertyname);
                        if (texture != null)
                        {
                            if (_allTexture.ContainsKey(texture))
                                _allTexture[texture]++;
                            else
                                _allTexture.Add(texture, 1);
                        }
                    }

                if (_allShader.ContainsKey(shader))
                    _allShader[shader]++;
                else
                    _allShader.Add(shader, 1);
            }
        }
    }
}