using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
#if UNITY_IOS
using UnityEditor.iOS.Xcode;
#endif

public static class Builder {
	static readonly string build_dir = "project";
	
	static readonly string ios_build_path = "iOS";

	//com.gcp2.stepbystep.android.google.global.normal  
	//com.gcp2.stepbystep.ios.apple.global.ent
	//com.gcp2.stepbystep.ios.apple.global.normal
	static readonly string ios_appidentifier = "com.gcp2.stepbystep.ios.apple.global.normal";

	static readonly string googleplay_appidentifier = "com.gcp2.stepbystep.android.google.global.normal";

	static readonly string android_apk_name =  "stepbystep.apk";
	static readonly string android_build_path = "Android";


	static readonly char separator = Path.DirectorySeparatorChar;

	static void SwitchBuildTarget(BuildTargetGroup group,BuildTarget target) {
        #if UNITY_5_6_OR_NEWER
        EditorUserBuildSettings.SwitchActiveBuildTarget(group,target);
        #else
        EditorUserBuildSettings.SwitchActiveBuildTarget(target);
        #endif
    }

    static void SwitchBuildTargetiOS() {
        //외부 빌드 스크립트에서 참조용
        SwitchBuildTarget(BuildTargetGroup.iOS,BuildTarget.iOS);
    }

    static void SwitchBuildTargetAndroid() {
        //외부 빌드 스크립트에서 참조용
        SwitchBuildTarget(BuildTargetGroup.Android,BuildTarget.Android);
    }

	static BuildOptions GetBuildOptions(bool isDebug, bool isProject) {
		BuildOptions opt = BuildOptions.None;
		if(isDebug){
			opt = BuildOptions.SymlinkSources |
					BuildOptions.Development | 
					BuildOptions.ConnectWithProfiler |
					BuildOptions.AllowDebugging;
		} 
		
		// iOS?
		if (isProject) {
			#if UNITY_2019_3_OR_NEWER
			opt = opt;
			#else 
			opt = opt | BuildOptions.AcceptExternalModificationsToPlayer;
			#endif
		} 
		/* 2019.4.13f
		아이폰 OS
		var options = BuildOptions.AcceptExternalModificationsToPlayer;
		->
		var options = BuildOptions.AllowDebugging;

		안드로이드
		var options = BuildOptions.AcceptExternalModificationsToPlayer;
		->
		var options = BuildOptions.AllowDebugging;
		EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
		*/
		
		return opt;
	}

	[MenuItem("Hive/Development/Build iOS Debug")]
	static void BuildiOSDebug() {
		BuildiOS(true);
	}

	[MenuItem("Hive/Development/Build iOS Release")]
	static void BuildiOSRelease() {
		BuildiOS(false);
	}

	//iOS : com.com2us.stepbystep.normal.freefull.apple.global.ios.universal
	static void BuildiOS(bool isDebug) {
		const BuildTargetGroup build_target_group = BuildTargetGroup.iOS;
		const BuildTarget build_target = BuildTarget.iOS;
		try {
			if(!EditorUserBuildSettings.SwitchActiveBuildTarget(build_target_group,build_target)) {
				throw new Exception("BuildPlayer failure: can not change build target.");
			}
			
        	Hive.Unity.Editor.HiveConfigXML.iOS.commit();
			SetHiveServer(false);
			//save config xml
			//Hive.Unity.Editor.HiveConfigXML.iOS.commit();

			if(isDebug) {
				disableHIVELog();
			}
			//bundle id setting
			UnityEditor.PlayerSettings.applicationIdentifier = ios_appidentifier;//이전 앱아이디 -> "com.com2us.stepbystep.normal.freefull.apple.global.ios.universal";

			//set device and os setting
			UnityEditor.PlayerSettings.iOS.sdkVersion = iOSSdkVersion.DeviceSDK; 
			UnityEditor.PlayerSettings.iOS.targetOSVersionString = "13.0";
			
			//status bar style
			UnityEditor.PlayerSettings.iOS.statusBarStyle = iOSStatusBarStyle.LightContent;
			
			string buildDirectory = Path.GetFullPath(".") + separator + build_dir;
			Directory.CreateDirectory(buildDirectory);
	
			string BUILD_TARGET_PATH = buildDirectory + separator + ios_build_path;
			Directory.CreateDirectory(BUILD_TARGET_PATH);
	
			GenericBuild(BUILD_TARGET_PATH,build_target_group, build_target, GetBuildOptions(isDebug, true));		
		} catch(Exception e) {
			Debug.LogException(e);
		}
	}

	[MenuItem("Hive/Development/Build Android Debug")]
	static void BuildAndroidDebug() {
		BuildAndroid(true);
	}

	[MenuItem("Hive/Development/Build Android Release")]
	static void BuildAndroidRelease() {
		BuildAndroid(false);
	}

