#include "updater.h"

#include "processor.h"
#include <maps/wikimap/mapspro/services/editor/src/configs/config.h>
#include <maps/wikimap/mapspro/services/editor/src/sync/db_helpers.h>
#include <maps/wikimap/mapspro/services/editor/src/sync/branch_mask.h>
#include <maps/wikimap/mapspro/services/editor/src/revision_meta/bbox_update_task.h>

#include <maps/wikimap/mapspro/libs/revision_meta/include/utils.h>
#include <yandex/maps/wiki/common/string_utils.h>
#include <yandex/maps/wiki/revision/branch_manager.h>
#include <yandex/maps/wiki/revision/exception.h>
#include <yandex/maps/wiki/social/gateway.h>

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

#include <chrono>

namespace maps {
namespace wiki {
namespace approved_commits {

namespace {

const std::string WORKER_NAME = "revision_meta approved commits updater and branch_mask cleaner";
const std::chrono::seconds UPDATE_DELAY(60);

} // namespace

Updater::Updater()
    : ThreadObserver<Updater>(UPDATE_DELAY)
    , executionState_(make_unique<ExecutionState>())
{
    start();
}

Updater::~Updater()
{
    cancel();
}

constexpr const std::string&
Updater::name() const noexcept
{
    return WORKER_NAME;
}

void
Updater::doWork()
try {
    sync::cleanUpBranchMaskTable();

    auto work = cfg()->poolCore().masterWriteableTransaction();

    auto branch = revision::BranchManager(*work).loadApproved();
    auto threads = (sync::maxThreadsCount(branch.id()) / 3) + 1;

    sync::BranchLocker branchLocker(work);

    {
        auto socialTxn = cfg()->poolSocial().masterReadOnlyTransaction();
        revision_meta::moveFromPreApprovedToApprovedQueueIfPossible(
            *work,
            social::Gateway(*socialTxn).getAllActiveEditTasksCommitIds()
        );
    }

    Processor processor(branchLocker, branch, threads, COMMIT_RANGE_BATCH_SIZE);
    if (processor.tryProcess(revision_meta::ApprovedQueueMode::ViewAttrs, executionState_)
        && processor.tryProcess(revision_meta::ApprovedQueueMode::Labels, executionState_)
        && processor.tryProcess(revision_meta::ApprovedQueueMode::Bboxes, executionState_)) {
        work->commit();
    } else {
        INFO() << name() << " state, "
               << " CANCELED: " << executionState_->cancel
               << " FAILED: " << executionState_->fail;
    }
} catch (const revision::BranchNotExistsException&) {
    INFO() << name() << " skipped, approved branch not exists";
} catch (const revision::BranchAlreadyLockedException&) {
    INFO() << name() << " skipped, approved branch already locked";
} catch (const maps::Exception& e) {
    ERROR() << name() << " error: " << e;
} catch (const std::exception& e) {
    ERROR() << name() << " error: " << e.what();
} catch (...) {
    ERROR() << name() << " unknown error";
}

void
Updater::cancel()
{
    INFO() << "CANCEL " << name();
    executionState_->cancel = true;
}

} // namespace approved_commits
} // namespace wiki
} // namespace maps
