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

#include "../utils/geom.h"
#include "../utils/geom_iterator.h"
#include "../utils/object_elements_within_aoi.h"

#include <maps/libs/geolib/include/distance.h>

namespace {

double MAX_STATION_LINE_DISTANCE = 400; // meters
double MAX_EXIT_STATION_DISTANCE = 1000; // meters

} // namespace

using maps::wiki::validator::categories::TRANSPORT_METRO_EL;
using maps::wiki::validator::categories::TRANSPORT_METRO_LINE;
using maps::wiki::validator::categories::TRANSPORT_METRO_STATION;
using maps::wiki::validator::categories::TRANSPORT_METRO_EXIT;

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

VALIDATOR_SIMPLE_CHECK( transport_metro_geometry,
        TRANSPORT_METRO_EL, TRANSPORT_METRO_LINE,
        TRANSPORT_METRO_STATION, TRANSPORT_METRO_EXIT)
{
    context->objects<TRANSPORT_METRO_STATION>().visit(
        [&](const TransportMetroStation* station)
    {
        double distanceRatio = utils::mercatorDistanceRatio(station->geom());
        TId lineId = station->line();
        if (context->objects<TRANSPORT_METRO_LINE>().loaded(lineId)) {
            const auto* line =
                context->objects<TRANSPORT_METRO_LINE>().byId(
                    lineId);
            if (!line->elements().empty()
                    && utils::objectElementsWithinAoi<TRANSPORT_METRO_LINE>(
                            context, line)
                    && utils::distance(
                            station->geom(),
                            utils::geomIteratorRange<TRANSPORT_METRO_EL>(
                                line->elements(),
                                context))
                        * distanceRatio > MAX_STATION_LINE_DISTANCE) {
                context->error(
                    "station-too-far-from-line",
                    station->geom(),
                    { station->id(), lineId });
            }
        }

        for (TId exitId : station->exits()) {
            if (context->objects<TRANSPORT_METRO_EXIT>().loaded(exitId)) {
                const TransportMetroExit* exit =
                    context->objects<TRANSPORT_METRO_EXIT>().byId(exitId);
                if (geolib3::distance(station->geom(), exit->geom())
                        * distanceRatio > MAX_EXIT_STATION_DISTANCE) {
                    context->error(
                        "exit-too-far-from-station",
                        exit->geom(),
                        { exit->id(), station->id() });
                }
            }
        }
    });
}

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