#include <maps/wikimap/mapspro/services/mrc/eye/experiments/signs_map/lib/datasets/include/objects.h>

#include <maps/wikimap/mapspro/services/mrc/libs/yt/include/serialization.h>

namespace maps::mrc::eye::datasets {

namespace {

static constexpr const char* FEATURE_ID = "feature_id";
static constexpr const char* OBJECTS = "objects";
static constexpr const char* TYPE = "type";
static constexpr const char* BBOX = "bbox";
static constexpr const char* OBJECT_ID = "object_id";

} // namespace

bool operator==(const Object& lhs, const Object& rhs) {
    return std::tuple(lhs.objectId, lhs.bbox, lhs.type)
        == std::tuple(rhs.objectId, rhs.bbox, rhs.type);
}


template<>
std::tuple<db::TId, Objects> fromJson(const json::Value& item) {
    Objects objects;
    for (const json::Value& objectJson : item[OBJECTS]) {
        objects.push_back({
            objectJson[OBJECT_ID].as<db::TId>(),
            common::ImageBox::fromJson(objectJson[BBOX]),
            traffic_signs::stringToTrafficSign(objectJson[TYPE].as<std::string>())
        });
    };

    return {
        item[FEATURE_ID].as<db::TId>(),
        std::move(objects)
    };
}
template<>
json::Value toJson(const db::TId& featureId, const Objects& objects) {
    std::vector<json::Value> objectsJson;
    for (const auto& object : objects) {
        json::repr::ObjectRepr objectContent{
            {OBJECT_ID, json::Value(object.objectId)},
            {BBOX, toJson(object.bbox)},
            {TYPE, json::Value(traffic_signs::toString(object.type))},
        };
        objectsJson.push_back(json::Value(objectContent));
    }

    json::repr::ObjectRepr content{
        {FEATURE_ID, json::Value(featureId)},
        {OBJECTS, json::Value(objectsJson)},
    };

    return json::Value(content);
}

template<>
std::tuple<db::TId, Objects> fromNode(const NYT::TNode& node) {
    Objects objects;
    for (const NYT::TNode& objectNode : node[OBJECTS].AsList()) {
        objects.push_back({
            objectNode[OBJECT_ID].AsInt64(),
            yt::deserialize<common::ImageBox>(objectNode[BBOX]),
            traffic_signs::stringToTrafficSign(objectNode[TYPE].AsString())
        });
    }

    return {
        node[FEATURE_ID].AsInt64(),
        std::move(objects)
    };
}
template<>
NYT::TNode toNode(const db::TId& featureId, const Objects& objects) {
    NYT::TNode objectsNode = NYT::TNode::CreateList();
    for (const auto& object : objects) {
        objectsNode.Add(
            NYT::TNode()
            (OBJECT_ID, object.objectId)
            (BBOX, yt::serialize(object.bbox))
            (TYPE, TString(traffic_signs::toString(object.type)))
        );
    }
    return NYT::TNode()
        (FEATURE_ID, featureId)
        (OBJECTS, objectsNode);
}


const NYT::TNode ObjectYTSchemaWrap::SCHEMA = NYT::TTableSchema()
    .AddColumn(FEATURE_ID, NYT::EValueType::VT_INT64)
    .AddColumn(OBJECTS, NYT::EValueType::VT_ANY).ToNode();

} // namespace maps::mrc::eye::datasets
