#include "poi_conflicts_common.h"

#include "maps/wikimap/mapspro/services/editor/src/check_permissions.h"
#include "maps/wikimap/mapspro/services/editor/src/configs/categories_strings.h"
#include "maps/wikimap/mapspro/services/editor/src/configs/config.h"

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

namespace maps::wiki {

namespace {
const std::string INDOOR_PREFIX = "indoor_";
const std::string POI_PART = "poi_";
const StringSet POI_GROUPS {
    CATEGORY_GROUP_INDOOR,
    CATEGORY_GROUP_POI,
};

const StringSet NON_POI_CONFLICTING_CATEGORIES {
    CATEGORY_ADDR,
    CATEGORY_TRANSPORT_AIRPORT,
    CATEGORY_TRANSPORT_AIRPORT_TERMINAL,
    CATEGORY_TRANSPORT_HELICOPTER,
    CATEGORY_TRANSPORT_METRO_STATION,
    CATEGORY_TRANSPORT_METRO_EXIT,
    CATEGORY_TRANSPORT_RAILWAY_STATION,
    CATEGORY_TRANSPORT_STOP,
    CATEGORY_TRANSPORT_TERMINAL,
    CATEGORY_VEGETATION_CNT,
};
} // namespace

bool
isGeoproduct(const views::ViewObject& object)
{
    return object.domainAttrs().count(ATTR_POI_IS_GEOPRODUCT);
}

bool
userHasAccessToGeoproducts(TUid uid, const PoiConflictingCategories& categoriesHolder, Transaction& workCore)
{
    try {
        CheckPermissions checker(uid, workCore);
        const auto& categories = categoriesHolder();
        return std::any_of(categories.begin(), categories.end(),
            [&](const auto& categoryId) {
                return checker.isUserHasAccessViewCategoryAttribute(categoryId, ATTR_POI_IS_GEOPRODUCT);
            });
    } catch (const acl::ACLException& ex) {
    }
    return false;
}

poi_conflicts::Kind
conflictKind(
    bool fistIsGeoproduct,
    bool secondIsGeoproduct)
{
    if (secondIsGeoproduct &&
        fistIsGeoproduct)
    {
        return poi_conflicts::Kind::GeoproductVsGeoproduct;
    }

    if (!secondIsGeoproduct &&
        !fistIsGeoproduct)
    {
        return poi_conflicts::Kind::PoiVsPoi;
    }
    return poi_conflicts::Kind::PoiVsGeoproduct;
}

StringSet poiCategoryIds(IndoorPoiPolicy indoorPoiPolicy)
{
    const auto editorCfg = cfg()->editor();
    return editorCfg->categories().idsByFilter(
        [&](const auto& category) {
            const auto id = category.id();
            if (id.find(POI_PART) == std::string::npos) {
                return false;
            }
            if (indoorPoiPolicy == IndoorPoiPolicy::Exclude &&
                id.starts_with(INDOOR_PREFIX))
            {
                return false;
            }
            auto group = editorCfg->categoryGroups().findGroupByCategoryId(id);
            return group && POI_GROUPS.count(group->id());
        });
}

PoiConflictingCategories::PoiConflictingCategories()
{
    data_ = poiCategoryIds();
    data_.insert(
        NON_POI_CONFLICTING_CATEGORIES.begin(),
        NON_POI_CONFLICTING_CATEGORIES.end());
}

poi_conflicts::ConflictSeverity
conflictSeverity(TZoom zoom, bool escalateGeoproduct, poi_conflicts::Kind kind)
{
    auto severity = poi_conflicts::ConflictSeverity::Error;
    if (zoom >= COMMON_MIN_CRITICAL_CONFLICT_ZOOM) {
        severity = poi_conflicts::ConflictSeverity::Critical;
    } else if (escalateGeoproduct &&
        kind == poi_conflicts::Kind::GeoproductVsGeoproduct &&
        zoom >= GEOPRODUCT_MIN_CRITICAL_CONFLICT_ZOOM)
    {
        severity = poi_conflicts::ConflictSeverity::Critical;
    }
    return severity;
}

} // namespace maps::wiki
