#include "Packet.hpp"

#include <stdexcept>

#include "SecurityMode.hpp"
#include "utils/serialize/basics.hpp"


namespace drp::packet::base {


Packet::Packet() = default;

Packet::Packet(const std::uint8_t channel, const SecurityMode securityMode, const std::vector<uint8_t>& content) {
    this->channel = channel;
    this->securityMode = securityMode;
    this->content = content;
}


PacketContent Packet::getContent(const Context& context) const {
    std::vector<std::uint8_t> content;

    switch (this->securityMode) {
        case SecurityMode::PLAIN:
            // copy the content
            content = this->content;
            break;

        case SecurityMode::AES:
            // decrypt the content
            content = context.cryptoAesKey.decrypt(this->content);
            break;

        case SecurityMode::RSA:
            throw std::runtime_error("Not implemented.");

        default:
            throw std::runtime_error("Unsupported security mode.");
    }

    // deserialize the content
    return PacketContent::deserialize(content);
}


void Packet::setContent(const Context& context, const SecurityMode securityMode, const PacketContent& packetContent) {
    this->securityMode = securityMode;

    const std::vector<std::uint8_t> content = packetContent.serialize();

    switch (this->securityMode) {
        case SecurityMode::PLAIN:
            // directly save the serialized content
            this->content = content;
            break;

        case SecurityMode::AES:
            // encrypt it with the defined AES key.
            this->content = context.cryptoAesKey.encrypt(content);
            break;

        case SecurityMode::RSA:
            throw std::runtime_error("Not implemented.");

        default:
            throw std::runtime_error("Unsupported security mode.");
    }
}


std::vector<std::uint8_t> Packet::serialize() const {
    // serialize the members
    const auto serializedChannel = util::serialize::serializeObject(this->channel);
    const auto serializedSecurityMode = util::serialize::serializeObject(static_cast<std::uint8_t>(this->securityMode));
    const auto serializedContent = util::serialize::serializeVector(this->content);

    // create a buffer to store our members
    std::vector<std::uint8_t> data;

    // store our members
    data.insert(data.end(), serializedChannel.begin(), serializedChannel.end());
    data.insert(data.end(), serializedSecurityMode.begin(), serializedSecurityMode.end());
    data.insert(data.end(), serializedContent.begin(), serializedContent.end());

    return data;
}

Packet Packet::deserialize(std::vector<std::uint8_t>& data) {
    // deserialize the members
    const auto packetChannel = util::serialize::deserializeObject<std::uint8_t>(data);
    const auto packetSecurityMode = static_cast<SecurityMode>(util::serialize::deserializeObject<std::uint8_t>(data));
    const auto packetContent = util::serialize::deserializeVector<std::uint8_t>(data);

    return Packet(packetChannel, packetSecurityMode, packetContent);
}


}
