#include <yandex/maps/wiki/revision/commit_manager.h>
#include <yandex/maps/wiki/revision/range_helpers.h>
#include <maps/libs/common/include/exception.h>
#include "commit_relations.h"
#include "commit_approver.h"
#include "commit_revert.h"
#include "commit_data.h"
#include "commit_merger.h"
#include "conflicts_checker.h"
#include "helpers.h"

namespace maps::wiki::revision {

using namespace helpers;

CommitManager::CommitManager(pqxx::transaction_base& work)
    : work_(work)
{}

bool CommitManager::hasDraftContributingCommitsWithoutOriginal(
    const ConstRange<DBID>& commitIds) const
{
    return hasDraftContributingCommitsWithoutOriginal(commitIds, EXCLUDE_NO_COMMITS);
}

bool CommitManager::hasDraftContributingCommitsWithoutOriginal(
    const ConstRange<DBID>& commitIds,
    const DBIDSet& excludeCommitIds) const
{
    if (commitIds.empty()) {
        return false;
    }
    return revision::hasDraftContributingCommitsWithoutOriginal(
        work_, idsToSet(commitIds), excludeCommitIds
    );
}

DBIDSet
CommitManager::findAllDraftContributingCommits(
    const ConstRange<DBID>& commitIds) const
{
    return findAllDraftContributingCommits(commitIds, EXCLUDE_NO_COMMITS);
}

DBIDSet
CommitManager::findAllDraftContributingCommits(
    const ConstRange<DBID>& commitIds,
    const DBIDSet& excludeCommitIds) const
{
    if (commitIds.empty()) {
        return {};
    }
    return revision::findAllDraftContributingCommits(work_, idsToSet(commitIds), excludeCommitIds);
}

DBIDSet
CommitManager::findDraftContributingCommits(
    const ConstRange<DBID>& commitIds,
    const ContributingCommitsOptions& options) const
{
    if (commitIds.empty()) {
        return {};
    }

    return revision::findDraftContributingCommits(
        work_,
        idsToSet(commitIds),
        EXCLUDE_NO_COMMITS,
        options);
}

DBIDSet
CommitManager::approve(const ConstRange<DBID>& commitIds) const
{
    if (commitIds.empty()) {
        return {};
    }

    CommitApprover approver(work_);
    return approver.process(idsToSet(commitIds));
}

DBIDSet
CommitManager::approveAll(DBID maxCommitId) const
{
    if (!maxCommitId) {
        return {};
    }

    CommitApprover approver(work_);
    return approver.processAll(maxCommitId);
}

DBIDSet
CommitManager::findDependentCommitsInTrunk(
    const ConstRange<DBID>& commitIds,
    const ResultChecker& resultChecker) const
{
    if (commitIds.empty()) {
        return {};
    }
    return revision::findDependentCommitsInTrunk(
        work_,
        idsToSet(commitIds),
        resultChecker);
}

bool
CommitManager::hasDependentCommitsInTrunk(const ConstRange<DBID>& commitIds) const
{
    REQUIRE(!commitIds.empty(), "empty commit ids");

    return revision::hasDependentCommitsInTrunk(work_, idsToSet(commitIds));
}

RevertData
CommitManager::revertCommitsInTrunk(
    const ConstRange<DBID>& commitIds,
    UserID user,
    const Attributes& commitAttributes) const
{
    REQUIRE(!commitIds.empty(), "empty commit ids");

    RevertCommitsResult result = revision::revertCommitsInTrunk(
        work_,
        idsToSet(commitIds),
        user,
        commitAttributes);
    return {Commit(std::move(result.createdCommitData)), std::move(result.revertedCommitIds)};
}

DBIDSet
CommitManager::mergeApprovedToStable(DBID maxCommitId) const
{
    if (!maxCommitId) {
        return {};
    }

    CommitMerger merger(work_);
    return merger.approvedToStable(maxCommitId);
}

} // namespace maps::wiki::revision
