#include "objects_query_ids.h"

#include "maps/wikimap/mapspro/services/editor/src/branch_helpers.h"
#include "maps/wikimap/mapspro/services/editor/src/check_permissions.h"
#include "maps/wikimap/mapspro/services/editor/src/objects_cache.h"

#include <yandex/maps/wiki/configs/editor/categories.h>
#include <maps/wikimap/mapspro/libs/acl/include/exception.h>

namespace maps::wiki {

ObjectsQueryIds::Request::Request(
    IdsFormat idsFormat,
    const std::string& oidsStr,
    SerializeDetailsFlags serializeDetailsFlags,
    TUid uid,
    Token token,
    TBranchId branchId)
    : serializeDetailsFlags(serializeDetailsFlags)
    , uid(uid)
    , dbToken(token)
    , branchId(branchId)
{
    try {
        if (idsFormat == IdsFormat::CSV) {
            objectIds = splitCast<std::vector<TOid>>(oidsStr, ',');
        } else {
            ASSERT(idsFormat == IdsFormat::JsonArray);
            const auto jsonArray = json::Value::fromString(oidsStr);
            objectIds.reserve(jsonArray.size());
            for (const auto& value : jsonArray) {
                objectIds.push_back(boost::lexical_cast<TOid>(value.as<std::string>()));
            }
        }
        return;
    } catch (boost::bad_lexical_cast& ex) {
        ERROR() << ex.what();
    } catch (maps::Exception& ex) {
        ERROR() << ex;
    }
    THROW_WIKI_LOGIC_ERROR(
        ERR_BAD_REQUEST, "Could not parse oids: '" << oidsStr << "'");
}

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

ObjectsQueryIds::~ObjectsQueryIds() {}

std::string
ObjectsQueryIds::printRequest() const
{
    std::stringstream ss;
    ss << " oids:";
    for (const auto& oid : request_.objectIds) {
        ss << " " << oid;
    }
    ss << " with-attrs: "
        << request_.serializeDetailsFlags.isSet(SerializeDetails::Attrs);
    ss << " with-permissions: "
        << request_.serializeDetailsFlags.isSet(SerializeDetails::Permissions);
    ss << " with-masters: "
        << request_.serializeDetailsFlags.isSet(SerializeDetails::Masters);
    ss << " user: " << request_.uid;
    ss << " token: " << request_.dbToken;
    ss << " branch: " << request_.branchId;
    return ss.str();
}

void
ObjectsQueryIds::control()
{
    const TOIds idsSet(request_.objectIds.begin(), request_.objectIds.end());
    const CachePolicy policy {
        request_.serializeDetailsFlags.isSet(SerializeDetails::Attrs)
            ? TableAttributesLoadPolicy::Load
            : TableAttributesLoadPolicy::Skip,
        ServiceAttributesLoadPolicy::Load,
        DanglingRelationsPolicy::Ignore
    };
    cache_.reset(
        new ObjectsCache(
            BranchContextFacade::acquireRead(request_.branchId, request_.dbToken),
            boost::none,
            policy
        )
    );
    CheckPermissions checker(request_.uid, cache_->workCore(),
        CheckPermissions::BannedPolicy::Allow);
    for (auto& object: cache_->get(idsSet)) {
        if (!object->category().system()) {
            try {
                checker.checkPermissionsToViewObject(object.get());
                result_->collection.add(std::move(object));
            } catch (const  wiki::acl::AccessDenied& ex) {
            };
        }
    }
    result_->serializeDetailsFlags = request_.serializeDetailsFlags;
}

} // namespace maps::wiki
