#include <maps/wikimap/mapspro/libs/common/include/yandex/maps/wiki/common/aoi.h>
#include <maps/libs/geolib/include/serialization.h>
#include <yandex/maps/wiki/common/string_utils.h>

#include <boost/range/adaptor/map.hpp>
#include <map>
#include <sstream>

namespace maps::wiki::common {

namespace {

template<typename Geom>
std::string geomMercToQueryValue(
    const Geom& geomMerc,
    pqxx::transaction_base& txn)
{
    return
        "ST_GeomFromWkb('" +
        txn.esc_raw(geolib3::WKB::toString(geomMerc)) +
        "', 3395)";
}

} // anonymous namespace

std::set<uint64_t> calculateAoisContainingPosition(
    const geolib3::Point2& positionMerc,
    pqxx::transaction_base& viewTrunkTxn)
{
    std::stringstream query;

    query <<
        " SELECT id" <<
        " FROM vrevisions_trunk.objects_a" <<
        " WHERE ST_Contains(" <<
             "the_geom," <<
             geomMercToQueryValue(positionMerc, viewTrunkTxn) <<
        " )" <<
        " AND domain_attrs ? 'cat:aoi'";

    std::set<uint64_t> aoiIds;
    for (const auto& row : viewTrunkTxn.exec(query.str())) {
        aoiIds.insert(row["id"].as<uint64_t>());
    }
    return aoiIds;
}

void addAoiRegionToViewTrunk(
    const AoiParams& aoiParams,
    pqxx::transaction_base& viewTrunkTxn)
{
    std::map<std::string, std::string> columnToVal;

    std::map<std::string, std::string> domainAttrs = {
        {"cat:aoi", "1"},
        {"aoi:name", aoiParams.name},
        {"aoi:type", std::to_string(aoiParams.type)}
    };

    columnToVal["id"] = std::to_string(aoiParams.aoiId);
    columnToVal["commit_id"] = std::to_string(aoiParams.commitId);
    columnToVal["the_geom"] = geomMercToQueryValue(aoiParams.polygonMerc, viewTrunkTxn);

    columnToVal["domain_attrs"] = viewTrunkTxn.quote(
        common::join(
            domainAttrs,
            [](const auto& keyVal) {
                return R"(")" + keyVal.first + R"("=>")" + keyVal.second + R"(")";
            },
            ","
        )
    );

    columnToVal["area"] = std::to_string(aoiParams.area);

    std::stringstream query;
    query <<
        " INSERT INTO vrevisions_trunk.objects_a" <<
        " (" << common::join(boost::adaptors::keys(columnToVal), ',') << ")" <<
        " VALUES (" << common::join(boost::adaptors::values(columnToVal), ',') << ") ";

    viewTrunkTxn.exec("SET search_path=vrevisions_trunk,public");
    viewTrunkTxn.exec(query.str());
    viewTrunkTxn.exec("SET search_path=public");
}

} // namespace maps::wiki::common
