#include "sync_geoproduct_flag.h"

#include "altay_reader.h"
#include "config.h"
#include "nmaps_export_result.h"
#include "object_helpers.h"

#include <maps/wikimap/mapspro/libs/editor_client/include/exception.h>
#include <yandex/maps/wiki/common/robot.h>
#include <yandex/maps/wiki/threadutils/threadpool.h>
#include <yandex/maps/wiki/threadutils/executor.h>

#include <maps/libs/log8/include/log8.h>
#include <maps/libs/common/include/make_batches.h>

namespace maps::wiki::merge_poi {

namespace {
const size_t THREADS_COUNT = 6;
const size_t BATCH_SIZE = 1000;

void
deleteAgentOwnedPoi(
    poi_feed::ObjectId nmapsId,
    editor_client::Instance& editorInstance)
try {
    const auto editorObject = getEditorObject(editorInstance, nmapsId);
    if (!editorObject) {
        return;
    }
    ASSERT(editorObject->firstCommit);
    const auto& firstCommit = *editorObject->firstCommit;

    if (firstCommit.author != common::WIKIMAPS_SPRAV_UID &&
        firstCommit.author != common::WIKIMAPS_SPRAV_COMMON_UID) {
        return;
    }
    editorInstance.deleteObject(nmapsId);
    INFO() << "Deleted unpublished object: " << nmapsId;
} catch (const editor_client::ServerException& ex) {
    WARN() << "Editor backend reported error while deleting unpublished object: "
        << nmapsId << " " << ex.status() << "\n" << ex;
} catch (const maps::Exception& ex) {
    ERROR() << "Exception while deleting unpublished object: "
        << nmapsId << "\n" << ex;
} catch (const std::exception& ex) {
    ERROR() << "Exception deleting unpublished object: "
        << nmapsId << "\n" << ex.what();
}

std::unordered_set<poi_feed::ObjectId>
nyakMappingUnknownPresentInExport(
    const NmapsExportResult& recentExportData,
    const std::string& nyakMappingUnknownYTURL)
{
    const auto nyakMappingUnknown = readNyakMappingUnknown(nyakMappingUnknownYTURL);
    std::unordered_set<poi_feed::ObjectId> present;
    present.reserve(nyakMappingUnknown.size());
    for (const auto& unknown : nyakMappingUnknown) {
        if (recentExportData.objectData(unknown.nmapsId)) {
            present.insert(unknown.nmapsId);
        }
    }
    return present;
}

} // namespace

void deleteUnpublishedPois(
    const NmapsExportResult& recentExportData,
    const Config& cfg,
    const std::string& nyakMappingUnknownYTURL)
{
    const auto toDeleteIds = nyakMappingUnknownPresentInExport(recentExportData, nyakMappingUnknownYTURL);
    ThreadPool threadPool(THREADS_COUNT);
    Executor threadedExecutor;
    const auto toDeleteIdsBatches = maps::common::makeBatches(toDeleteIds, BATCH_SIZE);
    for (const auto& batch : toDeleteIdsBatches) {
        threadedExecutor.addTask([&, batch] {
            editor_client::Instance editorInstance(cfg.editorWriterUrl(), common::WIKIMAPS_SPRAV_UID);
            for (const auto& oid : batch) {
                deleteAgentOwnedPoi(oid, editorInstance);
            }
        });
    };
    threadedExecutor.executeAllInThreads(threadPool);
}
} // maps::wiki::merge_poi
