#include "Peer.hpp"

#include "behavior/tasks/undefined/UndefinedTask.hpp"
#include "utils/serialize/basics.hpp"


Peer::Peer() = default;


Peer::Peer(const drp::util::crypto::RsaPublicKey& cryptoRsaPublicKey) {
    this->id = randomDistribution(randomGenerator);
    this->channel = 0;
    this->serverEnabled = false;
    this->status = drp::task::TaskType::UNDEFINED;

    this->latencyAverage = std::chrono::high_resolution_clock::duration::max();

    this->cryptoRsaPublicKey = cryptoRsaPublicKey;
}

Peer::Peer(
    std::uint32_t id,
    bool serverEnabled,
    drp::task::TaskType status,
    std::uint8_t channel,
    const std::chrono::high_resolution_clock::duration& latencyAverage,
    const drp::util::crypto::RsaPublicKey& cryptoRsaPublicKey
) {
    this->id = id;
    this->serverEnabled = serverEnabled;
    this->status = status;
    this->channel = channel;
    this->latencyAverage = latencyAverage;
    this->cryptoRsaPublicKey = cryptoRsaPublicKey;
}


std::vector<std::uint8_t> Peer::serialize() const {
    std::vector<std::uint8_t> data;

    // serialized the members
    const auto serializedId = drp::util::serialize::serializeObject<std::uint32_t>(this->id);
    const auto serializedServerEnabled = drp::util::serialize::serializeObject<std::uint8_t>(this->serverEnabled);
    const auto serializedStatus = drp::util::serialize::serializeObject<std::uint8_t>(static_cast<std::uint8_t>(this->status));
    const auto serializedChannel = drp::util::serialize::serializeObject<std::uint8_t>(this->channel);
    const auto serializedLatencyAverage = drp::util::serialize::serializeObject(this->latencyAverage);
    const auto serializedPublicKey = this->cryptoRsaPublicKey.serialize();

    // store them in the data
    data.insert(data.end(), serializedId.begin(), serializedId.end());
    data.insert(data.end(), serializedServerEnabled.begin(), serializedServerEnabled.end());
    data.insert(data.end(), serializedStatus.begin(), serializedStatus.end());
    data.insert(data.end(), serializedChannel.begin(), serializedChannel.end());
    data.insert(data.end(), serializedLatencyAverage.begin(), serializedLatencyAverage.end());
    data.insert(data.end(), serializedPublicKey.begin(), serializedPublicKey.end());

    return data;
}

Peer Peer::deserialize(std::vector<std::uint8_t>& data) {
    // deserialize the members
    const auto id = drp::util::serialize::deserializeObject<std::uint32_t>(data);
    const auto serverEnabled = drp::util::serialize::deserializeObject<std::uint8_t>(data);
    const auto status = static_cast<drp::task::TaskType>(drp::util::serialize::deserializeObject<std::uint8_t>(data));
    const auto channel = drp::util::serialize::deserializeObject<std::uint8_t>(data);
    const auto latencyAverage = drp::util::serialize::deserializeObject<std::chrono::high_resolution_clock::duration>(data);
    const auto publicKey = drp::util::crypto::RsaPublicKey::deserialize(data);

    return Peer(id, serverEnabled, status, channel, latencyAverage, publicKey);
}


std::mt19937 Peer::randomGenerator = std::mt19937(std::random_device{}());

std::uniform_int_distribution<std::uint32_t> Peer::randomDistribution = std::uniform_int_distribution(
    std::numeric_limits<std::uint32_t>::min(),
    std::numeric_limits<std::uint32_t>::max()
);