namespace Guru.Editor
{
	using System.Linq;
	using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEditor;
    using System.IO;
	using NUnit.Framework;

	/// <summary>
	/// 构建工具
	/// </summary>
    public partial class AppBuilder
    {
	    public static int AndroidTargetSdkVersion = 33;
	    public static string IOSTargetOSVersion = "13.0";
	    public static string GuruIOSTeamId = "39253T242A";
	    public static string GuruKeystoreName => "guru_key.jks";
	    public static string GuruKeystorePass => "guru0622";
	    public static string GuruAliasName => "guru";
	    public static string GuruAliasPass => "guru0622";
	    public static string GuruKeystorePath => Application.dataPath + $"/Plugins/Android/{GuruKeystoreName}";
	    public static string ProguardName => "proguard-user.txt";
	    public static string ProguardPath => Application.dataPath + $"/Plugins/Android/{ProguardName}";
	    public static string OutputDirName => "BuildOutput";

	    #region 构建接口

	    /// <summary>
	    /// 直接调用 Build 接口
	    /// </summary>
	    /// <param name="buildParam"></param>
	    /// <returns></returns>
	    public static string Build(AppBuildParam buildParam)
	    {
		    string outputPath = string.Empty;
		    switch (buildParam.TargetName)
		    {
			    case AppBuildParam.TargetNameAndroid:
				    SwitchBuildPlatform(BuildTarget.Android);
				    outputPath = BuildAndroid(buildParam);
				    break;
			    case AppBuildParam.TargetNameIOS:
				    SwitchBuildPlatform(BuildTarget.iOS);
				    outputPath = BuildIOS(buildParam);
				    break;
			    default:
					Debug.Log($"<color=red> Unsupported build target: {buildParam.TargetName}. Skip build...</color>");
				    break;
		    }

		    return outputPath;
	    }


	    #endregion
	    
        #region 构建 Android 接口

        /// <summary>
        /// 构建 Android 包体
        /// </summary>
        /// <param name="buildParam"></param>
        /// <returns></returns>
        public static string BuildAndroid(AppBuildParam buildParam)
	    {
		    // 切换平台
		    SwitchBuildPlatform(BuildTarget.Android);
		    // 打包通用设置
		    ChangeBuildPlayerCommonSetting(buildParam, BuildTargetGroup.Android);
		    
		    var isDebug = !buildParam.IsBuildRelease;
		    var useMinify = buildParam.AndroidUseMinify;
	        var buildNumber= GetBuildNumberString(BuildTarget.Android);
			if(buildParam.AutoSetBuildNumber) buildNumber = ChangeBuildNumber(BuildTarget.Android);
	        
			// 保存版本信息
			SaveBuildVersion(buildParam.BuildVersion, buildNumber);
			
	        //android专用打包设置
	        EditorUserBuildSettings.buildAppBundle = buildParam.IsBuildAAB;
	        EditorUserBuildSettings.development = isDebug;
#if UNITY_2020_3
	        EditorUserBuildSettings.androidCreateSymbolsZip = buildParam.IsBuildSymbols;
#elif UNITY_2021_3
	        EditorUserBuildSettings.androidCreateSymbols = buildParam.IsBuildSymbols? AndroidCreateSymbols.Public : AndroidCreateSymbols.Disabled; //Android 输出SymbolsZip的选项
#endif
	        PlayerSettings.muteOtherAudioSources = false;
			// ---- 开启 Minify 后需要配置 proguard-user.txt 文件 ---- 
			if (useMinify) DeployProguardTxt();
			PlayerSettings.Android.minifyWithR8 = useMinify;
			PlayerSettings.Android.minifyRelease = useMinify;
			PlayerSettings.Android.minifyDebug = useMinify;
			// ---- 部署 Guru 专用的 Keystore ----
		    if (buildParam.UseGuruCerts && DeployAndroidKeystore())
		    {
			    // ---- 使用 Guru 专用的 KeyStore ----
			    PlayerSettings.Android.useCustomKeystore = true;
			    PlayerSettings.Android.keystoreName = GuruKeystorePath;
			    PlayerSettings.Android.keystorePass = GuruKeystorePass;
			    PlayerSettings.Android.keyaliasName = GuruAliasName;
			    PlayerSettings.Android.keyaliasPass = GuruAliasPass;
		    }
		    else if(!string.IsNullOrEmpty(buildParam.AndroidKeystorePath))
		    {
			    // ---- 使用 Custom 的 KeyStore ----
			    PlayerSettings.Android.useCustomKeystore = true;
			    PlayerSettings.Android.keystoreName = buildParam.AndroidKeystorePath;
			    PlayerSettings.Android.keystorePass = buildParam.AndroidKeystorePass;
			    PlayerSettings.Android.keyaliasName = buildParam.AndroidAlias;
			    PlayerSettings.Android.keyaliasPass = buildParam.AndroidAliasPass;
		    }

		    PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARMv7 | AndroidArchitecture.ARM64; //只构建 armv7 和 arm64
	        PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel22;
	        if (buildParam.AndroidTargetVersion > 0) AndroidTargetSdkVersion = buildParam.AndroidTargetVersion;
	        PlayerSettings.Android.targetSdkVersion = (AndroidSdkVersions)AndroidTargetSdkVersion;  // 默认设置API为33
	        
	        //打包
	        string symbolDefine = buildParam.IsBuildRelease ? GameDefine.MACRO_RELEASE : GameDefine.MACRO_DEBUG;
	        string apkPath = string.Empty;
	        string version = Application.version;
	        string extension = buildParam.IsBuildAAB ? ".aab" : ".apk";
	        if (EditorUserBuildSettings.exportAsGoogleAndroidProject) extension = ""; // 输出工程
		    string outputDir = Path.GetFullPath($"{Application.dataPath }/../{OutputDirName}/Android");
	        apkPath = $"{outputDir}/{Application.productName.Replace(" ","_")}_{symbolDefine}_{version}_{buildNumber}{extension}";
	        if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);

