import uuid
import copy


def apply_uuid_to_elements(elements, uuid_to_apply=None):
    """Append a new UUID to the id of each cytoscape element

    This is used as a workaround to update the source/target of edges, and the parent/child relatioship of nodes.
    In Cytoscape.js, these relationships are immutable, and a move() function has to
    be called on the element to update the aforementioned properties.
    However, Dash Cytoscape doesn't expose this functionality.
    See https://github.com/plotly/dash-cytoscape/issues/106.
    By providing a new ID, we can avoid this restriction.

    Args:
        elements: a list of Cytoscape elements
        uuid_to_apply: a UUID to append. Defaults to None.
            If None is provided, this function generates a new UUID.

    Returns:
        A list of Cytoscape elements with an UUID appended to their ID fields.
    """
    if uuid_to_apply is None:
        uuid_to_apply = uuid.uuid4()

    out_elements = []

    # the properties of the element that need to have a UUID
    # appended
    UUID_KEYS = ["id", "source", "target", "parent"]
    for element in elements:
        new_element = copy.deepcopy(element)
        for key in UUID_KEYS:
            if key in new_element["data"]:
                new_element["data"][key] += f"#{uuid_to_apply}"
        out_elements.append(new_element)

    return out_elements