#include <maps/libs/cmdline/include/cmdline.h>
#include <maps/libs/log8/include/log8.h>
#include <maps/wikimap/mapspro/services/mrc/libs/common/include/pg_locks.h>
#include <maps/wikimap/mapspro/services/mrc/libs/config/include/config.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/metadata_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/long_tasks/user_activity_stat/lib/clickhouse.h>
#include <maps/wikimap/mapspro/services/mrc/long_tasks/user_activity_stat/lib/db.h>
#include <maps/libs/common/include/exception.h>
#include <yandex/maps/pgpool3utils/pg_advisory_mutex.h>

namespace user_activity_stat = maps::mrc::user_activity_stat;

namespace {

void updateMetadata(maps::pgpool3::Pool& pool)
{
    INFO() << "updating metadata";
    auto txn = pool.masterWriteableTransaction();
    maps::mrc::db::MetadataGateway{*txn}.upsertByKey(
        user_activity_stat::LAST_RUN_TIME,
        maps::chrono::formatSqlDateTime(maps::chrono::TimePoint::clock::now()));
    txn->commit();
}

}  // namespace

int main(int argc, char* argv[])
try {
    maps::cmdline::Parser parser;
    auto syslog = parser.string("syslog-tag")
                      .help("redirect log output to syslog with given tag");
    auto configPath = parser.string("config").help("path to configuration");
    auto secretVersion = parser.string("secret").help(
        "version for secrets from yav.yandex-team.ru");
    auto dryRun =
        parser.flag("dry-run").help("do not publish data to clickhouse");
    parser.parse(argc, argv);

    if (syslog.defined()) {
        maps::log8::setBackend(maps::log8::toSyslog(syslog));
    }
    auto mrcConfig =
        maps::mrc::common::templateConfigFromCmdPath(secretVersion, configPath);

    auto mrcPostgres =
        mrcConfig.makePoolHolder(maps::mrc::common::LONG_READ_DB_ID,
                                 maps::mrc::common::LONG_READ_POOL_ID);

    auto mutex = maps::pgp3utils::PgAdvisoryXactMutex{
        mrcPostgres.pool(),
        static_cast<int64_t>(maps::mrc::common::LockId::UserActivityStat)};
    if (!dryRun && !mutex.try_lock()) {
        INFO() << "another process is ongoing";
        return EXIT_SUCCESS;
    }

    auto userActivity =
        user_activity_stat::loadUserActivity(mrcPostgres.pool());

    if (!dryRun) {
        user_activity_stat::clickhouse::upload(
            userActivity, mrcConfig.externals().clickHouseConfig());
        updateMetadata(mrcPostgres.pool());
    }

    INFO() << "done";
    return EXIT_SUCCESS;
}
catch (const maps::Exception& e) {
    ERROR() << e;
    return EXIT_FAILURE;
}
catch (const std::exception& e) {
    ERROR() << e.what();
    return EXIT_FAILURE;
}
