#include "get_geolocks.h"
#include "maps/wikimap/mapspro/services/editor/src/configs/config.h"
#include "maps/wikimap/mapspro/services/editor/src/magic_strings.h"
#include "maps/wikimap/mapspro/services/editor/src/utils.h"
#include <yandex/maps/wiki/revision/branch_manager.h>
#include <maps/wikimap/mapspro/libs/acl/include/aclgateway.h>
#include <maps/wikimap/mapspro/libs/acl_utils/include/moderation.h>

namespace maps::wiki {

GetGeoLocks::GetGeoLocks(const Request& request)
    : controller::BaseController<GetGeoLocks>(BOOST_CURRENT_FUNCTION)
    , request_(request)
{
    result_->branchId = request_.branchId;
    result_->branchState = revision::BranchState::Unavailable;
}

std::string
GetGeoLocks::printRequest() const
{
    std::stringstream ss;
    ss << " uid: " << request_.uid;
    ss << " branch: " << request_.branchId;
    ss << " bb: " << request_.bboxStr;
    return ss.str();
}

void
GetGeoLocks::control()
{
    try {
        auto work = cfg()->poolCore().masterReadOnlyTransaction();
        loadData(*work);
        return;
    } catch (const maps::Exception& ex) {
        ERROR() << "GetGeolocks: caught maps:exception: " << ex;
    } catch (const std::exception& ex) {
        ERROR() << "GetGeolocks: caught std:exception: " << ex.what();
    } catch (...) {
        ERROR() << "GetGeolocks: caught unknown exception";
    }
    result_->branchState = revision::BranchState::Unavailable;
}

void
GetGeoLocks::loadData(pqxx::transaction_base& work)
{
    auto branch = make_unique<revision::Branch>(
        revision::BranchManager(work).load(request_.branchId));

    result_->branchState = branch->state();
    if (result_->branchState != revision::BranchState::Normal) {
        return;
    }

    auto branchType = branch->type();
    if (branchType == revision::BranchType::Approved ||
        branchType == revision::BranchType::Deleted) {

        return;
    }

    auto bbox = createBbox(request_.bboxStr, SpatialRefSystem::Geodetic);
    auto locks = geolocks::GeoLock::loadByGeom(work, request_.branchId, bbox);
    if (locks.empty()) {
        return;
    }

    if (std::any_of(
        locks.begin(), locks.end(),
        [](const auto& lock) { return lock.commitId() > 0; }))
    {
        result_->locks = std::move(locks);
        return; // has automatical lock
    }

    auto user = acl::ACLGateway(work).user(request_.uid);
    if (acl_utils::hasRole(user, IGNORE_CUSTOM_GEOLOCKS_ROLE)) {
        return;
    }

    result_->locks = std::move(locks);
}

} // namespace maps::wiki
