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

class Program(string passwordPrompt, string embeddedResourceName)
{
	static void Main(string[] args)
	{
		Program program = new("Enter password: ", "encrypted.payload");
		program.ExtractCompressedEncryptedPayload();
	}

	void ExtractCompressedEncryptedPayload()
	{
		Console.Write(passwordPrompt);
		string? password = Console.ReadLine();
		if (string.IsNullOrEmpty(password)) return;

		using Stream? resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedResourceName);
		if (resourceStream == null)
		{
			Console.WriteLine("Resource niet gevonden. Beschikbare resources:");
			foreach (var name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
			{
				Console.WriteLine(name);
			}
			return;
		}

		// Read FileName
		byte[]? fileNameLengthBytes = new byte[4];
		resourceStream.Read(fileNameLengthBytes, 0, fileNameLengthBytes.Length);
		int fileNameLength = BitConverter.ToInt32(fileNameLengthBytes, 0);
		byte[]? fileNameBytes = new byte[fileNameLength];
		resourceStream.Read(fileNameBytes, 0, fileNameLength);
		string? fileName = Encoding.UTF8.GetString(fileNameBytes);

		// Read salt and encrypted data
		byte[]? salt = new byte[16];
		resourceStream.Read(salt, 0, salt.Length);

		byte[]? encryptedData = new byte[resourceStream.Length - resourceStream.Position];
		resourceStream.Read(encryptedData, 0, encryptedData.Length);

		using Rfc2898DeriveBytes? keyDeriver = new(password, salt, 100000, HashAlgorithmName.SHA256);
		byte[]? key = keyDeriver.GetBytes(32);
		byte[]? iv = keyDeriver.GetBytes(16);

		using Aes? aes = Aes.Create();
		aes.Key = key;
		aes.IV = iv;

		// Decrypt
		using MemoryStream? decryptedStream = new();
		using (CryptoStream? cs = new(decryptedStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
		{
			cs.Write(encryptedData, 0, encryptedData.Length);
			cs.FlushFinalBlock();
		}

		// Decompress
		byte[]? compressedData = decryptedStream.ToArray();
		using MemoryStream? compressedStream = new(compressedData);
		using MemoryStream? decompressedStream = new();
		using (GZipStream? gzip = new(compressedStream, CompressionMode.Decompress))
		{
			gzip.CopyTo(decompressedStream);
		}

		byte[]? decompressed = decompressedStream.ToArray();

		string? outputPath = fileName; // Usee original filename
		File.WriteAllBytes(outputPath, decompressed);

		Console.WriteLine($"Saved to: {outputPath}");
	}
}