#include <maps/wikimap/mapspro/libs/misc_point_to_indoor/include/point_to_indoor.h>

#include <yandex/maps/wiki/common/geom_utils.h>
#include <yandex/maps/wiki/revision/common.h>
#include <maps/wikimap/mapspro/libs/views/include/query_builder.h>

#include <maps/libs/geolib/include/conversion.h>
#include <maps/libs/geolib/include/distance.h>

namespace maps::wiki::misc {

std::optional<revision::DBID> getIndoorObjectId(
    pqxx::transaction_base& viewTxn,
    revision::DBID branchId,
    const geolib3::Point2& mercPoint,
    double searchRadiusInMeters,
    const std::string& universalIndoorLevelId)
{
    views::QueryBuilder qb(branchId);

    qb.selectFields(
        "ST_Distance(ST_GeomFromWKB($1, 3395), ST_Boundary(area_objects.the_geom)) as distance, "
        "area_objects.id as indoor_id");
    qb.fromTable(views::TABLE_OBJECTS_A, "area_objects");
    qb.whereClause(
        " area_objects.domain_attrs ? 'cat:indoor_level' "
        " AND ST_DWithin(ST_GeomFromWKB($1, 3395), area_objects.the_geom, $2) "
        " AND area_objects.domain_attrs -> 'indoor_level:universal' = $3 ");

    const auto query = qb.query() +
        " ORDER BY distance ASC "
        " LIMIT 1";

    const auto ratio = geolib3::MercatorRatio::fromMercatorPoint(mercPoint);
    const auto rows = viewTxn.exec_params(
        query,
        pqxx::binarystring{geolib3::WKB::toString(mercPoint)},
        ratio.toMercatorUnits(searchRadiusInMeters),
        universalIndoorLevelId);

    if (rows.empty()) {
        return std::nullopt;
    }
    return rows.front()["indoor_id"].as<revision::DBID>();
}

} // namespace maps::wiki::misc
