using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using LitJson;
using System.Text.RegularExpressions;

public class BuildUtils
{
    /// <summary>
    /// 递归遍历获取目标目录中的所有文件
    /// </summary>
    /// <param name="sourceDir">目标目录</param>
    /// <param name="splitAssetPath">是否要切割目录，以assets目录为根</param>
    /// <returns></returns>
    public static List<string> GetFiles(string sourceDir, bool splitAssetPath)
    {
        List<string> fileList = new List<string>();
        string[] fs = Directory.GetFiles(sourceDir);
        string[] ds = Directory.GetDirectories(sourceDir);
        for (int i = 0; i < fs.Length; i++)
        {
            var index = splitAssetPath ? fs[i].IndexOf("Assets") : 0;
            fileList.Add(fs[i].Substring(index));
        }
        for (int i = 0; i < ds.Length; i++)
        {
            fileList.AddRange(GetFiles(ds[i], splitAssetPath));
        }
        return fileList;
    }

    /// <summary>
    /// 递归遍历获取目标目录中的所有文件
    /// </summary>
    /// <param name="sourceDirs">目标目录数组</param>
    /// <param name="splitAssetPath">是否要切割目录，以assets目录为根</param>
    /// <returns></returns>
    public static List<string> GetFiles(string[] sourceDirs, bool splitAssetPath)
    {
        List<string> fileList = new List<string>();
        foreach (var sourceDir in sourceDirs)
        {
            fileList.AddRange(GetFiles(sourceDir, splitAssetPath));
        }
        return fileList;
    }

    /// <summary>
    /// 根据哈希表构建AssetBundleBuild列表
    /// </summary>
    /// <param name="tab">哈希表，key为AssetBundleName，value为路径</param>
    /// <returns></returns>
    public static AssetBundleBuild[] MakeAssetBundleBuildArray(Hashtable tab)
    {
        AssetBundleBuild[] buildArray = new AssetBundleBuild[tab.Count];
        int index = 0;
        foreach (string key in tab.Keys)
        {
            buildArray[index].assetBundleName = key;
            List<string> fileList = new List<string>();
            fileList = GetFiles(Application.dataPath + "/" + tab[key], true);
            buildArray[index].assetNames = fileList.ToArray();
            ++index;
        }
        return buildArray;
    }

    /// <summary>
    /// 打包常规配置表AssetBundle
    /// </summary>
    /// <param name="targetPath">目标路径</param>
    public static void BuildNormalCfgBundle(string targetPath)
    {
        Hashtable tab = new Hashtable();
        tab["normalcfg.bundle"] = "GameRes/Config";
        AssetBundleBuild[] buildArray = BuildUtils.MakeAssetBundleBuildArray(tab);
        BuildBundles(buildArray, targetPath);
    }

    /// <summary>
    /// 打包Lua的AssetBundle
    /// </summary>
    /// <param name="targetPath">目标路径</param>
    public static void BuildLuaBundle(string targetPath)
    {
        // 创建lua的Bundle临时目录
        var luaBundleDir = CreateTmpDir("luabundle");
        // 将Lua代码拷贝到Bundle临时目录（加密处理）
        var luaFiles = GetFiles(new string[] {
            Application.dataPath + "/LuaFramework/Lua",
            Application.dataPath + "/LuaFramework/ToLua/Lua",
        }, true);
        BuildUtils.CopyLuaToBuildDir(luaFiles, luaBundleDir);
        // 构建AssetBundleBuild列表
        Hashtable tab = new Hashtable();
        tab["lua.bundle"] = "luabundle";
        AssetBundleBuild[] buildArray = MakeAssetBundleBuildArray(tab);
        // 打包AssetBundle
        BuildBundles(buildArray, targetPath);

        // 删除Lua的AssetBundle临时目录
        DeleteDir(luaBundleDir);
        AssetDatabase.Refresh();
    }

    public static void BuildGameResBundle(string targetPath)
    {
        Hashtable tab = new Hashtable();
        tab["baseres.bundle"] = "GameRes/BaseRes";
        tab["uiprefabs.bundle"] = "GameRes/UIPrefabs";
        AssetBundleBuild[] buildArray = MakeAssetBundleBuildArray(tab);
        BuildBundles(buildArray, targetPath);
    }

    /// <summary>
    /// 打AssetBundle
    /// </summary>
    /// <param name="buildArray">AssetBundleBuild列表</param>
    /// <param name="targetPath">目标目录</param>
    public static void BuildBundles(AssetBundleBuild[] buildArray, string targetPath)
    {
        if (!Directory.Exists(targetPath))
        {
            Directory.CreateDirectory(targetPath);
        }
        BuildPipeline.BuildAssetBundles(targetPath, buildArray, BuildAssetBundleOptions.ChunkBasedCompression, GetBuildTarget());
    }

    /// <summary>
    /// app打包
    /// </summary>
    public static void BuildApp()
    {
        // 场景
        string[] scenes = new string[] { "Assets/Scenes/Main.unity"};
        // 文件名
        string appName = PlayerSettings.productName + "_" + VersionMgr.instance.appVersion + GetTargetPlatfromAppPostfix();
        // 输出目录
        string outputPath = Application.dataPath + "/../Bin/";
        if (!Directory.Exists(outputPath))
        {
            Directory.CreateDirectory(outputPath);
        }
        // 包体完整路径
        string appPath = Path.Combine(outputPath, appName);

        BuildPipeline.BuildPlayer(scenes, appPath, GetBuildTarget(), BuildOptions.None);
    }