	        BuildOptions opts = isDebug ? BuildOptions.Development : BuildOptions.None;
	        BuildPipeline.BuildPlayer(GetBuildScenes(), apkPath, BuildTarget.Android, opts);
	        if (buildParam.BuilderType == AppBuilderType.Editor)
	        {
		        Open(outputDir);
	        }
	        
	        if (buildParam.AutoPublish)
	        {
		        GuruPublishHelper.Publish(apkPath, buildParam.PgyerAPIKey); // 直接发布版本
	        }
	        return apkPath;
	    }

		/// <summary>
		/// 部署 Guru 专用的 Keystore
		/// </summary> 
        private static bool DeployAndroidKeystore()
        {
	        var dir = GetWorkingDir();
	        var from = $"{dir}/{GuruKeystoreName}";
	        var to = GuruKeystorePath;

	        if (File.Exists(to)) return true;
	        
	        if (File.Exists(from))
	        {
		        File.Copy(from, to);
		        return true;
	        }
	        
	        return false;
        }

		/// <summary>
		/// 部署混淆用配置
		/// </summary> 
        private static bool DeployProguardTxt()
        {
	        var dir = GetWorkingDir();
	        var from = $"{dir}/{ProguardName}";
	        var to = ProguardPath;

	        if (File.Exists(to)) return true;
	        
	        if (File.Exists(from))
	        {
		        File.Copy(from, to);
		        return true;
	        }
	        
	        return false;
        }


        #endregion
        
        #region 构建 IOS 接口
        
