#include "tasks_gateway.h"

#include <yandex/maps/wiki/common/default_config.h>
#include <yandex/maps/wiki/common/extended_xml_doc.h>

#include <maps/tools/grinder/worker/include/api.h>
#include <maps/libs/cmdline/include/cmdline.h>
#include <maps/libs/common/include/exception.h>
#include <maps/libs/log8/include/log8.h>
#include <maps/libs/mongo/include/init.h>

#include <string>
#include <functional>
#include <exception>

namespace worker = maps::grinder::worker;
using maps::wiki::common::ExtendedXmlDoc;
using std::placeholders::_1;

namespace {
constexpr std::size_t CONCURRENCY_LEVEL = 3;

void submitEditorTask(std::string tasksUrl, const worker::Task& task)
{
    using namespace maps::wiki::tasks_gateway;

    const auto& args = task.args();

    auto taskType = args["task-type"].as<std::string>();
    auto userId = args["uid"].as<UserId>();

    Params params;
    if (args.hasField("params")) {
        const auto& jsonParams = args["params"];
        for (const auto& field : jsonParams.fields()) {
            params[field] = jsonParams[field].as<std::string>();
        }
    }

    INFO() << "Creating task of type " << taskType << " as user " << userId;
    auto taskId = createTask(tasksUrl, taskType, userId, params);
    INFO() << "Created task " << taskId << " of type " << taskType;
}
} // anonymous namespace

int main(int argc, char* argv[]) try {
    maps::cmdline::Parser parser;
    auto workerConfig
        = parser.string("config").help("path to wiki services config");
    auto syslogTag = parser.string("syslog-tag").help(
        "redirect log output to syslog with given tag");
    auto grinderConfig = parser.string("grinder-config")
                             .help("path to the grinder configuration file");

    parser.parse(argc, argv);
    if (syslogTag.defined()) {
        maps::log8::setBackend(maps::log8::toSyslog(syslogTag));
    }

    maps::mongo::init();

    std::unique_ptr<ExtendedXmlDoc> configPtr;
    if (workerConfig.defined()) {
        configPtr.reset(new ExtendedXmlDoc(workerConfig));
    } else {
        configPtr = maps::wiki::common::loadDefaultConfig();
    }

    auto tasksUrl = configPtr->get<std::string>("/config/services/tasks/url");

    worker::Options options;
    if (grinderConfig.defined()) {
        options.setConfigLocation(grinderConfig);
    }
    options.setConcurrencyLevel(CONCURRENCY_LEVEL);
    options.on("submit-editor-task",
               std::bind(submitEditorTask, tasksUrl, _1));
    worker::run(std::move(options));
    return EXIT_SUCCESS;
}
catch (const maps::Exception& e) {
    WARN() << "Worker failed: " << e;
    return EXIT_FAILURE;
}
catch (const std::exception& e) {
    WARN() << "Worker failed: " << e.what();
    return EXIT_FAILURE;
}
