#include "approve.h"
#include <maps/wikimap/mapspro/services/editor/src/approved_commits/approver.h>
#include <maps/wikimap/mapspro/services/editor/src/exception.h>
#include <maps/wikimap/mapspro/services/editor/src/branch_helpers.h>
#include <maps/wikimap/mapspro/services/editor/src/moderation_log.h>

#include <maps/wikimap/mapspro/libs/acl/include/aclgateway.h>
#include <yandex/maps/wiki/revision/commit.h>
#include <yandex/maps/wiki/social/gateway.h>

#include <maps/wikimap/mapspro/libs/acl_utils/include/moderation.h>

namespace maps {
namespace wiki {

namespace {

const std::string TASK_METHOD_NAME = "CommitsApprove";

} // namespace

CommitsApprove::Request::Request(TUid uid, TCommitId commitId)
    : user(uid)
    , commitId(commitId)
{
    CHECK_REQUEST_PARAM(uid);
    CHECK_REQUEST_PARAM(commitId);
}

std::string
CommitsApprove::Request::dump() const
{
    std::stringstream ss;
    ss << " uid: " << user
       << " commit: " << commitId;
    return ss.str();
}


CommitsApprove::CommitsApprove(
        const ObserverCollection&,
        const Request& request,
        taskutils::TaskID asyncTaskID)
    : controller::BaseController<CommitsApprove>(BOOST_CURRENT_FUNCTION, asyncTaskID)
    , request_(request)
{}

std::string
CommitsApprove::printRequest() const
{
    return request_.dump();
}

void
CommitsApprove::control()
{
    processApprove();
    logModerationEvent(result_->taskIds, ModerationLogger::Action::Closed);
}

void
CommitsApprove::processApprove()
{
    auto branchCtx = CheckedTrunkBranchContextFacade().acquireWrite();

    acl::ACLGateway gateway(branchCtx.txnCore());
    auto user = gateway.user(request_.user);
    WIKI_REQUIRE(
        acl_utils::isCartographer(gateway, user),
        ERR_FORBIDDEN,
        "Approving commit " << request_.commitId << " denied, uid: " << request_.user);

    social::Gateway socialGw(branchCtx.txnSocial());
    auto superModConsole = socialGw.superModerationConsole(request_.user);

    result_->taskIds = superModConsole.closeRevertedTasks(
        socialGw.loadActiveEditTasksByCommitIds({request_.commitId}),
        social::CloseResolution::Approve
    );

    if (result_->taskIds.empty()) { // Approved commit is not a revert.
        approved_commits::CommitsApprover approver(branchCtx, user, {request_.commitId});
        result_->taskIds = approver.closeTasks(social::CloseResolution::Approve);
        approver.awakeUpdater();
    }

    auto commits = revision::Commit::load(
        branchCtx.txnCore(), revision::filters::CommitAttr::id().in({request_.commitId}));

    for (auto& commit: commits) {
        result_->commitModels.emplace_back(std::move(commit));
    }

    result_->token = branchCtx.commit();
}

const std::string&
CommitsApprove::taskName()
{
    return TASK_METHOD_NAME;
}

} // namespace wiki
} // namespace maps