        public static string BuildIOS(AppBuildParam buildParam)
	    {
	        //切换平台
	        SwitchBuildPlatform(BuildTarget.iOS);
	        //打包通用设置
	        ChangeBuildPlayerCommonSetting(buildParam, BuildTargetGroup.iOS);
	        
	        //修改打包版本号
	        var buildNumber= GetBuildNumberString(BuildTarget.Android);
	        if(buildParam.AutoSetBuildNumber) buildNumber = ChangeBuildNumber(BuildTarget.iOS);
	        
	        // 保存版本信息
	        SaveBuildVersion(buildParam.BuildVersion, buildNumber);
	        
	        var isDebug = !buildParam.IsBuildRelease;

	        //ios专用打包设置
	        PlayerSettings.muteOtherAudioSources = false;
	        PlayerSettings.iOS.appInBackgroundBehavior = iOSAppInBackgroundBehavior.Custom;
	        PlayerSettings.iOS.backgroundModes = iOSBackgroundMode.RemoteNotification | iOSBackgroundMode.Fetch; // 后台启动配置
	        PlayerSettings.iOS.targetDevice = iOSTargetDevice.iPhoneAndiPad;
	        PlayerSettings.iOS.sdkVersion = iOSSdkVersion.DeviceSDK;

	        var targetVersion = IOSTargetOSVersion;
	        if (!string.IsNullOrEmpty(buildParam.IOSTargetVersion)) targetVersion = buildParam.IOSTargetVersion;	        
	        PlayerSettings.iOS.targetOSVersionString = targetVersion;

	        var teamId = buildParam.IOSTeamId;
	        if (buildParam.UseGuruCerts) teamId = GuruIOSTeamId;
	
	        if (!string.IsNullOrEmpty(teamId))
	        {
		        PlayerSettings.iOS.appleEnableAutomaticSigning = true;
		        PlayerSettings.iOS.appleDeveloperTeamID = teamId;
	        }
	        
		    //打包
	        string outputDir = Path.GetFullPath($"{Application.dataPath }/../{OutputDirName}/Xcode");
	        if (Directory.Exists(outputDir))
	        {
	            Directory.Delete(outputDir, true);
	        }

	        // 构建后打开路径
	        try
	        {
		        BuildOptions opts = isDebug ? BuildOptions.Development : BuildOptions.None;
		        BuildPipeline.BuildPlayer(GetBuildScenes(), outputDir, BuildTarget.iOS, BuildOptions.None);
		        if (buildParam.BuilderType == AppBuilderType.Editor)
		        {
			        Open(outputDir);
		        }
	        }
	        catch (Exception e)
	        {
		        Debug.LogError(e.Message);
	        }

	        return outputDir;
	    }       

        #endregion

        #region 通用接口

		/// <summary>
		/// 获取工作目录
		/// </summary>
		/// <returns></returns>
        private static string GetWorkingDir()
        {
	        var guids = AssetDatabase.FindAssets($"{nameof(AppBuilder)} t:Script");
	        if (guids.Length > 0)
	        {
		        var path = "";
		        foreach (var guid in guids)
		        {
			        path = AssetDatabase.GUIDToAssetPath(guids[0]);
			        if (path.Contains($"Editor/BuildTool/{nameof(AppBuilder)}"))
			        {
				        return Directory.GetParent(path)!.FullName;
			        }
		        }
	        }
	        return Path.GetFullPath("Packages/com.guru.unity.sdk.core/Editor/BuildTool/");
        }

        /// <summary>
	    /// 平台切换
	    /// </summary>
	    /// <param name="targetPlatform"></param>
	    private static void SwitchBuildPlatform(BuildTarget targetPlatform)
	    {
		    if (EditorUserBuildSettings.activeBuildTarget != targetPlatform)
		    {
			    EditorUserBuildSettings.SwitchActiveBuildTarget(BuildPipeline.GetBuildTargetGroup(targetPlatform), targetPlatform);
			    AssetDatabase.Refresh();
		    }
	    }
	    
	    private static void ChangeBuildPlayerCommonSetting(AppBuildParam buildParam, BuildTargetGroup buildTargetGroup)
	    {
		    EditorUserBuildSettings.development = !buildParam.IsBuildRelease;
		    EditorUserBuildSettings.allowDebugging = false;
		    EditorUserBuildSettings.connectProfiler = false;
		    EditorUserBuildSettings.buildScriptsOnly = false;

		    var backend = ScriptingImplementation.IL2CPP;
		    if (buildTargetGroup == BuildTargetGroup.Android
		        && !buildParam.IsBuildRelease && buildParam.DebugWithMono)
		    {
			    backend = ScriptingImplementation.Mono2x;
		    }
		    PlayerSettings.SetScriptingBackend(buildTargetGroup, backend);
			
		    var companyName = buildParam.CompanyName;
		    if(string.IsNullOrEmpty(companyName)) companyName = GameDefine.CompanyName;
		    PlayerSettings.companyName = companyName;
		    
		    var bundleVersion = buildParam.BuildVersion;
		    if(!string.IsNullOrEmpty(bundleVersion)) PlayerSettings.bundleVersion = bundleVersion;
		    
		    // -------- Defines --------
		    List<string> defines = new List<string>();
		    var str = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup);
		    if (!string.IsNullOrEmpty(str))
		    {
			    defines = str.Split(';').ToList();
		    }

