#include "registry.h"
#include <maps/wikimap/mapspro/services/editor/src/objects/object.h>
#include <maps/wikimap/mapspro/services/editor/src/objects_cache.h>
#include <maps/wikimap/mapspro/services/editor/src/relations_manager.h>

namespace maps {
namespace wiki {
namespace srv_attrs{
namespace {

template<typename ObjectCollection>
std::vector<GeoObject*>
moveTo(
    RelationType direction,
    const std::string& roleId,
    const ObjectCollection& objects,
    RelationsStep::Selection selection)
{
    if (objects.empty()) {
        return {};
    }

    auto& cache = objects.front()->cache();
    auto& relationManager = cache.relationsManager();

    TOIds ids;
    for (const auto& obj : objects) {
        ids.insert(obj->id());
    }
    relationManager.loadRelations(direction, ids, {roleId});

    std::vector<GeoObject*> stepResult;
    if (selection == RelationsStep::Selection::Full) {
        for (const auto& obj : objects) {
            for (const auto& rel : obj->relations(direction).range(roleId)) {
                stepResult.push_back(rel.relative());
            }
            for (const auto& rel : obj->relations(direction).diff(roleId).deleted) {
                stepResult.push_back(rel.relative());
            }
        }
    } else {
        for (const auto& obj : objects) {
            for (const auto& rel : obj->relations(direction).diff(roleId).deleted) {
                stepResult.push_back(rel.relative());
            }
            for (const auto& rel : obj->relations(direction).diff(roleId).added) {
                stepResult.push_back(rel.relative());
            }
        }
    }
    return stepResult;
}
} // namespace

template<typename ObjectCollection>
std::vector<GeoObject*>
RelationsStep::backward(const ObjectCollection& objects, Selection selection) const
{
    return moveTo<ObjectCollection>(
            direction_ == RelationType::Master
                ? RelationType::Slave
                : RelationType::Master,
            roleId_, objects, selection);
}

std::vector<GeoObject*>
RelationsPath::backward(const std::vector<const GeoObject*>& initialObjects, size_t startPos) const
{
    if (steps().empty()) {
        return std::vector<GeoObject*>();
    }
    ASSERT(!initialObjects.empty());

    std::vector<GeoObject*> final = steps()[startPos].backward(
        initialObjects,
        startPos < steps().size() - 1
            ? RelationsStep::Selection::Diff
            : RelationsStep::Selection::Full);
    REQUIRE(startPos < steps().size(), "Steps index out of range");
    for (size_t stepIndex = startPos; stepIndex > 0; --stepIndex) {
        final = steps()[stepIndex - 1].backward(
                final,
                RelationsStep::Selection::Full);
    }
    return final;
}

} // namespace srv_attrs
} // namespace wiki
} // namespace maps
