#include <iostream>
#include <vector>

#include "Peer.hpp"
#include "utils/crypto/aes/AesKey.hpp"
#include "utils/crypto/rsa/RsaKeyPair.hpp"
#include "utils/serialize/basics.hpp"


int mainAes() {
    const auto aesKey = drp::util::crypto::AesKey256();

    // plain
    std::string text = "hello world!";
    const std::vector<std::uint8_t> plainData(text.begin(), text.end());
    std::cout << "plain: ";
    for (const auto& byte : plainData)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    // encrypted
    const auto encryptedData = aesKey.encrypt(plainData);
    std::cout << "encrypted: ";
    for (const auto& byte : encryptedData)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    // decrypted
    const auto decryptedData = aesKey.decrypt(encryptedData);
    std::cout << "decrypted: ";
    for (const auto& byte : decryptedData)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    return 0;
}


int mainRsa() {
    const auto rsaKey = drp::util::crypto::RsaKeyPair(2048);
    const auto rsaPrivateKey = rsaKey.getPrivateKey();
    const auto rsaPublicKey = rsaKey.getPublicKey();

    // plain
    std::string text = "hello world!";
    const std::vector<std::uint8_t> plainData(text.begin(), text.end());
    std::cout << "plain: ";
    for (const auto& byte : plainData)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    // encrypted
    const auto encryptedData = rsaPublicKey.encrypt(plainData);
    std::cout << "encrypted: ";
    for (const auto& byte : encryptedData)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    // decrypted
    const auto decryptedData = rsaPrivateKey.decrypt(encryptedData);
    std::cout << "decrypted: ";
    for (const auto& byte : decryptedData)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    return 0;
}


int mainSerialize() {
    std::string text = "hello world!";
    const std::vector<char> plainData(text.begin(), text.end());

    std::cout << "plain: ";
    for (const auto& byte : plainData)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    std::vector<std::uint8_t> serializedData = drp::util::serialize::serializeVector(plainData);

    std::cout << "serialized: ";
    for (const auto& byte : serializedData)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    std::vector<char> deserializedData = drp::util::serialize::deserializeVector<char>(serializedData);

    std::cout << "deserialized: ";
    for (const auto& byte : deserializedData)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    return 0;
}


int mainRsaSerialize() {
    // create a key pair
    drp::util::crypto::RsaKeyPair keyPair(2048);

    // create an object
    Peer peer;
    peer.channel = 7;
    peer.id = 253;

    // serialize it
    auto serializedPeer = peer.serialize();

    std::cout << "serialized: ";
    for (const auto& byte : serializedPeer)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    // encrypt it
    const std::vector<std::uint8_t> encryptedSerializedPeer = keyPair.getPublicKey().encrypt(serializedPeer);

    std::cout << "encrypted: ";
    for (const auto& byte : encryptedSerializedPeer)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    // decrypt it
    std::vector<std::uint8_t> decryptedSerializedPeer = keyPair.getPrivateKey().decrypt(encryptedSerializedPeer);

    std::cout << "decrypted: ";
    for (const auto& byte : decryptedSerializedPeer)
        std::cout << std::to_string(byte) << "-";
    std::cout << std::endl;

    const auto deserializedPeer = Peer::deserialize(decryptedSerializedPeer);

    std::cout << "peer id: " << std::to_string(deserializedPeer.id) << std::endl;
    std::cout << "peer channel: " << std::to_string(deserializedPeer.channel) << std::endl;

    return 0;
}


int main_test() {
    // mainAes();
    // mainRsa();
    // mainSerialize();
    mainRsaSerialize();

    return 0;
}