#pragma once

#include <maps/wikimap/mapspro/services/editor/src/common.h>
#include <maps/wikimap/mapspro/services/editor/src/branch_helpers.h>

#include <yandex/maps/wiki/revision/branch.h>
#include <maps/wikimap/mapspro/libs/revision_meta/include/branch_lock_ids.h>
#include <maps/libs/common/include/exception.h>

namespace maps {
namespace wiki {
namespace revision_meta {

/**
 * Branch lock id reserved for revision_meta update.
 * There are two kinds of update:
 * 1) Sync: for long-running cache update, e.g. fired from wiki-editor-tool.
 *   Sync must acquire branch lock with mode == revision::Branch::LockMode::Wait.
 * 2) Update: for short-running cache update, e.g. when commits are created
 *     in editor.
 *   Update must acquire this lock with mode == revision::Branch::LockMode::Nowait.
 */
const revision::Branch::LockId BRANCH_LOCK_ID = revision_meta::REVISION_META_LOCK_ID;

class QueueLockException : public Exception {};

/**
 * Class providing access to commits queue for revision_meta data update.
 * Commits queue facade is created for specific branch.
 * Usage scenario:
 *   1) Lock branch.
 *   2) Get commits list.
 *   3) Process commits.
 *   4) Confirm processing: delete processed commits.
 *   5) Commit transaction.
 * It is client's responsibility to delete processed commits from queue
 *   and commit transaction after processing.
 * Locking branch for update does not block pushing new commits into queue.
 */
class CommitsQueue
{
public:
    CommitsQueue(Transaction& txn, TBranchId branchId);

    /**
     * Lock commits to be processed (select for update with NOWAIT).
     * Must be called with branch lock acquired.
     * @throws QueueLockException in case of error.
     */
    TCommitIds lockCommits(
        boost::optional<TCommitId> maxCommitId,
        boost::optional<size_t> commitsLimit);

    void deleteCommits(const TCommitIds& commitIds);
    void clear();

    void push(TCommitId commitId);

private:
    Transaction& txn_;
    TBranchId branchId_;
};

} // namespace revision_meta
} // namespace wiki
} // namespace maps
