using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

namespace SFramework.Editor
{
    public static class SAssetsBundleHelper
    {
        static string ResourcesBuildDir
        {
            get
            {
                var dir = "Assets/" + SFrameworkDef.ResourceDir + "/";
                return dir;
            }
        }

        /// <summary>
        /// Unity 5新AssetBundle系统，需要为打包的AssetBundle配置名称
        /// 
        /// 直接将KEngine配置的BundleResources目录整个自动配置名称，因为这个目录本来就是整个导出
        /// </summary>
        [MenuItem("SFramework/AssetBundle/Auto Set Names To [BundleResources]")]
        public static void AutoSetAssetBundleNames()
        {
            var dir = ResourcesBuildDir;

            // Check marked asset bundle whether real
            foreach (var assetGuid in AssetDatabase.FindAssets(""))
            {
                var assetPath = AssetDatabase.GUIDToAssetPath(assetGuid);
                var assetImporter = AssetImporter.GetAtPath(assetPath);
                var bundleName = assetImporter.assetBundleName;
                if (string.IsNullOrEmpty(bundleName))
                {
                    continue;
                }
                if (!assetPath.StartsWith(dir))
                {
                    assetImporter.assetBundleName = null;
                }
            }

            // set BundleResources's all bundle name
            foreach (var filepath in System.IO.Directory.GetFiles(dir, "*.*", System.IO.SearchOption.AllDirectories))
            {
                if (filepath.EndsWith(".meta")) continue;

                var importer = AssetImporter.GetAtPath(filepath);
                if (importer == null)
                {
                    Debug.LogError(string.Format("Not found: {0}", filepath));
                    continue;
                }
                var bundleName = filepath.Substring(dir.Length, filepath.Length - dir.Length);
                importer.assetBundleName = bundleName + SFrameworkDef.AssetsBundleExtName;
            }
            Debug.Log("Make all asset name success!");
        }

        /// <summary>
        /// 清理冗余，即无此资源，却存在AssetBundle的文件, Unity 5 only
        /// </summary>
        [MenuItem("SFramework/AssetBundle/Clean Redundancies")]
        public static void CleanAssetBundlesRedundancies()
        {
            var platformName = SPlatformInfo.GetBuildPlatformName();
            var outputPath = GetExportPath(EditorUserBuildSettings.activeBuildTarget);
            var srcList = new List<string>(System.IO.Directory.GetFiles(ResourcesBuildDir, "*.*", System.IO.SearchOption.AllDirectories));
            for (var i = srcList.Count - 1; i >= 0; i--)
            {
                if (srcList[i].EndsWith(".meta"))
                    srcList.RemoveAt(i);
                else
                    srcList[i] = srcList[i].Replace(ResourcesBuildDir, "").ToLower();
            }

            var toListMap = new Dictionary<string, string>();
            var toList = new List<string>(System.IO.Directory.GetFiles(outputPath, "*.*", System.IO.SearchOption.AllDirectories));
            for (var i = toList.Count - 1; i >= 0; i--)
            {
                var filePath = toList[i];

                if (toList[i].EndsWith((".meta")) || toList[i].EndsWith(".manifest"))
                {
                    toList.RemoveAt(i);
                }
                else
                {
                    var rName = toList[i].Replace(outputPath, "");
                    if (rName == platformName || // 排除AB 平台总索引文件,
                        rName == (platformName + ".manifest") ||
                        rName == (platformName + ".meta") ||
                        rName == (platformName + ".manifest.meta"))
                    {
                        toList.RemoveAt(i);
                    }
                    else
                    {
                        // 去掉扩展名，因为AssetBundle额外扩展名
                        toList[i] = System.IO.Path.ChangeExtension(rName, "");// 会留下最后句点
                        toList[i] = toList[i].Substring(0, toList[i].Length - 1); // 去掉句点

                        toListMap[toList[i]] = filePath;
                    }
                }
            }

            // 删文件和manifest
            for (var i = 0; i < toList.Count; i++)
            {
                if (!srcList.Contains(toList[i]))
                {
                    var filePath = toListMap[toList[i]];
                    var manifestPath = filePath + ".manifest";
                    System.IO.File.Delete(filePath);
                    Debug.LogWarning("Delete... " + filePath);
                    if (System.IO.File.Exists(manifestPath))
                    {
                        System.IO.File.Delete(manifestPath);
                        Debug.LogWarning("Delete... " + manifestPath);
                    }


                }
            }
        }

