import networkx as nx


def match_reference(current_assignments, ref_assignments):
    """
    Determine if two sets of labels agree.
    This could be used to test if two sets of SMIRKS type a set of molecules
    in exactly the same way.

    This starts with two sets of "assignments" which are dictionaries
    like those created with get_typed_molecules.

    Let's imagine you wanted to type the molecule CF and CCl
    where most bonds are assigned X, but one bond in each molecule is
    assigned 'Y'. Then the reference_assignments would be:
    { 0: (0,1): 'X', (0,2): 'X', (0,3): 'X', (0,4): 'Y'},
      1: (0,1): 'X', (0,2): 'X', (0,3): 'X', (0,4): 'Y'},
    }

    Then you discover a set of SMIRKS patterns which match
    C-H bonds with one type and C-halogen have another.
    Then your current_assignments would be:
    { 0: (0,1): 'C-H', (0,2): 'C-H', (0,3): 'C-H', (0,4): 'C-hal.'},
      1: (0,1): 'C-H', (0,2): 'C-H', (0,3): 'C-H', (0,4): 'C-hal.'},
    }
    This would return a set tuples for the corresponding labels
    [('C-H', 'X'), ('C-hal.', 'Y')] and True for the two assigments matching.

    However, if your current set assigned different types to the two
    different carbon halogen bonds (C-F and C-Cl) then these two
    sets of assignments would not match and the result would be an empty set and False

    Parameters
    ----------
    current_assignments : dictionary of indices with current types
    ref_assignments : dictionary of indices with reference types

    Returns
    -------
    type_matches : set of tuples (current_label, reference_label)
                   pair of current and reference labels
                   None if the sets don't match
    is_match : boolean
               Does the current assignment exactly match the reference?
    """

    graph = nx.Graph()
    matches = set()
    r_labs = set()
    c_labs = set()

    for mol_idx, index_dict in ref_assignments.items():
        # check that mol_idx is in current_assignments
        if mol_idx not in current_assignments:
            return set(), False

        for indices, r_label in index_dict.items():
            # check this set of indices is in the current set
            if indices not in current_assignments[mol_idx]:
                return set(), False

            c_label = current_assignments[mol_idx][indices]
            # check if nodes exist for the two labels (and make them)
            if c_label not in graph:
                graph.add_node(c_label)
                c_labs.add('current_'+c_label)

            if r_label not in graph:
                graph.add_node(r_label)
                r_labs.add(r_label)

            # create an edge connecting the reference and current type
            graph.add_edge('current_'+c_label, r_label)
            matches.add((c_label, r_label))

    for c_label in c_labs:
        if len(graph.edges(c_label)) != 1:
            return set(), False

    for r_label in r_labs:
        if len(graph.edges(r_label)) != 1:
            return set(), False

    return matches, True