		    if (defines.Count > 0)
		    {
			    defines.Remove(GameDefine.MACRO_RELEASE);
			    defines.Remove(GameDefine.MACRO_DEBUG);
		    }
		    
		    defines.Add(buildParam.IsBuildRelease ? GameDefine.MACRO_RELEASE : GameDefine.MACRO_DEBUG);
		    if (!buildParam.IsBuildRelease || buildParam.IsBuildShowLog)
		    {
			    defines.Add(GameDefine.MACRO_LOG);
		    }
		    
		    // defines.Add("mopub_manager");
		    PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, defines.ToArray());
		    PlayerSettings.stripEngineCode = true;
		    PlayerSettings.SetManagedStrippingLevel(buildTargetGroup, ManagedStrippingLevel.Low);
		    PlayerSettings.SetApiCompatibilityLevel(buildTargetGroup, ApiCompatibilityLevel.NET_4_6);
	    }
	    
	    /// <summary>
	    /// 修改打包版本号
	    /// </summary>
	    /// <param name="buildTarget"></param>
	    /// <param name="isRelease"></param>
	    private static string ChangeBuildNumber(BuildTarget buildTarget)
	    {
		    var nowDate = DateTime.Now;
		    string strBuildNumber = $"{nowDate.Year - 2000}{nowDate.Month:00}{nowDate.Day:00}{(nowDate.Hour * 60 + nowDate.Minute) / 15}";
		    int buildNumber = int.Parse(strBuildNumber);
		    if (buildTarget == BuildTarget.iOS)
		    {
			    PlayerSettings.iOS.buildNumber = buildNumber.ToString();
		    }
		    else if (buildTarget == BuildTarget.Android)
		    {
			    PlayerSettings.Android.bundleVersionCode = buildNumber;
		    }
		    return strBuildNumber;
	    }
		
	    /// <summary>
	    /// 获取构建数变量
	    /// </summary>
	    /// <returns></returns>
	    private static string GetBuildNumberString(BuildTarget buildTarget)
	    {
		    if (buildTarget == BuildTarget.iOS)
		    {
			    return PlayerSettings.iOS.buildNumber;
		    }
		    
		    if (buildTarget == BuildTarget.Android)
		    {
			    return PlayerSettings.Android.bundleVersionCode.ToString();
		    } 
		    return "";
	    }


	    private static void SaveBuildVersion(string version, string code)
	    {
		    GuruAppVersion.SaveToDisk(version, code);
	    }

	    /// <summary>
	    /// 获取打包场景
	    /// </summary>
	    /// <returns></returns>
	    public static string[] GetBuildScenes()
	    {
		    List<string> names = new List<string>();
		    foreach (var e in EditorBuildSettings.scenes)
		    {
			    if(e == null)
				    continue;
			    if(e.enabled)
				    names.Add(e.path);
		    }
		    return names.ToArray();
	    }

		/// <summary>
		/// 打开路径
		/// </summary>
		/// <param name="path"></param>
	    public static void Open(string path)
	    {
#if UNITY_EDITOR_OSX
		    EditorUtility.RevealInFinder(path);
#else
			Application.OpenURL($"file://{path}");
#endif
		    
	    }
	    #endregion

	    #region 单元测试

		[Test]
	    public static void TEST_GetWorkingDir()
	    {
		    var path = GetWorkingDir();
		    Debug.Log(path);

		    if (Directory.Exists(path))
		    {
			    Open(path);
		    }
		    else
		    {
			    Debug.LogError($"path not found: {path}");
		    }

	    }


	    #endregion
	    
    }
}



