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

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

namespace {

static constexpr const char* FEATURE_ID_1 = "feature_id_1";
static constexpr const char* FEATURE_ID_2 = "feature_id_2";
static constexpr const char* MATCHES = "matches";
static constexpr const char* OBJECT_ID_1 = "object_id_1";
static constexpr const char* OBJECT_ID_2 = "object_id_2";

} // namespace

bool operator==(const Match& lhs, const Match& rhs) {
    return std::tuple(lhs.objectId1, lhs.objectId2)
        == std::tuple(rhs.objectId1, rhs.objectId2);
}


template<>
std::tuple<FeatureIdPair, Matches> fromJson(const json::Value& item) {
    Matches matches;
    for (const json::Value& matchJson : item[MATCHES]) {
        matches.push_back({
            matchJson[OBJECT_ID_1].as<db::TId>(),
            matchJson[OBJECT_ID_2].as<db::TId>(),
        });
    };

    return {
        {item[FEATURE_ID_1].as<db::TId>(), item[FEATURE_ID_2].as<db::TId>()},
        std::move(matches)
    };
}
template<>
json::Value toJson(const FeatureIdPair& featureIdPair, const Matches& matches) {
    std::vector<json::Value> matchesJson;
    for (const auto& match : matches) {
        json::repr::ObjectRepr matchContent{
            {OBJECT_ID_1, json::Value(match.objectId1)},
            {OBJECT_ID_2, json::Value(match.objectId2)}
        };
        matchesJson.push_back(json::Value(matchContent));
    }

    json::repr::ObjectRepr content{
        {FEATURE_ID_1, json::Value(featureIdPair.first)},
        {FEATURE_ID_2, json::Value(featureIdPair.second)},
        {MATCHES, json::Value(matchesJson)},
    };

    return json::Value(content);
}

template<>
std::tuple<FeatureIdPair, Matches> fromNode(const NYT::TNode& node) {
    Matches matches;
    for (const NYT::TNode& matchNode : node[MATCHES].AsList()) {
        matches.push_back({
            matchNode[OBJECT_ID_1].AsInt64(),
            matchNode[OBJECT_ID_2].AsInt64(),
        });
    }

    return {
        {node[FEATURE_ID_1].AsInt64(), node[FEATURE_ID_2].AsInt64()},
        std::move(matches)
    };
}
template<>
NYT::TNode toNode(const FeatureIdPair& featureIdPair, const Matches& matches) {
    NYT::TNode matchesNode = NYT::TNode::CreateList();
    for (const auto& match : matches) {
        matchesNode.Add(
            NYT::TNode()
            (OBJECT_ID_1, match.objectId1)
            (OBJECT_ID_2, match.objectId2)
        );
    }
    return NYT::TNode()
        (FEATURE_ID_1, featureIdPair.first)
        (FEATURE_ID_2, featureIdPair.second)
        (MATCHES, matchesNode);
}


const NYT::TNode MatchYTSchemaWrap::SCHEMA = NYT::TTableSchema()
    .AddColumn(FEATURE_ID_1, NYT::EValueType::VT_INT64)
    .AddColumn(FEATURE_ID_2, NYT::EValueType::VT_INT64)
    .AddColumn(MATCHES, NYT::EValueType::VT_ANY).ToNode();

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