#include "module.h"

#include "vehicle_restrictions_common.h"
#include "../utils/misc.h"

#include <yandex/maps/wiki/validator/categories.h>
#include <yandex/maps/wiki/validator/check.h>

namespace maps::wiki::validator::checks {

using categories::RD_EL;
using categories::VEHICLE_RESTRICTION;

VALIDATOR_SIMPLE_CHECK( vehicle_restriction_direction, VEHICLE_RESTRICTION, RD_EL )
{
    auto viewRdEl = context->objects<RD_EL>();
    context->objects<VEHICLE_RESTRICTION>().visit([&](const VehicleRestriction* vrObject) {
        std::unordered_set<TId> fatalRdEls;
        std::unordered_set<TId> criticalRdEls;
        std::unordered_set<TId> restrictedRdEls;
        for (auto rdElId : vrObject->restrictsRoadElements()) {
            if (!viewRdEl.loaded(rdElId)) {
                continue;
            }
            restrictedRdEls.insert(rdElId);
        }
        auto checkRdEl = [&](auto rdElId) {
            if (!viewRdEl.loaded(rdElId)) {
                return;
            }
            auto rdEl = viewRdEl.byId(rdElId);
            if (!(rdEl->direction() & RoadElement::Direction::Forward) &&
                !criticalRdEls.contains(rdElId)) {
                criticalRdEls.insert(rdElId);
                context->critical(
                    "vehicle-restriction-wrong-direction",
                    utils::geomForReport(rdEl),
                    {vrObject->id(), rdElId});
            }
            if (restrictedRdEls.contains(rdElId) && !fatalRdEls.contains(rdElId)) {
                fatalRdEls.insert(rdElId);
                context->fatal(
                    "vehicle-restriction-both-directions",
                    utils::geomForReport(rdEl),
                    {vrObject->id(), rdElId});
            }
        };
        for (auto rdElId : vrObject->restrictsRoadElementsFrom()) {
            checkRdEl(rdElId);
            restrictedRdEls.insert(rdElId);
        }

        for (auto rdElId : vrObject->restrictsRoadElementsTo()) {
            checkRdEl(rdElId);
        }
    });
}

} // namespace maps::wiki::validator::checks
