#include "entrance.h"

#include <yandex/maps/wiki/revision/revisionsgateway.h>
#include <yandex/maps/wiki/revision/snapshot.h>
#include <maps/libs/common/include/exception.h>

namespace maps::wiki::schedule_feedback {

namespace rf = revision::filters;

namespace {

std::vector<ObjId> entranceIds(
    const geolib3::BoundingBox& bboxMerc,
    const revision::Snapshot& snapshot)
{
    rf::ProxyFilterExpr entranceFilter =
        rf::ObjRevAttr::isNotDeleted() &&
        rf::ObjRevAttr::isNotRelation() &&
        rf::Attr("cat:poi_entrance").defined() &&
        rf::Geom::defined();

    auto areaFilter = rf::GeomFilterExpr(
        rf::GeomFilterExpr::Operation::IntersectsPoints,
        bboxMerc.minX(), bboxMerc.minY(),
        bboxMerc.maxX(), bboxMerc.maxY());

    auto filter = entranceFilter && areaFilter;
    auto entranceRevisionIds = snapshot.revisionIdsByFilter(filter);

    std::vector<ObjId> ids;
    for (const auto& revId : entranceRevisionIds) {
        ids.push_back(revId.objectId());
    }

    return ids;
}

std::set<std::string> entranceNames(
    const std::vector<ObjId>& entranceIds,
    const revision::Snapshot& snapshot)
{
    if (entranceIds.empty()) {
        return {};
    }

    auto entranceSlaveRelations = snapshot.relationsByFilter(
        rf::ObjRevAttr::masterObjectId().in(entranceIds) &&
        rf::ObjRevAttr::isNotDeleted()
    );

    std::vector<ObjId> slaveObjectIds;
    for (const auto& relation : entranceSlaveRelations) {
        ASSERT(relation.data().relationData);
        slaveObjectIds.push_back(relation.data().relationData->slaveObjectId());
    }

    if (slaveObjectIds.empty()) {
        return {};
    }

    auto nameRevs = snapshot.objectRevisionsByFilter(
        rf::ObjRevAttr::objectId().in(slaveObjectIds) &&
        rf::ObjRevAttr::isNotRelation() &&
        rf::ObjRevAttr::isNotDeleted() &&
        rf::Attr("cat:poi_nm").defined() &&
       !rf::Geom::defined());

    std::set<std::string> names;
    for (const auto& nameRev : nameRevs) {
        const auto& attrs = nameRev.data().attributes;
        ASSERT(attrs);
        if (attrs->count("poi_nm:name")) {
            names.insert(attrs->at("poi_nm:name"));
        }
    }
    return names;
}

} // anonymous

std::set<std::string> revisionEntranceNames(
    const geolib3::BoundingBox& bboxMerc,
    pqxx::transaction_base& coreTxn)
{
    revision::RevisionsGateway gtw(coreTxn);
    auto snapshot = gtw.snapshot(gtw.maxSnapshotId());

    return entranceNames(entranceIds(bboxMerc, snapshot), snapshot);
}

} // namespace maps::wiki::schedule_feedback
