#include "module.h"

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

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

#include <yandex/maps/wiki/common/misc.h>

#include <set>

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

using categories::RD;
using categories::RD_NM;


namespace {

void checkRenderLabel(const Road* road, CheckContext* context)
{
    if (road->type() != Road::Type::Kilometer) {
        return;
    }

    const bool hasAtLeastOneLocalRenderName = std::any_of(
        road->names().begin(), road->names().end(),
        [&context](const NameRelation& relation) {
            if (relation.type != NameRelation::Type::RenderLabel) {
                return false;
            }
            const Name* renderLabel = context->objects<RD_NM>().byId(relation.id);
            return renderLabel->isLocal();
        }
    );

    if (!hasAtLeastOneLocalRenderName) {
        context->error("missing-render-label", boost::none, { road->id() });
    }
}

const icu::RegexPattern MORE_THAN_ONE_WORD = utils::compilePattern(
    R"(\S\s+\S)"
);

void checkOfficialNameHasMoreThanOneWord(const Road* road, CheckContext* context)
{
    if (common::isIn(road->type(), {Road::Type::Route, Road::Type::NamedExit})) {
        return;
    }

    for (const NameRelation& relation: road->names()) {
        if (relation.type != NameRelation::Type::Official) {
            continue;
        }

        const Name* name = context->objects<RD_NM>().byId(relation.id);
        if (utils::isNameEmpty(name->name())) {
            continue;
        }

        if (!utils::matchesPattern(name->name(), MORE_THAN_ONE_WORD)) {
            context->report(
                common::isIn(name->lang(), {"ru", "be", "uk", "kk"})
                    ? Severity::Error
                    : Severity::Warning,
                "one-word-official-road-name",
                boost::none,
                {road->id()}
            );
        }
    }
}

} // end of anonymous namespace


VALIDATOR_SIMPLE_CHECK( road_naming, RD, RD_NM )
{
    context->objects<RD>().visit(
        [&](const Road* road) {
            utils::runBasicNamesCheck<RD_NM>(road, context);
                if (!utils::isNamed<RD_NM>(road, context)) {
                context->error("unnamed-road", boost::none, { road->id() });
            }
            checkOfficialNameHasMoreThanOneWord(road, context);
            checkRenderLabel(road, context);
        }
    );
}

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