#pragma once

#include "common.h"
#include "context.h"

#include <maps/wikimap/mapspro/libs/acl/include/check_context.h>
#include <maps/wikimap/mapspro/libs/acl/include/subject_path.h>

#include <pqxx/pqxx>

namespace maps {
namespace wiki {

class GeoObject;
struct RelationInfosDiff;

namespace acl {

class CheckContext;

} // namespace acl

namespace social {

class EventAlert;

} // namespace acl

const acl::SubjectPath SERVICE_ACL_BASE("mpro/editor");

class CheckPermissions
{
public:
    enum class CheckPolicy {
        All,
        ModifiedPrimary
    };
    enum class BannedPolicy {
        Allow,
        Deny
    };
    CheckPermissions(
        TUid userId,
        Transaction& work,
        const ObjectsDataMap& objectsUpdateData);

    CheckPermissions(
        TUid userId,
        Transaction& work,
        BannedPolicy bannedPolicy = BannedPolicy::Deny);

    void operator()(const GeoObject* object);

    void checkPermissionsToManageBranches();
    void checkPermissionsToEditBranch(TBranchId);
    bool isUserHasAccessToViewBranches();

    void checkPermissionsForCloneOperation(const GeoObject* object);

    void checkPermissionsToEditFilters();
    void checkPermissionsToViewFilters();
    bool isUserHasAccessToViewFilters();
    bool isUserHasAccessToEditPublicFilters();
    void checkAccessToPoisConflictsTool();
    void checkAccessToBusinessPhotosTool();
    void checkAccessToEditsFeed();

    void checkPermissionsForGroupMove(
        const StringSet& categoryIds);
    void checkPermissionsForGroupSyncGeometry(
        const std::string& categoryId);
    void checkPermissionsForGroupUpdateAttributes(
        const std::string& categoryId,
        const StringMultiMap& attributes);
    void checkPermissionsForGroupUpdateRelations(
        const StringSet& categoryIds);
    void checkPermissionsForGroupUpdateRelation();
    void checkPermissionsForGroupDelete();
    void checkPermissionsForGroupDeleteComments();

    void checkPermissionForCompletedByOthersTaskFeed();

    const acl::CheckContext& globalContext();

    void checkPermissionsToViewObject(const GeoObject* object);
    void checkPermissionsToEditObject(const GeoObject* object,
        CheckPolicy checkPolicy = CheckPolicy::All);
    bool isUserHasAccessToViewCategory(const std::string& categoryId);
    bool isUserHasAccessToViewValue(
        const std::string& categoryId,
        const std::string& attrId,
        const std::string& value);

    void checkPermissionsToBlockingTasks();

    bool allowToIgnoreRestrictions(const Category& category);

    bool isUserHasAccessToIgnoreOverlay(const StringSet& baseCategories);
    bool isUserHasAccessToStickPolygons();
    void checkUserHasAccessToIsLocalManualPolicy();
    void checkUserHasAccessToValidatorTasks();
    void checkAccessToEditorMode();

    bool isUserHasAccessViewCategoryAttribute(
        const std::string& categoryId,
        const std::string& attribute);

    bool isUserHasAccessToEventAlert(
        const social::EventAlert& alert,
        const std::string& categoryId);

    bool canUserAnnotateOtherUserCommit();
    bool canUserDeleteOtherUserComment();

    bool hasPermissionsToEditObjectGeometry(const GeoObject* obj);

private:

    void checkPermissionsToCreateObject(
        const acl::CheckContext& aclContext, const GeoObject* obj);
    void checkPermissionsToDeleteObject(
        const acl::CheckContext& aclContext, const GeoObject* obj);
    void checkPermissionsToObjectGeometry(
        const acl::CheckContext& aclContext, const GeoObject* obj);
    void checkPermissionsToObjectRelations(
        const acl::CheckContext& aclContext,
        const GeoObject* obj,
        const RelationInfosDiff& diffSlaves);
    void checkPermissionsToObjectAttributes(
        const acl::CheckContext& aclContext, const GeoObject* obj);
    void checkPermissionsToObjectAttributesWithContext(
        const acl::CheckContext& aclContext, const GeoObject* obj);
    void checkPermissionsToBlockedObjects(
        const acl::CheckContext& aclContext, const GeoObject* obj);
    void checkPermissionsForPrivateObjects(const GeoObject* obj);

    void checkPermissionsToPerformActionOnObject(const GeoObject* object, const std::string& action);

    TUid userId_;
    Transaction& work_;
    std::unique_ptr<acl::CheckContext> globalContext_;
    const ObjectsDataMap* objectsUpdateData_;
    BannedPolicy bannedPolicy_;
};

} // namespace wiki
} // namespace maps
