import logging
from typing import Iterable

import networkx as nx

LOG = logging.getLogger(__name__)


def find_house_m0(G: nx.Graph, node_id: int):
    random_count: int = G.graph['random_count']
    assert node_id >= random_count, f'{node_id} < {random_count}'
    offset: int = (node_id - G.graph['random_count']) % 5
    return node_id - offset


def find_house_handles(G: nx.Graph, node_id: int):
    m0: int = find_house_m0(G, node_id)
    return [int(n) for n in G.neighbors(m0) if int(n) < m0]


def attach_house(G: nx.Graph, attach_node: int, m0: int) -> nx.Graph:
    assert G.has_node(attach_node)
    G.add_edges_from(
        [
            (attach_node, m0),
            (m0, m0 + 1),
            (m0 + 1, m0 + 2),
            (m0 + 2, m0 + 3),
            (m0 + 3, m0),
            (m0, m0 + 4),
            (m0 + 1, m0 + 4),
        ]
    )
    return G


def get_neighborhood_subgraph(G: nx.Graph, root_id: int, hops: int):
    visited = set()
    subgraph_nodes = set([root_id])
    cache = []
    current_cache = [root_id]
    for _ in range(hops):
        cache = set([n for n in current_cache])
        current_cache.clear()
        while len(cache) > 0:
            center = cache.pop()
            if center in visited:
                continue
            visited.add(center)
            neighbors = [
                n for n in nx.neighbors(G, center) if n not in visited
            ]
            subgraph_nodes.update(neighbors)
            current_cache.extend(neighbors)
    return G.subgraph(subgraph_nodes).copy()


def has_element(items: Iterable[nx.Graph], G: nx.Graph) -> bool:
    assert isinstance(items, Iterable), 'items is not an iterable'
    assert isinstance(G, nx.Graph), 'G is not of type nx.Graph'

    for H in items:
        if nx.is_isomorphic(G, H):
            return True
    return False

