#include <maps/wikimap/mapspro/libs/query_builder/include/update_query.h>

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

namespace maps::wiki::query_builder {

namespace internal {

std::string buildUpdateQuery(
    const pqxx::transaction_base& txn,
    const std::string& table,
    const std::map<std::string, QuotedValue>& keyValues,
    const std::map<std::string, JsonbEntry>& jsonbEntries,
    const WhereConditions& whereConditions,
    const std::vector<std::string>& returning)
{
    REQUIRE(
        !keyValues.empty(),
        "Cannot build empty update query for table " << table);

    std::ostringstream query;
    query << "UPDATE " << table << " SET " << maps::wiki::common::join(
        keyValues,
        [&txn](const std::pair<std::string, QuotedValue>& entry) {
            return entry.first + " = " + entry.second.quote(txn);
        },
        ", "
    );
    if (!jsonbEntries.empty()) {
        query << ", " << maps::wiki::common::join(
            jsonbEntries,
            [&txn](const std::pair<std::string, JsonbEntry>& entry) {
                return entry.first + " = " + makeJsonbSetExpression(txn, entry.first, entry.second);
            },
            ", "
        );
    }
    auto where = whereConditions.asString(txn);
    if (!where.empty()) {
        query << ' ' << where;
    }

    if (returning.size()) {
        query << " RETURNING " << maps::wiki::common::join(returning, ", ");
    }

    return query.str();
}

} // namespace internal

UpdateQuery::UpdateQuery(
    std::string table, WhereConditions whereConditions)
    : ModifyQuery(std::move(table))
    , whereConditions_(std::move(whereConditions))
{}

std::string UpdateQuery::asString(const pqxx::transaction_base& txn) const
{
    return internal::buildUpdateQuery(
        txn, table_, data_.keyValues(), data_.jsonbEntries(), whereConditions_, data_.returning());
}

} // namespace maps::wiki::query_builder
