#include <maps/wikimap/mapspro/services/mrc/eye/lib/import_detection/include/importer.h>
#include <maps/wikimap/mapspro/services/mrc/eye/lib/common/include/id_stream.h>

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

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

#include <chrono>
#include <thread>

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

int main(int argc, const char** argv) try {
    maps::cmdline::Parser parser;

    auto syslog = parser.string("syslog-tag")
            .help("redirect log output to syslog with given tag");

    auto mrcConfigPath = parser.string("mrc-config")
            .help("path to mrc config");

    auto secretVersion = parser.string("secret-version")
            .help("version for secrets from yav.yandex-team.ru");

    auto frameIdsPath = parser.string("frame-ids")
            .help("path to frame ids file");

    auto loop = parser.flag("loop")
            .help("work in infinite loop");

    auto batchSize = parser.num("batch")
            .defaultValue(1000)
            .help("recognition batch size (default 1000)");

    auto commit = parser.flag("commit")
            .help("commit results");

    auto enableSign = parser.flag("enable-sign")
            .help("enable sign recognition");

    auto enableTrafficLight = parser.flag("enable-traffic-light")
            .help("enable traffic light recognition");

    auto enableHouseNumber = parser.flag("enable-house-number")
            .help("enable house number recognition");

    auto enableRoadMarking = parser.flag("enable-road-marking")
            .help("enable road marking recognition");

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

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

    const auto config =
        maps::mrc::common::templateConfigFromCmdPath(secretVersion,
                                                     mrcConfigPath);

    wiki::common::PoolHolder poolHolder = config.makePoolHolder();

    db::eye::RecognitionTypes recognitionTypes;
    if (enableSign) {
        recognitionTypes.push_back(db::eye::RecognitionType::DetectSign);
    }
    if (enableTrafficLight) {
        recognitionTypes.push_back(db::eye::RecognitionType::DetectTrafficLight);
    }
    if (enableHouseNumber) {
        recognitionTypes.push_back(db::eye::RecognitionType::DetectHouseNumber);
    }
    if (enableRoadMarking) {
        recognitionTypes.push_back(db::eye::RecognitionType::DetectRoadMarking);
    }

    ImportDetectionConfig workerConfig;
    workerConfig.mrc.pool = &poolHolder.pool();
    workerConfig.mrc.commit = commit;
    workerConfig.recognitionTypes = recognitionTypes;

    DetectionImporter importer(workerConfig);

    if (not loop) {
        if (frameIdsPath.defined()) {
            for (IdStream idStream(frameIdsPath); idStream.valid(); ) {
                importer.processBatch(idStream.readBatch(batchSize));
            }
        } else {
            WARN() << "No frame ids!";
        }

        return EXIT_SUCCESS;
    }

    INFO() << "Loop mode...";
    if (frameIdsPath.defined()) {
        WARN() << "Ignore frame ids '" << frameIdsPath << "'";
    }

    for (;;) {
        INFO() << "Process new batch...";
        const auto [_, isImportCompleted] = importer.processBatchInLoopMode(batchSize);
        if (isImportCompleted) {
            INFO() << "Import completed";
            break;
        }
    }

    return EXIT_SUCCESS;
} catch (const maps::Exception& e) {
    FATAL() << e;
    return EXIT_FAILURE;
} catch (const yexception& e) {
    FATAL() << e.what();

    if (e.BackTrace()) {
        FATAL() << e.BackTrace()->PrintToString();
    }

    return EXIT_FAILURE;
} catch (const std::exception& e) {
    FATAL() << e.what();
    return EXIT_FAILURE;
} catch (...) {
    FATAL() << "Unknown error!";
    return EXIT_FAILURE;
}
