/******************************************************************************
 * Spine Runtimes License Agreement
 * Last updated April 5, 2025. Replaces all prior versions.
 *
 * Copyright (c) 2013-2026, Esoteric Software LLC
 *
 * Integration of the Spine Runtimes into software or otherwise creating
 * derivative works of the Spine Runtimes is permitted under the terms and
 * conditions of Section 2 of the Spine Editor License Agreement:
 * http://esotericsoftware.com/spine-editor-license
 *
 * Otherwise, it is permitted to integrate the Spine Runtimes into software
 * or otherwise create derivative works of the Spine Runtimes (collectively,
 * "Products"), provided that each user of the Products must obtain their own
 * Spine Editor license and redistribution of the Products in any form must
 * include this license and copyright notice.
 *
 * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
 * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/

#pragma warning disable 0219

#define SPINE_SKELETONMECANIM

#if UNITY_2017_2_OR_NEWER
#define NEWPLAYMODECALLBACKS
#endif

#if UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif

#if UNITY_2018_3_OR_NEWER
#define NEWHIERARCHYWINDOWCALLBACKS
#endif

#if UNITY_2021_2_OR_NEWER
#define USES_NAMED_BUILD_TARGETS
#endif

using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEngine;

namespace Spine.Unity.Editor {

	public static class SpineBuildEnvUtility {
		public const string SPINE_ALLOW_UNSAFE_CODE = "SPINE_ALLOW_UNSAFE";
		public const string SPINE_AUTO_UPGRADE_COMPONENTS_OFF = "SPINE_AUTO_UPGRADE_COMPONENTS_OFF";
		public const string SPINE_ENABLE_THREAD_PROFILING = "SPINE_ENABLE_THREAD_PROFILING";
		public const string SPINE_DISABLE_LOAD_BALANCING = "SPINE_DISABLE_LOAD_BALANCING";

		static bool IsInvalidGroup (BuildTargetGroup group) {
			int gi = (int)group;
			return
				gi == 15 || gi == 16 || group == BuildTargetGroup.Unknown;
		}

		public static bool EnableBuildDefine (string define) {

			bool wasDefineAdded = false;

#if !USES_NAMED_BUILD_TARGETS
			Debug.LogWarning("Please ignore errors \"PlayerSettings Validation: Requested build target group doesn't exist\" below");
#endif
			foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {
				if (IsInvalidGroup(group))
					continue;

				try {
#if USES_NAMED_BUILD_TARGETS
					var target = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(group);
					string defines = PlayerSettings.GetScriptingDefineSymbols(target);
#else
					string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
#endif
					if (!defines.Contains(define)) {
						wasDefineAdded = true;
						if (defines.EndsWith(";", System.StringComparison.Ordinal))
							defines += define;
						else
							defines += ";" + define;
#if USES_NAMED_BUILD_TARGETS
						PlayerSettings.SetScriptingDefineSymbols(target, defines);
#else
						PlayerSettings.SetScriptingDefineSymbolsForGroup(group, defines);
#endif
					}
				} catch (System.Exception) {
				}
			}
#if !USES_NAMED_BUILD_TARGETS
			Debug.LogWarning("Please ignore errors \"PlayerSettings Validation: Requested build target group doesn't exist\" above");
#endif
			if (wasDefineAdded) {
				Debug.LogWarning("Setting Scripting Define Symbol " + define);
			} else {
				Debug.LogWarning("Already Set Scripting Define Symbol " + define);
			}
			return wasDefineAdded;
		}

		public static bool DisableBuildDefine (string define) {

			bool wasDefineRemoved = false;
			foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {
				if (IsInvalidGroup(group))
					continue;

				try {
#if USES_NAMED_BUILD_TARGETS
					var target = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(group);
					string defines = PlayerSettings.GetScriptingDefineSymbols(target);
#else
					string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
#endif
					if (defines.Contains(define)) {
						wasDefineRemoved = true;
						if (defines.Contains(define + ";"))
							defines = defines.Replace(define + ";", "");
						else
							defines = defines.Replace(define, "");
#if USES_NAMED_BUILD_TARGETS
						PlayerSettings.SetScriptingDefineSymbols(target, defines);
#else
						PlayerSettings.SetScriptingDefineSymbolsForGroup(group, defines);
#endif
					}
				} catch (System.Exception) {
				}
			}

			if (wasDefineRemoved) {
				Debug.LogWarning("Removing Scripting Define Symbol " + define);
			} else {
				Debug.LogWarning("Already Removed Scripting Define Symbol " + define);
			}
			return wasDefineRemoved;
		}

		public static void DisableSpineAsmdefFiles () {
			SetAsmdefFileActive("spine-unity-editor", false);
			SetAsmdefFileActive("spine-unity", false);
		}

		public static void EnableSpineAsmdefFiles () {
			SetAsmdefFileActive("spine-unity-editor", true);
			SetAsmdefFileActive("spine-unity", true);
		}

		internal static void SetAsmdefFileActive (string filename, bool setActive) {

			string typeSearchString = setActive ? " t:TextAsset" : " t:AssemblyDefinitionAsset";
			string extensionBeforeChange = setActive ? ".txt" : ".asmdef";
			string[] guids = AssetDatabase.FindAssets(filename + typeSearchString);
			foreach (string guid in guids) {
				string currentPath = AssetDatabase.GUIDToAssetPath(guid);
				if (System.IO.Path.GetExtension(currentPath) != extensionBeforeChange) // asmdef is also found as t:TextAsset, so check
					continue;

				string targetPath = System.IO.Path.ChangeExtension(currentPath, setActive ? "asmdef" : "txt");
				if (System.IO.File.Exists(currentPath) && !System.IO.File.Exists(targetPath)) {
					System.IO.File.Copy(currentPath, targetPath);
					System.IO.File.Copy(currentPath + ".meta", targetPath + ".meta");
				}
				AssetDatabase.DeleteAsset(currentPath);
			}
		}
	}
}