        [MenuItem("SFramework/AssetBundle/Create Version File")]
        public static void CreateVersionFile()
        {
            AssetBundle.UnloadAllAssetBundles(true);

            var platformName = SPlatformInfo.GetBuildPlatformName();
            var outputPath = GetExportPath(EditorUserBuildSettings.activeBuildTarget);
            Debug.Log(string.Format("CreateVersionFile -> platformName:{0} outputPath:{1}", platformName, outputPath));

            // Load manifestAB
            string manifestABPath = Application.dataPath + "/../Product/Bundles/" + platformName + "/" + platformName;
            Debug.Log("manifestABPath -> " + manifestABPath);

            byte[] byManifest = System.IO.File.ReadAllBytes(manifestABPath);
            AssetBundle manifestAB = AssetBundle.LoadFromMemory(byManifest);
            if (manifestAB == null)
            {
                Debug.LogError("CreateVersionFile -> Get ManifestAB Failed. Path:" + manifestABPath);
                return;
            }
            AssetBundleManifest manifest = manifestAB.LoadAsset("AssetBundleManifest") as AssetBundleManifest;
            if (manifest == null)
            {
                Debug.LogError("CreateVersionFile -> Get Manifest From AssetBundle Failed.");
                return;
            }

            SVersionInfo curVersionInfo = new SVersionInfo();
            curVersionInfo.version = 0;
            curVersionInfo.fileInfo = new List<SFileInfo>();
            // Add Manifest File
            string manifestFileName   = platformName;
            SFileInfo manifestFileInfo = SToolFunction.CreateFileInfo(manifestFileName, outputPath + manifestFileName);
            curVersionInfo.fileInfo.Add(manifestFileInfo);

            // Add Manifest Ext File(platform.manifest)
            string manifestExtFileName      = platformName + ".manifest";
            SFileInfo manifestExtFileInfo = SToolFunction.CreateFileInfo(manifestExtFileName, outputPath + manifestExtFileName);
            curVersionInfo.fileInfo.Add(manifestExtFileInfo);

            // Add files in manifest.
            string[] allABName = manifest.GetAllAssetBundles();
            curVersionInfo.fileCount = allABName.Length;
            foreach (string abName in allABName)
            {
                string oneABFullPathWithName = outputPath + abName;
                SFileInfo curFileInfo = SToolFunction.CreateFileInfo(abName, oneABFullPathWithName);
                curFileInfo.hashInfo = manifest.GetAssetBundleHash(abName).ToString();

                curVersionInfo.fileInfo.Add(curFileInfo);
                // Debug.Log(string.Format("oneAB:{0} Size:{1}", abName, oneABFileInfo.Length));

                Debug.Log(string.Format("abName: {0} FileSize:{1} HashCode: {2}", 
                    curFileInfo.fileName, curFileInfo.fileSize, curFileInfo.hashInfo));
            }
            string jsonString = LitJson.JsonMapper.ToJson(curVersionInfo);
            Debug.Log("jsonString -> " + jsonString);

            string jsonPath = Application.dataPath + "/../Product/Bundles/" + platformName + "/" + SFrameworkDef.VersionFileName;
            System.IO.StreamWriter build_info = new System.IO.StreamWriter(jsonPath);
            build_info.Write(jsonString);
            build_info.Close();
            build_info.Dispose();

            manifestAB.Unload(true);
            Debug.Log("CreateVersionFile Success!");
        }

