#include "component_feed/component_feed_cache.h"

#include "config.h"
#include "loader_helpers.h"

#include <maps/libs/common/include/exception.h>
#include <maps/libs/log8/include/log8.h>
#include <maps/libs/common/include/make_batches.h>
#include <yandex/maps/wiki/common/default_config.h>
#include <yandex/maps/wiki/common/extended_xml_doc.h>
#include <yandex/maps/wiki/threadutils/threadpool.h>
#include <yandex/maps/wiki/threadutils/executor.h>
#include <library/cpp/resource/resource.h>
#include <yandex/maps/wiki/revision/revisionsgateway.h>
#include <yandex/maps/wiki/common/retry_duration.h>

using namespace maps::wiki::poi;
using namespace maps::wiki;
using namespace maps;
namespace {
const size_t BATCH_SIZE = 1000;
const size_t THREADS_COUNT = 10;
}

int main(int, char* argv[]) try {
    const auto configXmlPtr = maps::wiki::common::loadDefaultConfig();
    auto mapping = NResource::Find(maps::wiki::rubrics::RUBRICS_MAPPING_CONFIG_RESOURCE_ID);
    Config cfg{*configXmlPtr, mapping, YMAPSDF_XML_DEFAULT_PATH};
    DBIDSet idsToResetCache;
    std::ifstream ids(argv[1]);
    log8::setLevel(log8::Level::DEBUG);
    while (ids) {
        DBID id;
        ids >> id;
        idsToResetCache.insert(id);
    }
    INFO() << "ids read " << idsToResetCache.size();
    if (idsToResetCache.empty()) {
        return EXIT_SUCCESS;
    }
    const auto cacheUpdateCommitId = maps::wiki::common::retryDuration([&] {
        auto coreTxn = cfg.mainPool().slaveTransaction();
        revision::RevisionsGateway gateway(*coreTxn, cfg.branch());
        return gateway.headCommitId();
    });
    INFO() << " Branch's head " << cacheUpdateCommitId;
    const auto batches = maps::common::makeBatches(idsToResetCache, BATCH_SIZE);
    ThreadPool threadPool(THREADS_COUNT);
    Executor threadedExecutor;
    size_t iBatch = 0;
    for (const auto& batch : batches) {
        ++iBatch;
        threadedExecutor.addTask([&, batch, iBatch] {
            DBIDSet idsSet;
            for (const auto oid : batch) {
                idsSet.insert(oid);
            }
            ComponentFeedCache feedCache(idsSet, cfg);
            for (const auto oid : batch) {
                feedCache.resetCache(oid);
                feedCache.get(oid, cacheUpdateCommitId);
            }
            feedCache.saveModified();
            INFO() << "Batch " << iBatch << " of " << batches.size() << " done.";
        });
    }
    threadedExecutor.executeAllInThreads(threadPool);
}
catch (const maps::Exception& e) {
    ERROR() << "Reset cache tool POI failed: " << e;
    return EXIT_FAILURE;
}
catch (const std::exception& e) {
    ERROR() << "Reset cache tool POI failed: " << e.what();
    return EXIT_FAILURE;
}
