//
// Created by Dan Crosby on 10/23/22.
//

#ifndef EAGLE0_SHARDOK_LIBRARY_UTIL_ACTION_RESULT_FLATBUFFER_HELPERS_HPP
#define EAGLE0_SHARDOK_LIBRARY_UTIL_ACTION_RESULT_FLATBUFFER_HELPERS_HPP

#include <cstring>
#include <stdexcept>
#include <string>
#include <type_traits>

#include "src/main/flatbuffer/net/eagle0/shardok/storage/unit.hpp"
#include "src/main/protobuf/net/eagle0/shardok/storage/action_result.pb.h"

namespace shardok {

using ActionResult = net::eagle0::shardok::storage::ActionResult;
using ResolvedUnit = net::eagle0::shardok::storage::ResolvedUnit;
using Unit = net::eagle0::shardok::storage::fb::Unit;

static_assert(std::is_trivially_copyable_v<Unit>);

[[nodiscard]] static inline auto UnitToBytes(const Unit& unit) -> std::string {
    std::string bytes(sizeof(Unit), '\0');
    std::memcpy(bytes.data(), &unit, sizeof(Unit));
    return bytes;
}

[[nodiscard]] static inline auto UnitFromBytes(const std::string& unitBytes) -> Unit {
    if (unitBytes.size() != sizeof(Unit)) {
        throw std::invalid_argument("Unexpected unit byte length");
    }

    Unit unit{};
    std::memcpy(&unit, unitBytes.data(), sizeof(Unit));
    return unit;
}

static inline void AddChangedUnit(ActionResult& result, const Unit& unit) {
    result.add_changed_units_fb(&unit, sizeof(Unit));
}

static inline void AddUnitToResolved(ResolvedUnit& resolvedUnit, const Unit& unit) {
    *resolvedUnit.mutable_unit_bytes() = UnitToBytes(unit);
}

}  // namespace shardok

#endif  // EAGLE0_SHARDOK_LIBRARY_UTIL_ACTION_RESULT_FLATBUFFER_HELPERS_HPP
