"""Minimal NetworkX shim for testing without pip install."""


class _EdgeView:
    """Lightweight edge view supporting both iteration and ``edges(data=True)`` calls."""

    def __init__(self, edges_dict):
        self._edges = edges_dict

    def __iter__(self):
        return iter(self._edges.keys())

    def __len__(self):
        return len(self._edges)

    def __call__(self, data=False):
        if data:
            return [(src, dst, dict(attrs)) for (src, dst), attrs in self._edges.items()]
        return list(self._edges.keys())


class DiGraph:
    def __init__(self):
        self._nodes = {}
        self._edges = {}  # (src, dst) -> attrs
        self._adj = {}    # src -> {dst: attrs}
        self._pred = {}   # dst -> {src: attrs}

    def add_node(self, node, **attrs):
        self._nodes[node] = attrs
        if node not in self._adj:
            self._adj[node] = {}
        if node not in self._pred:
            self._pred[node] = {}

    def add_edge(self, src, dst, **attrs):
        self.add_node(src)
        self.add_node(dst)
        self._edges[(src, dst)] = attrs
        self._adj.setdefault(src, {})[dst] = attrs
        self._pred.setdefault(dst, {})[src] = attrs

    def has_edge(self, src, dst):
        return (src, dst) in self._edges

    @property
    def nodes(self):
        return list(self._nodes.keys())

    @property
    def edges(self):
        return _EdgeView(self._edges)

    def number_of_nodes(self):
        return len(self._nodes)

    def number_of_edges(self):
        return len(self._edges)

    def in_degree(self):
        return [(n, len(self._pred.get(n, {}))) for n in self._nodes]

    def out_degree(self):
        return [(n, len(self._adj.get(n, {}))) for n in self._nodes]
