#include "save_exclusion.h"
#include <maps/wikimap/mapspro/services/editor/src/configs/config.h>
#include "maps/wikimap/mapspro/services/editor/src/check_permissions.h"
#include <maps/wikimap/mapspro/services/editor/src/exception.h>

#include <yandex/maps/wiki/revision/branch_manager.h>
#include <yandex/maps/wiki/revision/revisionsgateway.h>
#include <yandex/maps/wiki/validator/storage/exception.h>
#include <yandex/maps/wiki/validator/storage/exclusions_gateway.h>

namespace maps::wiki {

namespace {

DECLARE_ERR_CODE( ERR_NONEXISTENT_MESSAGE );
DECLARE_ERR_CODE( ERR_EXCLUSION_EXISTS );
DECLARE_ERR_CODE( ERR_NONEXISTENT_EXCLUSION );

} // namespace

namespace vs = validator::storage;

SaveValidationExclusion::SaveValidationExclusion(
        const Request& request)
    : controller::BaseController<SaveValidationExclusion>(BOOST_CURRENT_FUNCTION)
    , request_(request)
{ }

std::string
SaveValidationExclusion::printRequest() const
{
    std::stringstream ss;
    ss << " uid: " << request_.uid
       << " branch: " << request_.branchId
       << " message-id: " << request_.messageId;
    return ss.str();
}

void
SaveValidationExclusion::control()
{
    auto workCore = cfg()->poolCore().masterReadOnlyTransaction();
    CheckPermissions(
            request_.uid,
            *workCore).checkUserHasAccessToValidatorTasks();
    auto branch = revision::BranchManager(*workCore).load(request_.branchId);

    auto workValidation = cfg()->poolValidation().masterWriteableTransaction();

    revision::RevisionsGateway revGw(*workCore, branch);
    auto snapshot = revGw.snapshot(revGw.headCommitId());

    auto exclGw = vs::ExclusionsGateway(*workValidation);

    result_->uid = request_.uid;
    try {
        switch (request_.operation) {
        case Op::Add:
            {
                auto storedMessage =
                    exclGw.addExclusion(
                        request_.messageId, request_.uid, snapshot);
                result_->exclusion.reset(new vs::StoredMessageDatum(std::move(storedMessage)));
                break;
            }
        case Op::Remove:
            {
                auto storedMessage =
                    exclGw.removeExclusion(request_.messageId, snapshot);
                result_->exclusion.reset(new vs::StoredMessageDatum(std::move(storedMessage)));
                break;
            }
        }
    } catch (const vs::NonexistentMessageError&) {
        THROW_WIKI_LOGIC_ERROR(
                ERR_NONEXISTENT_MESSAGE,
                "message does not exist, id: " << request_.messageId);
    } catch (const vs::ExclusionExistsError&) {
        THROW_WIKI_LOGIC_ERROR(
                ERR_EXCLUSION_EXISTS,
                "exclusion already exists for message id: " << request_.messageId);
    } catch (const vs::NonexistentExclusionError&) {
        THROW_WIKI_LOGIC_ERROR(
                ERR_NONEXISTENT_EXCLUSION,
                "no exclusion exists for message id: " << request_.messageId);
    }

    workValidation->commit();
}

} // namespace maps::wiki
