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

#include <maps/wikimap/mapspro/services/mrc/libs/db/include/common.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/feature_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/yt/include/io.h>
#include <maps/wikimap/mapspro/services/mrc/libs/yt/include/schema.h>

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

#include <maps/libs/cmdline/include/cmdline.h>
#include <maps/libs/log8/include/log8.h>
#include <maps/libs/sql_chemistry/include/batch_load.h>

#include <fstream>
#include <optional>
#include <utility>

namespace maps::mrc::eye {

void run(
        const common::Config& config,
        db::TIds featureIds,
        const std::string& featureTableYtPath)
{
    INFO() << "Starting...";

    wiki::common::PoolHolder mrc(config.makePoolHolder());
    auto txn = mrc.pool().slaveTransaction();

    const auto yt = config.externals().yt().makeClient();

    auto filter = db::table::Feature::id.in(std::move(featureIds));
    sql_chemistry::BatchLoad<db::table::Feature> batch(1000, filter);

    yt->Create(TString(featureTableYtPath), NYT::NT_TABLE,
        NYT::TCreateOptions()
            .Recursive(true)
            .Attributes(NYT::TNode()(
                "schema", yt::getSchemaOf<db::Feature>().ToNode())
            )
    );

    while (batch.next(*txn)) {
        yt::saveToTable(
            *yt,
            NYT::TRichYPath(TString(featureTableYtPath))
                .Append(true),
            batch.begin(), batch.end()
        );
    }
}

db::TIds readFeatureIds(std::istream& in)
{
    db::TIds featureIds;

    for (db::TId featureId; in; ) {
        in >> featureId;
        featureIds.push_back(featureId);
    }

    return featureIds;
}

} // namespace maps::mrc::eye

int main(int argc, const char** argv) try {
    NYT::Initialize(argc, argv);

    maps::cmdline::Parser parser("Upload mrc features to yt table");

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

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

    auto featureIdsPath = parser.string("feature-ids")
            .help("path to feature ids");

    auto ytTablePath = parser.string("yt-table")
            .required()
            .help("yt table path");

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

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

    maps::mrc::db::TIds featureIds;
    if (featureIdsPath.defined()) {
        std::ifstream in(featureIdsPath);
        featureIds = maps::mrc::eye::readFeatureIds(in);
    } else {
        featureIds = maps::mrc::eye::readFeatureIds(std::cin);
    }

    maps::mrc::eye::run(config, std::move(featureIds), ytTablePath);

    return EXIT_SUCCESS;
} catch (const maps::Exception& ex) {
    FATAL() << "Failed: " << ex;
    return EXIT_FAILURE;
} catch (const std::exception& ex) {
    FATAL() << "Failed: " << ex.what();
    return EXIT_FAILURE;
} catch (...) {
    FATAL() << "Unknown error!";
}
