/* 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 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()
		{
			try
			{
				var asset = Resources.Load<TextAsset>(AvatarSDKMoveSettings.CredentialsResourceName);
				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 UserSession(tokens[0], tokens[1], tokens[2]);
			}
			catch (Exception ex)
			{
				Debug.LogFormat("Could not load the Avatar SDK Move session: {0}", ex.Message);
				return null;
			}
		}

		public static bool HasSession()
		{
			UserSession session = LoadSession();
			return session != null && session.IsValid;
		}

		public static UserSession LoadCurrentSession()
		{
			UserSession session = LoadSession();
			if (session == null || !session.IsValid)
				return session;

			UserSession cached = LoadCachedSession(session.email);
			return cached != null && cached.IsValid ? cached : session;
		}

		public static UserSession LoadCachedSession(string email)
		{
			try
			{
				string path = GetCachedSessionPath(email);
				if (!File.Exists(path))
					return null;

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

				string[] tokens = text.Split(' ');
				return new UserSession(tokens[0], tokens[1], tokens[2]);
			}
			catch (Exception ex)
			{
				Debug.LogWarningFormat("Could not read the cached Avatar SDK Move session: {0}", ex.Message);
				return null;
			}
		}

		public static void StoreCachedSession(UserSession session)
		{
			try
			{
				string text = string.Format("{0} {1} {2}", session.email, session.token, session.refreshToken);
				text = Convert.ToBase64String(Encoding.UTF8.GetBytes(text));
				File.WriteAllText(GetCachedSessionPath(session.email), EncryptionUtils.Encrypt(text, GetKey()));
			}
			catch (Exception ex)
			{
				Debug.LogWarningFormat("Could not cache the Avatar SDK Move session: {0}", ex.Message);
			}
		}

		public static void ClearCachedSession(string email)
		{
			try
			{
				string path = GetCachedSessionPath(email);
				if (File.Exists(path))
					File.Delete(path);
			}
			catch (Exception ex)
			{
				Debug.LogWarningFormat("Could not clear the cached Avatar SDK Move session: {0}", ex.Message);
			}
		}

		private static string GetCachedSessionPath(string email)
		{
			string filename = string.Format("session_{0}.dat", EncryptionUtils.GetMd5Hash(email));
			return Path.Combine(Application.persistentDataPath, filename);
		}

#if UNITY_EDITOR
		public static void StoreSession(UserSession session)
		{
			Store(AvatarSDKMoveSettings.CredentialsResourcesFolder, AvatarSDKMoveSettings.CredentialsResourceName,
				session.email, session.token, session.refreshToken);

			StoreCachedSession(session);
		}

		public static void ClearSession()
		{
			UserSession session = LoadSession();
			if (session != null && !string.IsNullOrEmpty(session.email))
				ClearCachedSession(session.email);

			string path = Path.Combine(AvatarSDKMoveSettings.CredentialsResourcesFolder, AvatarSDKMoveSettings.CredentialsResourceName + ".txt");
			if (File.Exists(path))
				AssetDatabase.DeleteAsset(path);

			Resources.UnloadUnusedAssets();
			AssetDatabase.Refresh();
		}

		public static void StoreClientCredentials(ClientCredentials credentials)
		{
			Store(AvatarSDKMoveSettings.ClientResourcesFolder, AvatarSDKMoveSettings.ClientResourceName,
				credentials.clientId, credentials.clientSecret);
		}

		private static void Store(string folder, string resourceName, params string[] values)
		{
			var distraction = new StringBuilder();
			for (int i = 0; i < DistractionTokensCount; ++i)
				distraction.Append(Guid.NewGuid());

			string text = string.Format("{0} {1}", string.Join(" ", values), distraction);
			text = Convert.ToBase64String(Encoding.UTF8.GetBytes(text));

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

			AssetDatabase.SaveAssets();
			AssetDatabase.Refresh();
		}
#endif
	}
}
