using Noctalk.Shared.Chat.Encryption;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using ChatMessage = Noctalk.Shared.Chat.Api.Json.Chat_client__to__server.Poll.Message;

namespace Noctalk_client.Client.Chat;

public static class Local_message_crypto
{
    private static readonly JsonSerializerOptions Json_options = new();

    public static ChatMessage Chat__encrypt_text(string The_message_content, Guid Sender_client_guid, long Message_counter, string conversation__local_encryption__key)
    {
        return Chat__encrypt_inner_message(Message_type.Text, The_message_content, Sender_client_guid, Message_counter, conversation__local_encryption__key);
    }

    public static ChatMessage Chat__encrypt_image(string Message_content, Guid Sender_client_guid, long Message_counter, string conversation__local_encryption__key)
    {
        return Chat__encrypt_inner_message(Message_type.Image, Message_content, Sender_client_guid, Message_counter, conversation__local_encryption__key);
    }

    public static ChatMessage Chat__encrypt_clear_history(Guid Sender_client_guid, long Message_counter, string conversation__local_encryption__key)
    {
        return Chat__encrypt_inner_message(Message_type.Clear_history, string.Empty, Sender_client_guid, Message_counter, conversation__local_encryption__key);
    }

    private static ChatMessage Chat__encrypt_inner_message(Message_type Message_type, string The_message_content, Guid Sender_client_guid, long Message_counter, string conversation__local_encryption__key)
    {
        Inner_message innerMessage = new()
        {
            Message_type = Message_type,
            Message_content = The_message_content,
            Sender_client_guid = Sender_client_guid,
            Message_counter = Message_counter,
            Created_utc = DateTime.UtcNow
        };

        byte[] key = Convert.FromBase64String(conversation__local_encryption__key);
        byte[] nonce = RandomNumberGenerator.GetBytes(12);
        byte[] plaintext = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(innerMessage, Json_options));
        byte[] ciphertext = new byte[plaintext.Length];
        byte[] tag = new byte[16];

        using AesGcm aesGcm = new(key, tag.Length);
        aesGcm.Encrypt(nonce, plaintext, ciphertext, tag);

        return new ChatMessage
        {
            Nonce = Convert.ToBase64String(nonce),
            Ciphertext = Convert.ToBase64String(ciphertext.Concat(tag).ToArray())
        };
    }

    public static Inner_message Chat__decrypt(ChatMessage The_message, string conversation__local_encryption__key)
    {
        byte[] key = Convert.FromBase64String(conversation__local_encryption__key);
        byte[] nonce = Convert.FromBase64String(The_message.Nonce);
        byte[] ciphertextWithTag = Convert.FromBase64String(The_message.Ciphertext);
        byte[] ciphertext = ciphertextWithTag[..^16];
        byte[] tag = ciphertextWithTag[^16..];
        byte[] plaintext = new byte[ciphertext.Length];

        using AesGcm aesGcm = new(key, tag.Length);
        aesGcm.Decrypt(nonce, ciphertext, tag, plaintext);

        return JsonSerializer.Deserialize<Inner_message>(Encoding.UTF8.GetString(plaintext), Json_options) ?? new Inner_message();
    }
}
