using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace AxCopilot.Services;

public static class CryptoService
{
	private static readonly byte[] AppSeed = new byte[32]
	{
		65, 88, 45, 67, 111, 109, 109, 97, 110, 100,
		101, 114, 45, 75, 101, 121, 45, 48, 49, 48,
		52, 45, 115, 106, 46, 98, 97, 101, 99, 107,
		167, 92
	};

	private static readonly byte[] AppSalt = new byte[16]
	{
		88, 67, 77, 68, 83, 97, 108, 116, 158, 39,
		193, 74, 179, 6, 127, 216
	};

	private static byte[]? _appKey;

	private static byte[] GetAppKey()
	{
		if (_appKey != null)
		{
			return _appKey;
		}
		using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(AppSeed, AppSalt, 100000, HashAlgorithmName.SHA256);
		_appKey = rfc2898DeriveBytes.GetBytes(32);
		return _appKey;
	}

	public static string PortableEncrypt(string plainText)
	{
		if (string.IsNullOrEmpty(plainText))
		{
			return "";
		}
		byte[] appKey = GetAppKey();
		using Aes aes = Aes.Create();
		aes.Key = appKey;
		aes.Mode = CipherMode.CBC;
		aes.Padding = PaddingMode.PKCS7;
		aes.GenerateIV();
		using ICryptoTransform cryptoTransform = aes.CreateEncryptor();
		byte[] bytes = Encoding.UTF8.GetBytes(plainText);
		byte[] array = cryptoTransform.TransformFinalBlock(bytes, 0, bytes.Length);
		byte[] array2 = new byte[16 + array.Length];
		Buffer.BlockCopy(aes.IV, 0, array2, 0, 16);
		Buffer.BlockCopy(array, 0, array2, 16, array.Length);
		return Convert.ToBase64String(array2);
	}

	public static string PortableDecrypt(string base64)
	{
		if (string.IsNullOrEmpty(base64))
		{
			return "";
		}
		try
		{
			byte[] array = Convert.FromBase64String(base64);
			if (array.Length < 17)
			{
				return "";
			}
			byte[] appKey = GetAppKey();
			byte[] array2 = new byte[16];
			Buffer.BlockCopy(array, 0, array2, 0, 16);
			byte[] array3 = new byte[array.Length - 16];
			Buffer.BlockCopy(array, 16, array3, 0, array3.Length);
			using Aes aes = Aes.Create();
			aes.Key = appKey;
			aes.IV = array2;
			aes.Mode = CipherMode.CBC;
			aes.Padding = PaddingMode.PKCS7;
			using ICryptoTransform cryptoTransform = aes.CreateDecryptor();
			byte[] bytes = cryptoTransform.TransformFinalBlock(array3, 0, array3.Length);
			return Encoding.UTF8.GetString(bytes);
		}
		catch
		{
			return "";
		}
	}

	public static string EncryptIfEnabled(string plainText, bool encryptionEnabled)
	{
		return encryptionEnabled ? PortableEncrypt(plainText) : plainText;
	}

	public static string DecryptIfEnabled(string value, bool encryptionEnabled)
	{
		if (string.IsNullOrEmpty(value))
		{
			return "";
		}
		if (!encryptionEnabled)
		{
			return value;
		}
		string text = PortableDecrypt(value);
		return string.IsNullOrEmpty(text) ? value : text;
	}

	private static byte[] GetOrCreateMasterKey()
	{
		string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot");
		string path = Path.Combine(text, ".master_key");
		if (File.Exists(path))
		{
			byte[] encryptedData = File.ReadAllBytes(path);
			return ProtectedData.Unprotect(encryptedData, null, DataProtectionScope.CurrentUser);
		}
		byte[] bytes = RandomNumberGenerator.GetBytes(32);
		Directory.CreateDirectory(text);
		File.WriteAllBytes(path, ProtectedData.Protect(bytes, null, DataProtectionScope.CurrentUser));
		return bytes;
	}

	public static byte[] EncryptBytes(byte[] plainBytes)
	{
		byte[] orCreateMasterKey = GetOrCreateMasterKey();
		byte[] bytes = RandomNumberGenerator.GetBytes(12);
		byte[] array = new byte[16];
		byte[] array2 = new byte[plainBytes.Length];
		using AesGcm aesGcm = new AesGcm(orCreateMasterKey, 16);
		aesGcm.Encrypt(bytes, plainBytes, array2, array);
		byte[] array3 = new byte[28 + array2.Length];
		Buffer.BlockCopy(bytes, 0, array3, 0, 12);
		Buffer.BlockCopy(array, 0, array3, 12, 16);
		Buffer.BlockCopy(array2, 0, array3, 28, array2.Length);
		return array3;
	}

	public static byte[] DecryptBytes(byte[] encrypted)
	{
		if (encrypted.Length < 28)
		{
			throw new CryptographicException("Invalid encrypted data");
		}
		byte[] orCreateMasterKey = GetOrCreateMasterKey();
		byte[] array = new byte[12];
		byte[] array2 = new byte[16];
		byte[] array3 = new byte[encrypted.Length - 28];
		Buffer.BlockCopy(encrypted, 0, array, 0, 12);
		Buffer.BlockCopy(encrypted, 12, array2, 0, 16);
		Buffer.BlockCopy(encrypted, 28, array3, 0, array3.Length);
		byte[] array4 = new byte[array3.Length];
		using AesGcm aesGcm = new AesGcm(orCreateMasterKey, 16);
		aesGcm.Decrypt(array, array3, array2, array4);
		return array4;
	}

	public static void EncryptToFile(string filePath, string content)
	{
		byte[] bytes = Encoding.UTF8.GetBytes(content);
		byte[] bytes2 = EncryptBytes(bytes);
		File.WriteAllBytes(filePath, bytes2);
	}

	public static string DecryptFromFile(string filePath)
	{
		if (!File.Exists(filePath))
		{
			return "";
		}
		byte[] encrypted = File.ReadAllBytes(filePath);
		byte[] bytes = DecryptBytes(encrypted);
		return Encoding.UTF8.GetString(bytes);
	}
}
