#include "save_state.h"
#include <maps/wikimap/mapspro/services/editor/src/branch_helpers.h>
#include <maps/wikimap/mapspro/services/editor/src/exception.h>
#include <maps/wikimap/mapspro/libs/revision_meta/include/branch_lock_ids.h>
#include <yandex/maps/wiki/revision/exception.h>

namespace maps {
namespace wiki {

namespace {

DECLARE_ERR_CODE( ERR_BRANCH_ALREADY_DELETED );
const std::string TASK_METHOD_NAME = "SaveBranchState";

} // namespace

std::string
SaveBranchState::Request::dump() const
{
    std::stringstream ss;
    ss << " uid: " << user;
    ss << " state: " << branchState;
    ss << " branch: " << branchId;
    return ss.str();
}

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

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

void
SaveBranchState::control()
{
    auto branchCtx = BranchContextFacade(request_.branchId)
        .acquireManageBranches(request_.user);

    branchCtx.branch.lock(
        branchCtx.txnCore(), revision_meta::GLOBAL_LOCK_ID,
        revision::Branch::LockMode::Nowait, revision::Branch::LockType::Shared);

    WIKI_REQUIRE(
        branchCtx.branch.type() != revision::BranchType::Deleted,
        ERR_BRANCH_ALREADY_DELETED,
        "can not change state for deleted branch: " << branchCtx.branch.id());

    auto branch = branchCtx.branch;
    if (branch.setState(branchCtx.txnCore(), request_.branchState)) {
        INFO() << "Branch " << branch.id()
               << " state was changed: " << request_.branchState
               << " by uid: " << request_.user
               << " (old state: " << branchCtx.branch.state() << ")";

        if (branch.type() == revision::BranchType::Approved) {
            //All manual operations should reset this attribute
            branch.concatenateAttributes(branchCtx.txnCore(), {{STABLE_BRANCH_CREATION_ATTR, "0"}});
        }
    }
    result_->branches = loadHeadBranches(branchCtx.txnCore());
    result_->token = branchCtx.commit();
}

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

} // namespace wiki
} // namespace maps
