from anytree import LevelOrderIter

import johnnydep
from johnnydep.compat import dict
from johnnydep.util import CircularMarker


template = """\
%(comment)s
digraph %(title)s {
    %(edges)s
}
"""


def jd2dot(dist, comment=None):
    """exports johnnydist to graphviz DOT language
    https://graphviz.org/doc/info/lang.html
    nodes are the project name [+extras]
    edges will be labeled with any requirement constraints
    """
    if comment is None:
        comment = "generated by https://github.com/wimglenn/johnnydep v" + johnnydep.__version__
    if comment:
        if not comment.startswith(("//", "#")):
            comment = "# " + comment
    title = dist.project_name.replace("-", "_")
    edges = []
    for node in LevelOrderIter(dist):
        if isinstance(node, CircularMarker):
            # todo - render cycles differently?
            continue
        if node.parent is not None:
            node_name = node._name_with_extras(attr="project_name")
            parent_node_name = node.parent._name_with_extras(attr="project_name")
            spec = node.req.specifier
            label = ' [label="{}"]'.format(spec) if spec else ""
            edge = '"{}" -> "{}"'.format(parent_node_name, node_name)
            edges.append(edge + label + ";")
    edges = list(dict.fromkeys(edges))  # order-preserving de-dupe
    edges = "\n    ".join(edges)
    if not edges:
        # project with no dependencies - it's just a single node
        node_name = dist._name_with_extras(attr="project_name")
        edges = '"{}";'.format(node_name)
    result = template % {"comment": comment, "title": title, "edges": edges}
    return result.strip()
