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

#include <maps/libs/cmdline/include/cmdline.h>
#include <maps/libs/enum_io/include/enum_io.h>
#include <maps/libs/log8/include/log8.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/string_utils.h>
#include <memory>

namespace maps::wiki::gdpr {
namespace {

enum class Action
{
    Start,
    Status,
    Info,
    AnonymizeEdits,
    AnonymizeComments,
    AnonymizeFeedback,
    AnonymizeModeration,
    AnonymizeSprav,
    CleanAclProfile,
    CleanSocialProfile,
    CleanStats,
    Finish,
};

constexpr enum_io::Representations<Action> ACTION_REPR {
    {Action::Start, "start"},
    {Action::Status, "status"},
    {Action::Info, "info"},
    {Action::AnonymizeEdits, "anonymize-edits"},
    {Action::AnonymizeComments, "anonymize-comments"},
    {Action::AnonymizeFeedback, "anonymize-feedback"},
    {Action::AnonymizeModeration, "anonymize-moderation"},
    {Action::AnonymizeSprav, "anonymize-sprav"},
    {Action::CleanAclProfile, "clean-acl-profile"},
    {Action::CleanSocialProfile, "clean-social-profile"},
    {Action::CleanStats, "clean-stats"},
    {Action::Finish, "finish"},
};
DEFINE_ENUM_IO(Action, ACTION_REPR);

std::string allActions()
{
    return common::join(maps::enum_io::enumerateValues<Action>(), '\n');
}

int run(
    const common::ExtendedXmlDoc& config,
    TUid uid,
    const std::string& actionStr,
    const std::string& requestId,
    bool dryRun)
{
    INFO() << "Uid: " << uid;
    INFO() << "Action: " << actionStr;
    INFO() << "RequestId: " << requestId;

    auto action = enum_io::tryFromString<Action>(actionStr);
    if (!action) {
        ERROR() << "Unsupported action: " << actionStr;
        return EXIT_FAILURE;
    }

    DbPools dbPools(config, "grinder");
    Worker worker(dbPools, uid, dryRun);

    switch(*action) {
        case Action::Start:
            worker.start(requestId);
            break;
        case Action::Status:
            worker.status();
            break;
        case Action::Info:
            worker.info();
            break;
        case Action::AnonymizeEdits:
            worker.anonymizeEdits();
            break;
        case Action::AnonymizeComments:
            worker.anonymizeComments();
            break;
        case Action::AnonymizeFeedback:
            worker.anonymizeFeedback();
            break;
        case Action::AnonymizeSprav:
            worker.anonymizeSprav();
            break;
        case Action::AnonymizeModeration:
            worker.anonymizeModeration();
            break;
        case Action::CleanAclProfile:
            worker.cleanAclProfile();
            break;
        case Action::CleanSocialProfile:
            worker.cleanSocialProfile();
            break;
        case Action::CleanStats:
            worker.cleanStats();
            break;
        case Action::Finish:
            worker.finish();
            break;
    }
    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 config = argsParser.file("config")
        .help("Path to services.xml with database connection settings.");
    auto uid = argsParser.size_t("uid")
        .help("Passport uid (puid)");
    auto action = argsParser.string("action")
        .help(allActions());
    auto requestId = argsParser.string("request-id")
        .defaultValue("")
        .help("request_id from Passport");
    auto dryRun = argsParser
        .flag("dry-run")
        .help("do not update data in database")
        .defaultValue(false);
    argsParser.parse(argc, argv);

    if (!action.defined()) {
        argsParser.printUsageAndExit(EXIT_FAILURE);
    }

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

    return run(*configPtr, uid, action, requestId, 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;
}