	//Android : com.com2us.stepbystep.normal.freefull.google.global.android.common
	static void BuildAndroid(bool isDebug) {
		const BuildTargetGroup build_target_group = BuildTargetGroup.Android;
		const BuildTarget build_target = BuildTarget.Android;
		try {
			if(!EditorUserBuildSettings.SwitchActiveBuildTarget(build_target_group,build_target)) {
				throw new Exception("BuildPlayer failure: can not change build target.");
			}

			Hive.Unity.Editor.HiveConfigXmlStep.PrepareAndroidSetting();
			Hive.Unity.Editor.HiveConfigXML.Android.commit();

			SetHiveServer(true);

            UnityEditor.HiveEditor.HiveMultidexResolver.resolveMultidex();
			//save config xml
			//Hive.Unity.Editor.HiveConfigXML.Android.commit();

			//bundle id setting
			UnityEditor.PlayerSettings.applicationIdentifier = googleplay_appidentifier; //이전 앱아이디 -> "com.com2us.stepbystep.normal.freefull.google.global.android.common";


			string buildDirectory = Path.GetFullPath(".") + separator + build_dir + separator + android_build_path;
        	Directory.CreateDirectory(buildDirectory);
			
			string BUILD_TARGET_APK = buildDirectory + separator + android_apk_name;

			//key store setting
			UnityEditor.PlayerSettings.Android.keystoreName = buildDirectory + "/StepbyStep_Upload.keystore";
			UnityEditor.PlayerSettings.Android.keystorePass = "Gcpmarket1";
			UnityEditor.PlayerSettings.Android.keyaliasName = "gcp";
			UnityEditor.PlayerSettings.Android.keyaliasPass = "Gcpmarket1";
 			
			UnityEditor.PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel24;


			string[] args = System.Environment.GetCommandLineArgs();

			string versionCodeNum = "0";
			string versionString = "";
			for ( int i = 0; i < args.Length; i++) {
				if ((args[i].Equals("-versionNum")) && (i < args.Length - 1)) {
					versionCodeNum = args[i+1];
				}
				if ((args[i].Equals("-extraParam")) && (i < args.Length -1)) {
					versionString = args[i+1];
				}
			}

			Debug.Log("Version  : " + versionString + " version code : " + versionCodeNum);
			// TODO: Gradle에 버전 코드 변경

			string bundleVersionShortName = PlayerSettings.bundleVersion; // aka 4.12.0.1 or 4.12.0.0.12345 , same as iTunes Connect Display for identify update. & displayVersion
			// int bundleVersionBuildCode;	// aka 4120001 for update order, product index, buildNumber
			// parseBuildVersion(versionString, out bundleVersionShortName);




			#if UNITY_5_6_OR_NEWER
			FixGradleTemplate(versionCodeNum, bundleVersionShortName);
			#else
			PlayerSettings.bundleVersion = bundleVersionShortName;
			PlayerSettings.Android.bundleVersionCode = bundleVersionBuildCode;
        	#endif


			GenericBuild(BUILD_TARGET_APK, build_target_group,build_target,GetBuildOptions(isDebug, false));
		} catch(Exception e) {
			Debug.LogException(e);
		}
	}

	private static string[] FindEnabledEditorScenes() {
        List<string> EditorScenes = new List<string>();
        foreach(EditorBuildSettingsScene scene in EditorBuildSettings.scenes) {
           if (!scene.enabled) continue;
           EditorScenes.Add(scene.path);
        }
        return EditorScenes.ToArray();
    }

