#include <maps/wikimap/mapspro/services/mrc/libs/config/include/config.h>

#include <maps/wikimap/mapspro/services/mrc/eye/experiments/signs_map/toloka/matches/lib/include/feature.h>
#include <maps/wikimap/mapspro/services/mrc/eye/experiments/signs_map/toloka/matches/lib/include/object.h>
#include <maps/wikimap/mapspro/services/mrc/eye/experiments/signs_map/toloka/matches/lib/include/pair.h>
#include <maps/wikimap/mapspro/services/mrc/eye/experiments/signs_map/toloka/matches/lib/include/task.h>
#include <maps/wikimap/mapspro/services/mrc/eye/experiments/signs_map/toloka/matches/lib/include/strings.h>
#include <maps/wikimap/mapspro/services/mrc/eye/experiments/signs_map/toloka/matches/lib/include/serialization.h>

#include <maps/libs/cmdline/include/cmdline.h>
#include <maps/libs/common/include/exception.h>
#include <maps/libs/log8/include/log8.h>

using namespace maps;
using namespace maps::mrc;
using namespace maps::mrc::eye;
using namespace maps::mrc::common;

namespace {

Tasks prepareTasks(
    const FeatureIdPairs& featureIdPairs,
    const FeatureById& featureById,
    const ObjectsByFeatureId& objectsByFeatureId)
{
    Tasks tasks;

    for (const auto& [featureId1, featureId2] : featureIdPairs) {
        const auto& feature1 = featureById.at(featureId1);
        const auto& objects1 = objectsByFeatureId.at(featureId1);

        const auto& feature2 = featureById.at(featureId2);
        const auto& objects2 = objectsByFeatureId.at(featureId2);

        tasks.emplace_back(
            feature1, objects1,
            feature2, objects2
        );
    }
    return tasks;
}

} // namespace

int main(int argc, const char** argv) try {
    cmdline::Parser parser("Prepare Toloka tasks");

    cmdline::Option<std::string> mrcConfigPath = parser.string("mrc-config")
        .help("Path to mrc config")
        .required();

    cmdline::Option<std::string> secretVersion = parser.string("secret-version")
        .help("version for secrets from yav.yandex-team.ru")
        .required();

    cmdline::Option<std::string> objectsPath = parser.string("objects")
        .help("Path to json file with objects")
        .required();

    cmdline::Option<std::string> pairsPath = parser.string("pairs")
        .help("Path to text file with pairs of feature ids")
        .required();

    cmdline::Option<std::string> tasksPath = parser.string("tasks")
        .help("Path to json file with Toloka tasks")
        .required();

    parser.parse(argc, const_cast<char**>(argv));

    const Config mrcConfig
        = templateConfigFromCmdPath(secretVersion, mrcConfigPath);

    INFO() << "Loading objects: " << objectsPath;
    const auto objectsByFeatureId = loadObjects(objectsPath);
    INFO() << "Loaded objects for " << objectsByFeatureId.size() << " features";

    INFO() << "Loading pairs: " << pairsPath;
    const auto featureIdPairs = loadPairs(pairsPath);
    INFO() << "Loaded " << featureIdPairs.size() << " pairs";

    INFO() << "Loading features";
    maps::wiki::common::PoolHolder mrc(mrcConfig.makePoolHolder());
    const auto featureById = loadFeatures(mrc.pool(), featureIdPairs);
    INFO() << "Loaded " << featureById.size() << " features";

    INFO() << "Preparing tasks";
    const auto tasks = prepareTasks(featureIdPairs, featureById, objectsByFeatureId);
    INFO() << "Prepared " << tasks.size() << " tasks";

    INFO() << "Dump Toloka tasks: " << tasksPath;
    dumpTasks(tasks, tasksPath);

    INFO() << "Done!";

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