#include "addr.h"
#include "utils.h"
#include "magic_string.h"

#include <yandex/maps/wiki/diffalert/object.h>
#include <yandex/maps/wiki/diffalert/snapshot.h>

namespace maps {
namespace wiki {
namespace diffalert {

void checkAddrNames(const DiffContext& d, MessageReporter& messages)
{
    if (!(d.categoryId() == cat::ADDR
          && d.newObject()
          && (!d.oldObject() || namesChanged(d)))) {
        return;
    }

    TIds officialNameIds;
    auto newObjectTableAttrs = d.oldObject()
        ? d.newObject()->loadSlaveRelations()
        : d.tableAttrsAdded();
    for (const auto& rel : newObjectTableAttrs) {
        if (rel.role == role::name::OFFICIAL) {
            officialNameIds.insert(rel.slaveId);
        }
    }
    if (officialNameIds.empty()) {
        messages.report({2, 3}, "addr-without-official-names");
    }

    TIds addedNameIds;
    for (const auto& rel : d.tableAttrsAdded()) {
        if (role::name::ALL_ROLES.count(rel.role)) {
            addedNameIds.insert(rel.slaveId);
        }
    }

    TIds nameIdsToLoad = addedNameIds;
    nameIdsToLoad.insert(officialNameIds.begin(), officialNameIds.end());
    auto nameObjects = d.newSnapshot().objectsByIds(nameIdsToLoad);

    std::set<std::string> officialNameStrings;
    std::set<std::string> officialNameLangs;
    for (const auto& name : nameObjects) {
        if (officialNameIds.count(name->id())) {
            officialNameStrings.insert(name->attr(attr::NAME).value());

            if (!officialNameLangs.insert(name->attr(attr::LANG).value()).second) {
                messages.report({0, 3}, "multiple-official-names-same-lang");
            }
        }
    }
    if (officialNameStrings.size() > 1) {
        messages.report({1, 3}, "addr-different-official-names");
    }

    for (const auto& name : nameObjects) {
        if (addedNameIds.count(name->id())) {
            const std::string nameStr = name->attr(attr::NAME).value();
            if (nameStr.empty() || !(nameStr[0] >= '0' && nameStr[0] <= '9')) {
                messages.report({2, 3}, "addr-name-doesnt-start-with-digit");
                break;
            }
        }
    }
}

} // namespace diffalert
} // namespace wiki
} // namespace maps
