/* Copyright (C) Itseez3D, Inc. - All Rights Reserved
* You may not use this file except in compliance with an authorized license
* Unauthorized copying of this file, via any medium is strictly prohibited
* Proprietary and confidential
* UNLESS REQUIRED BY APPLICABLE LAW OR AGREED BY ITSEEZ3D, INC. IN WRITING, SOFTWARE DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED
* See the License for the specific language governing permissions and limitations under the License.
* Written by Itseez3D, Inc. <support@avatarsdk.com>, August 2026
*/

using System;
using System.IO;
using System.Text;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace AvatarSDKMove
{
	public static class AuthUtils
	{
		private const int DistractionTokensCount = 10;
		private const string SessionKeyBase = "avatar_sdk_move_session";

		public static event Action SessionChanged;

		private static string SessionKey { get { return SessionKeyBase + AvatarSDKMoveServer.SessionKeySuffix; } }

		private static string GetKey()
		{
			string key = "mV9$q2Lr!ncTe8#wPd4^Ax7&Zk1@Bs6";
			key = Convert.ToBase64String(Encoding.UTF8.GetBytes(key));
			if (key.Length > 32)
				key = key.Substring(0, 32);
			while (key.Length < 32)
				key += key[0];
			return key;
		}

		public static ClientCredentials LoadClientCredentials()
		{
			try
			{
				var asset = Resources.Load<TextAsset>(AvatarSDKMoveSettings.ClientResourceName);
				if (asset == null)
					return null;

				string text = EncryptionUtils.Decrypt(asset.text, GetKey());
				text = Encoding.UTF8.GetString(Convert.FromBase64String(text));

				string[] tokens = text.Split(' ');
				return new ClientCredentials(tokens[0], tokens[1]);
			}
			catch (Exception ex)
			{
				Debug.LogFormat("Could not load the Avatar SDK Move client credentials: {0}", ex.Message);
				return null;
			}
		}

		public static UserSession LoadSession()
		{
			string stored = LoadValue(SessionKey);
			if (string.IsNullOrEmpty(stored))
				return null;

			try
			{
				UserSession session = JsonUtility.FromJson<UserSession>(EncryptionUtils.Decrypt(stored, GetKey()));
				return session != null && session.IsValid ? session : null;
			}
			catch (Exception ex)
			{
				Debug.LogWarningFormat("Could not read the Avatar SDK Move session: {0}", ex.Message);
				DeleteValue(SessionKey);
				return null;
			}
		}

		public static bool HasSession()
		{
			return HasValue(SessionKey);
		}

		public static void StoreSession(UserSession session)
		{
			SaveValue(SessionKey, EncryptionUtils.Encrypt(JsonUtility.ToJson(session), GetKey()));
			SessionChanged?.Invoke();
		}

		public static void ClearSession()
		{
			DeleteValue(SessionKey);
			SessionChanged?.Invoke();
		}

		internal static void RaiseSessionChanged()
		{
			SessionChanged?.Invoke();
		}

#if UNITY_EDITOR
		private static string LoadValue(string key)
		{
			return EditorPrefs.GetString(key, string.Empty);
		}

		private static bool HasValue(string key)
		{
			return EditorPrefs.HasKey(key);
		}

		private static void SaveValue(string key, string value)
		{
			EditorPrefs.SetString(key, value);
		}

		private static void DeleteValue(string key)
		{
			EditorPrefs.DeleteKey(key);
		}

		public static void StoreClientCredentials(ClientCredentials credentials)
		{
			var distraction = new StringBuilder();
			for (int i = 0; i < DistractionTokensCount; ++i)
				distraction.Append(Guid.NewGuid());

			string text = string.Format("{0} {1} {2}", credentials.clientId, credentials.clientSecret, distraction);
			text = Convert.ToBase64String(Encoding.UTF8.GetBytes(text));

			Directory.CreateDirectory(AvatarSDKMoveSettings.ClientResourcesFolder);
			string path = Path.Combine(AvatarSDKMoveSettings.ClientResourcesFolder, AvatarSDKMoveSettings.ClientResourceName + ".txt");
			File.WriteAllText(path, EncryptionUtils.Encrypt(text, GetKey()));

			AssetDatabase.SaveAssets();
			AssetDatabase.Refresh();
		}
#else
		private static string LoadValue(string key)
		{
			return PlayerPrefs.GetString(key, string.Empty);
		}

		private static bool HasValue(string key)
		{
			return PlayerPrefs.HasKey(key);
		}

		private static void SaveValue(string key, string value)
		{
			PlayerPrefs.SetString(key, value);
			PlayerPrefs.Save();
		}

		private static void DeleteValue(string key)
		{
			PlayerPrefs.DeleteKey(key);
			PlayerPrefs.Save();
		}
#endif
	}
}
