#include <maps/wikimap/mapspro/services/gdpr/src/lib/worker.h>
#include <maps/wikimap/mapspro/services/gdpr/src/lib/utils.h>

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

#include <maps/libs/cmdline/include/cmdline.h>
#include <maps/libs/log8/include/log8.h>
#include <maps/libs/pgpool3utils/include/yandex/maps/pgpool3utils/pg_advisory_mutex.h>

#include <memory>

namespace maps::wiki::gdpr {
namespace {

int run(
    const common::ExtendedXmlDoc& config,
    std::chrono::days threshold,
    bool dryRun)
{
    DbPools dbPools(config, "grinder");

    pgp3utils::PgAdvisoryXactMutex locker(
        dbPools.core(),
        static_cast<int64_t>(common::AdvisoryLockIds::GDPR));
    if (!locker.try_lock()) {
        INFO() << "GDPR is already under process (Database is locked)";
        return EXIT_SUCCESS;
    }

    auto& coreWriteTxn = locker.writableTxn();
    auto takeouts = getTakeoutDataWithThreshold(coreWriteTxn, threshold);
    INFO() << "Found " << takeouts.size() << " unprocessed takeouts";

    for (const auto& takeoutData : takeouts) {
        try {
            INFO() << "Processing takeout id:" << takeoutData.takeoutId
                << " uid:" << takeoutData.uid;
            Worker worker(dbPools, takeoutData.uid, dryRun);
            worker.anonymizeEdits();
            worker.anonymizeComments();
            worker.anonymizeFeedback();
            worker.anonymizeModeration();
            worker.anonymizeSprav();
            worker.cleanAclProfile();
            worker.cleanSocialProfile();
            worker.cleanStats();
            worker.finish();
        } catch (const maps::Exception& e) {
            ERROR() << "Failed to process takeout [" << takeoutData.requestId << "]: " << e;
        } catch (const std::exception& e) {
            ERROR() << "Failed to process takeout [" << takeoutData.requestId << "]: " << e.what();
        }
    }
    return EXIT_SUCCESS;
}

} // namespace
} // namespace maps::wiki::gdpr

int main(int argc, char** argv) try {
    using namespace maps::wiki::gdpr;

    maps::cmdline::Parser argsParser;
    auto syslogTag = argsParser.string("syslog-tag")
        .help("redirect log output to syslog with given tag");
    auto config = argsParser.file("config")
        .help("path to services.xml with database connection settings.");
    auto daysAgo = argsParser.num("days-ago")
        .help("threshold to filter out more recent requests");
    auto dryRun = argsParser
        .flag("dry-run")
        .help("do not update data in database")
        .defaultValue(false);
    argsParser.parse(argc, argv);

    if (syslogTag.defined()) {
        maps::log8::setBackend(maps::log8::toSyslog(syslogTag));
    }

    auto configPtr = config.defined()
        ? std::make_unique<maps::wiki::common::ExtendedXmlDoc>(config)
        : maps::wiki::common::loadDefaultConfig();

    return run(*configPtr, std::chrono::days{daysAgo}, dryRun);
} catch (const maps::Exception& e) {
    FATAL() << "Exception caught: " << e;
    return EXIT_FAILURE;
} catch (const std::exception& ex) {
    FATAL() << "Exception caught: " << ex.what();
    return EXIT_FAILURE;
} catch (...) {
    FATAL() << "Unknown exception caught";
    return EXIT_FAILURE;
}
