import re

from py4cytoscape import networks
from py4cytoscape.network_selection import get_selected_nodes, select_edges
from py4cytoscape.py4cytoscape_logger import cy_log
from py4cytoscape.py4cytoscape_utils import *  # type: ignore  # noqa: F403

re_parenthesis_1 = re.compile(r'[(]+')
re_parenthesis_2 = re.compile(r'[)]+')


@cy_log  # pragma: no cover
def select_edges_connecting_selected_nodes(network=None, base_url=DEFAULT_BASE_URL):  # noqa: F405 # pragma: no cover
    """Select edges in a Cytoscape Network connecting the selected nodes, including self loops connecting single nodes.

    Any edges selected beforehand are deselected before any new edges are selected

    Args:
        network (SUID or str or None): Name or SUID of a network. Default is the
            "current" network active in Cytoscape.
        base_url (str): Ignore unless you need to specify a custom domain,
            port or version to connect to the CyREST API. Default is http://127.0.0.1:1234
            and the latest version of the CyREST API supported by this version of py4cytoscape.

    Returns:
         dict: {'nodes': [node list], 'edges': [edge list]} or None if no selected nodes
    Raises:
        CyError: if network name or SUID doesn't exist
        requests.exceptions.RequestException: if can't connect to Cytoscape or Cytoscape returns an error

    Examples:
        >>> select_edges_connecting_selected_nodes()
        None
        >>> select_edges_connecting_selected_nodes(network='My Network')
        {'nodes': [103990, 103991, ...], 'edges': [104432, 104431, ...]}
        >>> select_edges_connecting_selected_nodes(network=52)
        {'nodes': [103990, 103991, ...], 'edges': [104432, 104431, ...]}

    Note:
        In the return value node list is list of all selected nodes, and
        edge list is the SUIDs of selected edges -- dict is None if no nodes were selected or there were no newly
        created edges
    """
    net_suid = networks.get_network_suid(network, base_url=base_url)

    selected_nodes = get_selected_nodes(network=net_suid, base_url=base_url)
    # TODO: In R version, NA test is after len() test ... shouldn't it be before?
    if not selected_nodes:
        return None

    all_edges = networks.get_all_edges(net_suid, base_url=base_url)

    selected_sources = set()
    selected_targets = set()
    for n in selected_nodes:
        n = re_parenthesis_1.sub('\(', n)  # type: ignore
        n = re_parenthesis_2.sub('\)', n)  # type: ignore
        selected_sources |= set(filter(re.compile('^' + n).search, all_edges))  # type: ignore
        selected_targets |= set(filter(re.compile(n + '$').search, all_edges))  # type: ignore

    selected_edges = list(selected_sources.intersection(selected_targets))

    if len(selected_edges) == 0:
        return None
    res = select_edges(
        selected_edges,
        by_col='name',
        preserve_current_selection=False,
        network=net_suid,
        base_url=base_url,
    )
    return res
    # TODO: isn't the pattern match a bit cheesy ... shouldn't it be ^+n+' ('    and    ') '+n+$ ???
