#include "db.h"

#include <maps/libs/chrono/include/days.h>
#include <maps/libs/log8/include/log8.h>
#include <maps/libs/sql_chemistry/include/batch_load.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/disqualified_source_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/metadata_gateway.h>

#include <string>

using namespace maps::chrono::literals;

namespace maps::mrc::taxi_stat {

namespace {

const std::string APP_NAME = "taxi_stat";
const std::string LAST_RUN_TIME = APP_NAME + ".timestamp";

void updateBans(const db::DisqualifiedSource& disqSrc,
                chrono::TimePoint now,
                Bans& result)
{
    auto firstDay = std::chrono::floor<chrono::Days>(disqSrc.startedAt());
    auto lastDay = std::chrono::floor<chrono::Days>(
        std::min(now, disqSrc.endedAt().value_or(now)));
    for (; firstDay < lastDay; firstDay += 1_days) {
        ++result[BanKey{.date = firstDay, .disqType = disqSrc.disqType()}];
    }
}

}  // namespace

void updateLastRunTime(pgpool3::Pool& pool, chrono::TimePoint now)
{
    auto txn = pool.masterWriteableTransaction();
    db::MetadataGateway{*txn}.upsertByKey(LAST_RUN_TIME,
                                          chrono::formatSqlDateTime(now));
    txn->commit();
}

std::optional<chrono::TimePoint> loadLastRunTime(pqxx::transaction_base& txn)
{
    auto result = db::MetadataGateway{txn}.tryLoadByKey(LAST_RUN_TIME);
    if (!result) {
        return std::nullopt;
    }
    return chrono::parseSqlDateTime(*result);
}

Bans loadBans(pgpool3::Pool& pool, chrono::TimePoint now)
{
    auto result = Bans{};
    auto batch =
        sql_chemistry::BatchLoad<db::table::DisqualifiedSource>{10'000};
    while (batch.next(*pool.slaveTransaction())) {
        for (const auto& disqSrc : batch.result()) {
            updateBans(disqSrc, now, result);
        }
    }
    return result;
}

}  // namespace maps::mrc::taxi_stat
