#pragma once

#include <maps/wikimap/mapspro/services/mrc/libs/graph/include/common.h>
#include <maps/wikimap/mapspro/services/mrc/libs/graph/include/id.h>

#include <boost/range/adaptor/map.hpp>

#include <memory>
#include <optional>
#include <unordered_map>

namespace maps::mrc::graph {

class Graph {

    using ElementById = std::unordered_map<TId, RoadElement>;

    struct Impl;

public:
    Graph(AccessId accessId, const RoadElements& elements, const Conditions& conditions);

    ~Graph();

    AccessId accessId() const;

    bool hasElement(TId id) const;

    const RoadElement& elementById(TId id) const;
    const RoadElement& elementByDirectedId(const DirectedId& id) const;
    const RoadElement& elementByNodeId(NodeId nodeId) const;

    using ElementRange = boost::select_second_const_range<ElementById>;

    ElementRange elements() const;

    Edges edges(NodeId nodeId);

    TId getId(NodeId nodeId) const;
    const DirectedId& getDirectedId(NodeId nodeId) const;

    // Null if impossible to move through the element
    OptionalNodeId getNodeId(const DirectedId& directedId);

    // For tests:
    NodeId getNodeId(const Trace& trace);
    const Trace& getTrace(NodeId nodeId) const;

private:
    std::unique_ptr<Impl> impl_;
};

} // namespace maps::mrc::graph