	static void GenericBuild(string target_path,BuildTargetGroup build_target_group, BuildTarget build_target, BuildOptions build_options)
    {
		string[] SCENE = FindEnabledEditorScenes();
		UnityEditor.Build.Reporting.BuildReport res = BuildPipeline.BuildPlayer(SCENE, target_path, build_target, build_options);
        UnityEditor.Build.Reporting.BuildSummary summary = res.summary;

        if (summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
        {
			throw new Exception("BuildPlayer failure: " + res);
        }
    }

	static void SetHiveServer(bool isAndroid) {
		// Get server value
		string[] args = System.Environment.GetCommandLineArgs();
		string server = "";
		for ( int i = 0 ; i < args.Length ; i++) {
			if ((args[i].Equals("-hiveServer")) && (i < args.Length - 1)) {
				server = args[i+1];
			}
		}

		if (server.Equals("")){
			return;
		}

        Hive.Unity.Editor.HiveConfigXML platform = null;

		if (isAndroid) {
			platform = Hive.Unity.Editor.HiveConfigXML.Android;
		} else {
			platform = Hive.Unity.Editor.HiveConfigXML.iOS;
		}

		switch(server.ToLower()) {
			case "real":
			platform.zone = Hive.Unity.Editor.HiveConfigXML.ZoneType.real;
			break;
			case "sandbox":
			platform.zone = Hive.Unity.Editor.HiveConfigXML.ZoneType.sandbox;
			break;
			// case "test":
			// platform.zone = Hive.Unity.Editor.HiveConfigXML.ZoneType.test;
			// break;
			default:
			Debug.Log("SetHiveServer : default");
			return;
		}

		platform.commit();
		
	}

	static void disableHIVELog() {
		Hive.Unity.Editor.HiveConfigXML.Android.useLog = false;
		Hive.Unity.Editor.HiveConfigXML.iOS.useLog = false;
	}


    // bundleVersionShortName ( Android : versionName , iOS : bundleVersionString,Short )
	// bundleVersionBuildCode ( Android : versionCode , iOS : bundleVersion,Build )
	private static void parseBuildVersion(string versionString, out string bundleVersionShortName) {
		
		string[] buildSeperator = versionString.Split('_','#');
		
		int major = 0;
		int minor = 0;
		int patch = 0;
		int fix = 0;
		int build = 0;
		
		if( buildSeperator.Length > 0 ) {
			string[] versionSeperator = buildSeperator[0].Split('.',',');
			if(versionSeperator.Length > 0 && Int32.TryParse(versionSeperator[0], out major)) {
				if( major > 99 ) major = 99;
				else if( major < 0 ) major = 0;
			}
			if(versionSeperator.Length > 1 && Int32.TryParse(versionSeperator[1], out minor)) {
				if( minor > 99 ) minor = 99;
				else if( minor < 0 ) minor = 0;
			}
			if(versionSeperator.Length > 2 && Int32.TryParse(versionSeperator[2], out patch)) {
				if( patch > 99 ) patch = 99;
				else if( patch < 0 ) patch = 0;
			}
			if(versionSeperator.Length > 3 && Int32.TryParse(versionSeperator[3], out fix)) {
				if( fix > 99 ) fix = 99;
				else if( fix < 0 ) fix = 0;
			}
		}

		bundleVersionShortName = (major +"."+ minor +"."+ patch + "."+ fix).ToString();
		
		if(buildSeperator.Length > 1 && Int32.TryParse(buildSeperator[1], out build)) {
			if( build < 0 ) build = 0;
			bundleVersionShortName += "." + build;
		}
    }

    private static void FixGradleTemplate(string bundleVersionCode, string bundleVersionName)
    {
        var gradleFile = Application.dataPath + "/Plugins/Android/mainTemplate.gradle";
        var gradleData = File.ReadAllText(gradleFile);
    
        var signTemplate = "\tsigningConfigs { release {\r\n\t\tstoreFile file(\'_0_\')\r\n\t\tstorePassword \'_1_\'\r\n\t\tkeyAlias \'_2_\'\r\n\t\tkeyPassword \'_3_\'\r\n\t} }";
        var signData = signTemplate.Replace("_0_", PlayerSettings.Android.keystoreName)
                                .Replace("_1_", PlayerSettings.Android.keystorePass)
                                .Replace("_2_", PlayerSettings.Android.keyaliasName)
                                .Replace("_3_", PlayerSettings.Android.keyaliasPass);
    
        gradleData = gradleData
                    .Replace("**VERSIONCODE**", bundleVersionCode)
                    .Replace("**SIGN**", signData);
    
        File.WriteAllText(gradleFile, gradleData);
    }
    
    [PostProcessBuild(1)]
   public static void OnPostprocessBuild(BuildTarget buildTarget, string pathToBuiltProject)
   {
#if UNITY_IOS
      // Get plist
      string plistPath = pathToBuiltProject + "/Info.plist";
      PlistDocument plist = new PlistDocument();
      plist.ReadFromString(File.ReadAllText(plistPath));
 
      // Get root
      PlistElementDict rootDict = plist.root;
 
      // Set encryption usage boolean
      string encryptKey = "ITSAppUsesNonExemptEncryption";
        rootDict.SetBoolean(encryptKey, false);
 
      // remove exit on suspend if it exists.
      string exitsOnSuspendKey = "UIApplicationExitsOnSuspend";
      if(rootDict.values.ContainsKey(exitsOnSuspendKey))
      {
         rootDict.values.Remove(exitsOnSuspendKey);
      }

	  // 권한 관련 문구들 추가
		rootDict.SetString("NSCameraUsageDescription", "When registering a profile image in the game, you need to \"Allow\" the camera to take pictures.");
		rootDict.SetString("NSPhotoLibraryUsageDescription", "\"Allow\" is required to upload in-game profile images from Photos.");
		rootDict.SetString("NSUserTrackingUsageDescription", "The authority is requested to use the Advertising Identifiers (IDFA) for promotion targeting and tracking analysis.");
		// FBSDKShareKit에서 libSwiftCoreLocation을 참조하여 위치 권한을 요청할 수 있음 (문구는 현재 임시 번역)
		rootDict.SetString("NSLocationWhenInUseUsageDescription", "\"Allow\" is requested to use the location information for contents sharing.");

		rootDict.SetString("CFBundleName", "Planet Explore");
	  // Add Capability
	  	string pbxPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
        var capManager = new ProjectCapabilityManager(pbxPath, "ios.entitlements", "Unity-iPhone");
        capManager.AddGameCenter();
        capManager.AddInAppPurchase();
        capManager.AddPushNotifications(true);
		capManager.AddSignInWithApple();
		capManager.AddAssociatedDomains(new string[]{
			"applinks:promotion.qpyou.cn",
			"applinks:test-promotion.qpyou.cn",
			"applinks:sandbox-promotion.qpyou.cn"
		});

		capManager.WriteToFile();

      // Write to file
      File.WriteAllText(plistPath, plist.WriteToString());
#endif
   }
}