    /// <summary>
    /// 生成原始Lua代码的md5
    /// </summary>
    public static void GenOriginalLuaFrameworkMD5File()
    {
        VersionMgr.instance.Init();
        JsonData jsonData = GetOriginalLuaframeworkMD5Json();
        var jsonStr = JsonMapper.ToJson(jsonData);
        jsonStr = jsonStr.Replace(",", ",\n");
        if (!Directory.Exists(BIN_PATH))
        {
            Directory.CreateDirectory(BIN_PATH);
        }
        using (StreamWriter sw = new StreamWriter(BIN_PATH + "LuaFrameworkFiles_" + VersionMgr.instance.appVersion + ".json"))
        {
            sw.Write(jsonStr);
        }
    }

    /// <summary>
    /// 获取原始lua代码md5json
    /// </summary>
    /// <returns></returns>
    public static JsonData GetOriginalLuaframeworkMD5Json()
    {
        var sourceDirs = new string[] {
            Application.dataPath + "/LuaFramework/Lua",
            Application.dataPath + "/LuaFramework/ToLua/Lua",
        };
        JsonData jsonData = new JsonData();
        foreach (var sourceDir in sourceDirs)
        {
            List<string> fileList = new List<string>();
            fileList = GetFiles(sourceDir, false);
            foreach (var luaFile in fileList)
            {
                if (!luaFile.EndsWith(".lua")) continue;

                var md5 = LuaFramework.Util.md5file(luaFile);
                var key = luaFile.Substring(luaFile.IndexOf("Assets/"));
                jsonData[key] = md5;
            }
        }
        return jsonData;
    }

    /// <summary>
    /// 尝试获取Lua代码版本
    /// </summary>
    /// <returns></returns>
    public static string TryGetLuaFrameworkFilesVersion()
    {
        if (!Directory.Exists(BuildUtils.BIN_PATH))
            return null;
        var fs = Directory.GetFiles(BuildUtils.BIN_PATH);
        foreach (var f in fs)
        {
            if (f.Contains("LuaFrameworkFiles_"));
            {
                var result = Regex.Match(f, ".*LuaFrameworkFiles_(.*).json");
                if (null != result)
                {
                    return result.Groups[1].Value;
                }
            }
        }
        return null;
    }

    /// <summary>
    /// 创建临时目录
    /// </summary>
    /// <param name="dirName">目录名称</param>
    /// <returns></returns>
    public static string CreateTmpDir(string dirName)
    {
        var tmpDir = string.Format(Application.dataPath + "/{0}/", dirName);
        if (Directory.Exists(tmpDir))
        {
            Directory.Delete(tmpDir, true);

        }
        Directory.CreateDirectory(tmpDir);
        return tmpDir;
    }

    /// <summary>
    /// 删除目录
    /// </summary>
    /// <param name="targetDir">目标目录</param>
    public static void DeleteDir(string targetDir)
    {
        if (Directory.Exists(targetDir))
        {
            Directory.Delete(targetDir, true);
        }
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 拷贝Lua到目标目录，并做加密处理
    /// </summary>
    /// <param name="luaFiles">源目录列表</param>
    /// <param name="luaBundleDir">母包目录</param>
    public static void CopyLuaToBuildDir(List<string> luaFiles, string luaBundleDir)
    {
        foreach (var luaFile in luaFiles)
        {
            if (luaFile.EndsWith(".meta")) continue;
            var luaFileFullPath = Application.dataPath + "/../" + luaFile;
            // 由于BuildAssetBundle不识别.lua文件，所以拷贝一份到临时目录，统一加上.bytes结尾
            var targetFile = luaFile.Replace("Assets/LuaFramework/Lua", "");
            targetFile = targetFile.Replace("Assets/LuaFramework/ToLua/Lua", "");
            targetFile = luaBundleDir + targetFile + ".bytes";
            var targetDir = Path.GetDirectoryName(targetFile);
            if (!Directory.Exists(targetDir))
            {
                Directory.CreateDirectory(targetDir);
            }

            // 加密处理
            byte[] bytes = File.ReadAllBytes(luaFileFullPath);
            byte[] encrypBytes = AESEncrypt.Encrypt(bytes);
            File.WriteAllBytes(targetFile, encrypBytes);
        }
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 获取当前平台
    /// </summary>
    /// <returns></returns>
    public static BuildTarget GetBuildTarget()
    {
#if UNITY_STANDALONE
        return BuildTarget.StandaloneWindows;
#elif UNITY_ANDROID
        return BuildTarget.Android;
#else
        return BuildTarget.iOS;
#endif
    }

    /// <summary>
    /// 获取目标平台app后缀
    /// </summary>
    /// <param name="usAAB">是否使用aab打包</param>
    /// <returns></returns>
    public static string GetTargetPlatfromAppPostfix(bool usAAB = false)
    {
#if UNITY_STANDALONE
        return ".exe";
#elif UNITY_ANDROID
        if (usAAB)
        {
            return ".aab";
        }
        else
        {
            return ".apk";
        }
#else
        return ".ipa";
#endif
    }

    public static string BIN_PATH
    {
        get { return Application.dataPath + "/../Bin/"; }
    }
}