#include <maps/wikimap/mapspro/tools/ymapsdf-conversion/shp2ymapsdf/database.h>

#include <maps/libs/ymapsdf/include/ad.h>

#include <maps/libs/common/include/exception.h>
#include <maps/libs/log8/include/log8.h>
#include <yandex/maps/wiki/common/string_utils.h>

namespace maps::wiki::shp2ymapsdf {

Database::Database(
        const std::string& connStr,
        const std::string& srcSchema,
        const std::string& dstSchema)
    : srcSchema_(srcSchema)
    , dstSchema_(dstSchema)
    , connR_(connStr)
    , workR_(connR_)
    , connW_(connStr)
    , workW_(connW_)
{
    workR_.exec("SET search_path=" + srcSchema_ + ",public");
    workW_.exec("SET search_path=" + dstSchema_ + ",public");
}

pqxx::result Database::read(
    const Query& query,
    const std::string& context,
    const std::string& groupKey)
{
    INFO() << "Loading " << context << " ...";

    auto queryStr = query.str();
    if (!groupKey.empty()) {
        queryStr += " ORDER BY " + groupKey;
    }
    auto rows = workR_.exec(queryStr);
    INFO() << "Loaded " << context << " : " << rows.size();
    return rows;
}

void Database::write(const Query& query)
{
    const size_t WRITE_BUFFER_MAX_SIZE = 1000;
        writeBuffer_.emplace_back(query.str());
    if (writeBuffer_.size() >= WRITE_BUFFER_MAX_SIZE) {
        flush();
    }
}

Id Database::maxId(const std::string& table, std::string key)
{
    if (key.empty()) {
        key = table + "_id";
    }
    flush();

    auto rows = workW_.exec("SELECT MAX(" + key + ") FROM " + table);
    return rows[0][0].as<Id>(0);
}

Id Database::countryId()
{
    flush();

    auto query = Query()
        .select("ad_id")
        .from("ad")
        .where(Query()
            << "level_kind=" << static_cast<uint32_t>(ymapsdf::ad::LevelKind::Country));

    auto rows = workW_.exec(query.str());
    ASSERT(rows.size() <= 1);
    return rows.empty() ? 0 : rows[0][0].as<Id>(0);
}

void Database::commit()
{
    flush();
    workW_.commit();
}

std::string Database::quote(const std::string& str) const
{
    return workW_.quote(str);
}

std::string Database::toGeom(const std::string& wkb) const
{
    return "ST_SetSRID(ST_GeomFromWkb('" + workW_.esc_raw(wkb) + "'),4326)";
}

void Database::flush()
{
    if (!writeBuffer_.empty()) {
        workW_.exec(maps::wiki::common::join(writeBuffer_, ';'));
        writeBuffer_.clear();
    }
}

} // namespace maps::wiki::shp2ymapsdf