        //[MenuItem("SFramework/AssetBundle/Build All to All Platforms")]
        //public static void BuildAllAssetBundlesToAllPlatforms()
        //{
        //    var platforms = new List<BuildTarget>()
        //    {
        //        BuildTarget.iOS,
        //        BuildTarget.Android,
        //        BuildTarget.StandaloneWindows,
        //        BuildTarget.StandaloneOSX,
        //    };

        //    // Build all support platforms asset bundle
        //    var currentBuildTarget = EditorUserBuildSettings.activeBuildTarget;
        //    platforms.Remove(currentBuildTarget);
        //    BuildAllAssetBundles();

        //    foreach (var platform in platforms)
        //    {
        //        if (EditorUserBuildSettings.SwitchActiveBuildTarget(platform))
        //            BuildAllAssetBundles();
        //    }

        //    // revert platform 
        //    EditorUserBuildSettings.SwitchActiveBuildTarget(currentBuildTarget);
        //}

        [MenuItem("SFramework/AssetBundle/ReBuild All")]
        public static void ReBuildAllAssetBundles()
        {
            var outputPath = GetExportPath(EditorUserBuildSettings.activeBuildTarget);
            System.IO.Directory.Delete(outputPath, true);

            Debug.Log("Delete folder: " + outputPath);

            BuildAllAssetBundles();
        }

        [MenuItem("SFramework/AssetBundle/Build All %&b")]
        public static void BuildAllAssetBundles()
        {
            if (EditorApplication.isPlaying)
            {
                Debug.LogError("Cannot build in playing mode! Please stop!");
                return;
            }
            AutoSetAssetBundleNames();
            var outputPath = GetExportPath(EditorUserBuildSettings.activeBuildTarget);
            Debug.Log(string.Format("Asset bundle start build to: {0}", outputPath));
            BuildPipeline.BuildAssetBundles(outputPath, BuildAssetBundleOptions.DeterministicAssetBundle, EditorUserBuildSettings.activeBuildTarget);
            //BuildPipeline.BuildAssetBundles(outputPath, BuildAssetBundleOptions.DeterministicAssetBundle | BuildAssetBundleOptions.AppendHashToAssetBundleName, EditorUserBuildSettings.activeBuildTarget);
            CreateVersionFile();
        }

        /// <summary>
        /// Extra Flag ->   ex:  Android/  AndroidSD/  AndroidHD/
        /// </summary>
        /// <param name="platfrom"></param>
        /// <returns></returns>
        public static string GetExportPath(BuildTarget platfrom)
        {
            //string basePath =
            //    System.IO.Path.GetFullPath(KEngine.AppEngine.GetConfig(KEngineDefaultConfigs.AssetBundleBuildRelPath));
            string basePath = SFrameworkDef.AssetsBundleProductDir;

            if (System.IO.File.Exists(basePath))
            {
                SAssetsBundleHelper.ShowDialog("路径配置错误: " + basePath);
                throw new System.Exception("路径配置错误");
            }
            if (!System.IO.Directory.Exists(basePath))
            {
                System.IO.Directory.CreateDirectory(basePath);
            }

            string path = null;
            var platformName = SPlatformInfo.GetBuildPlatformName();

            path = basePath + "/" + platformName + "/";
            if (!System.IO.Directory.Exists(path))
            {
                System.IO.Directory.CreateDirectory(path);
            }
            return path;
        }

        public static void ClearConsole()
        {
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(SceneView));
            System.Type type = assembly.GetType("UnityEditorInternal.LogEntries");
            System.Reflection.MethodInfo method = type.GetMethod("Clear");
            method.Invoke(null, null);
        }

        public static bool ShowDialog(string msg, string title = "提示", string button = "确定")
        {
            return EditorUtility.DisplayDialog(title, msg, button);
        }

        public static void ShowDialogSelection(string msg, System.Action yesCallback)
        {
            if (EditorUtility.DisplayDialog("确定吗", msg, "是!", "不！"))
            {
                yesCallback();
            }
        }
    }

}
