#include <array>
#include <catch2/catch_test_macros.hpp>

#include "fsfw/cfdp/handler/PutRequest.h"
#include "fsfw/cfdp/tlv/ReservedMessageCreator.h"

TEST_CASE("Put Request", "[cfdp]") {
  using namespace cfdp;
  using namespace returnvalue;

  std::array<uint8_t, 32> reservedMsgCustomData{};
  std::array<uint8_t, 128> reservedMsgBuf{};
  std::array<uint8_t, 128> buffer{};
  EntityId destId(WidthInBytes::ONE_BYTE, 5);
  std::string srcFileName = "hello.txt";
  std::string destFileName = "hello2.txt";
  uint8_t* msgBufPtr = reservedMsgCustomData.data();
  size_t msgSize = 0;
  cfdp::StringLv srcName(srcFileName);
  cfdp::StringLv destName(destFileName);
  CHECK(destId.serializeAsLv(&msgBufPtr, &msgSize, reservedMsgCustomData.size()) == OK);
  CHECK(srcName.serialize(&msgBufPtr, &msgSize, reservedMsgCustomData.size(),
                          SerializeIF::Endianness::NETWORK) == OK);
  CHECK(destName.serialize(&msgBufPtr, &msgSize, reservedMsgCustomData.size(),
                           SerializeIF::Endianness::NETWORK) == OK);
  ReservedMessageCreator creator(static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST),
                                 reservedMsgCustomData.data(), msgSize);
  msgSize = 0;
  ReturnValue_t result = creator.serializeBe(reservedMsgBuf.data(), msgSize, buffer.size());
  CHECK(result == returnvalue::OK);

  SECTION("Put Request with reserved message") {
    PutRequest putRequest(destId, reservedMsgBuf.data(), msgSize, nullptr, 0);
    uint8_t* bufPtr = buffer.data();
    size_t serLen = 0;
    REQUIRE(putRequest.serialize(&bufPtr, &serLen, buffer.size(),
                                 SerializeIF::Endianness::NETWORK) == OK);

    CHECK(putRequest.getSerializedSize() == serLen);
    PutRequest requestDeserialized;
    size_t deserLen = putRequest.getSerializedSize();
    const uint8_t* deserPtr = buffer.data();
    REQUIRE(requestDeserialized.deSerialize(&deserPtr, &deserLen,
                                            SerializeIF::Endianness::NETWORK) == OK);
    CHECK(requestDeserialized.getDestId().getWidth() == destId.getWidth());
    CHECK(requestDeserialized.getDestId().getValue() == destId.getValue());
    size_t totalMsgsSize = 0;
    const uint8_t* msgsToUserStart = requestDeserialized.getMessagesToUser(totalMsgsSize);
    CHECK(totalMsgsSize == msgSize);
    cfdp::Tlv genericTlv;
    genericTlv.deSerialize(&msgsToUserStart, &totalMsgsSize, SerializeIF::Endianness::NETWORK);
    CHECK(genericTlv.getType() == TlvType::MSG_TO_USER);
    CHECK(genericTlv.getLengthField() == genericTlv.getSerializedSize() - 2);
    CHECK(genericTlv.getValue()[0] == 'c');
    CHECK(genericTlv.getValue()[1] == 'f');
    CHECK(genericTlv.getValue()[2] == 'd');
    CHECK(genericTlv.getValue()[3] == 'p');
  }
}