"""
Use case: user has visited a travel agency website recently.
Advertisers want to display ads about travel promotions to all members of his household.
"""
from collections.abc import Iterable

from gremlin_python.process.traversal import Column, T
from gremlin_python.process.graph_traversal import project, valueMap, out
import networkx as nx

from nepytune import drawing


def get_all_transient_ids_in_household(g, transient_id):
    """Given transient id, get all transient ids from its household."""
    return (
        g.V(transient_id)
            .hasLabel("transientId")
            .in_("has_identity")
            .in_("member")
            .has("type", "household")
            .out("member")
            .out("has_identity").
        values("uid")
    )


def draw_referenced_subgraph(g, transient_id):
    graph = drawing.spring_layout(
        _build_networkx_graph(
            g,
            g.V(transient_id).in_("has_identity").in_("member").next()
        )
    )

    drawing.draw(
        title="Single identity group graph structure",
        scatters=[
            drawing.edges_scatter(graph)
        ] + list(
            drawing.scatters_by_label(
                graph, attrs_to_skip=["pos"],
                sizes={"identityGroup": 60, "transientId": 20, "persistentId": 40}
            )
        ),
        annotations=drawing.edge_annotations(graph)
    )


# ===========================
# Everything below was added to introspect the query results via visualisations


def _get_identity_group_hierarchy(g, identity_group_id):
    return (
        g.V(identity_group_id)
            .project("props", "persistent_ids")
                .by(valueMap(True))
                .by(
                    out("member")
                    .group()
                    .by()
                    .by(
                        project("props", "transient_ids")
                            .by(valueMap(True))
                            .by(
                                out("has_identity").valueMap(True).fold()
                        )
                    ).select(Column.values)
                )
    )


def _build_networkx_graph(g, identity_group_id):
    def get_attributes(attribute_list):
        attrs = {}
        for attr_name, value in attribute_list:
            attr_name = str(attr_name)

            if isinstance(value, Iterable) and not isinstance(value, str):
                for i, single_val in enumerate(value):
                    attrs[f"{attr_name}-{i}"] = single_val
            else:
                if '.' in attr_name:
                    attr_name = attr_name.split('.')[-1]
                attrs[attr_name] = value

        return attrs

    graph = nx.Graph()

    for ig_node in _get_identity_group_hierarchy(g, identity_group_id).toList():
        ig_id = ig_node["props"][T.id]

        graph.add_node(
            ig_id,
            **get_attributes(ig_node["props"].items())
        )

        for persistent_node in ig_node["persistent_ids"]:
            p_id = persistent_node["props"][T.id]
            graph.add_node(
                p_id,
                **get_attributes(persistent_node["props"].items())
            )
            graph.add_edge(ig_id, p_id, label="member")

            for transient_node_map in persistent_node["transient_ids"]:
                transient_id = transient_node_map[T.id]
                graph.add_node(
                    transient_id,
                    **get_attributes(transient_node_map.items())
                )
                graph.add_edge(transient_id, p_id, label="has_identity")

    return graph

"""
Use case: user has visited a travel agency website recently.
Advertisers want to display ads about travel promotions to all members of his household.
"""
from collections.abc import Iterable

from gremlin_python.process.traversal import Column, T
from gremlin_python.process.graph_traversal import project, valueMap, out
import networkx as nx

from nepytune import drawing


def get_all_transient_ids_in_household(g, transient_id):
    """Given transient id, get all transient ids from its household."""
    return (
        g.V(transient_id)
            .hasLabel("transientId")
            .in_("has_identity")
            .in_("member")
            .has("type", "household")
            .out("member")
            .out("has_identity").
        values("uid")
    )


def draw_referenced_subgraph(g, transient_id):
    graph = drawing.spring_layout(
        _build_networkx_graph(
            g,
            g.V(transient_id).in_("has_identity").in_("member").next()
        )
    )

    drawing.draw(
        title="Single identity group graph structure",
        scatters=[
            drawing.edges_scatter(graph)
        ] + list(
            drawing.scatters_by_label(
                graph, attrs_to_skip=["pos"],
                sizes={"identityGroup": 60, "transientId": 20, "persistentId": 40}
            )
        ),
        annotations=drawing.edge_annotations(graph)
    )


# ===========================
# Everything below was added to introspect the query results via visualisations


def _get_identity_group_hierarchy(g, identity_group_id):
    return (
        g.V(identity_group_id)
            .project("props", "persistent_ids")
                .by(valueMap(True))
                .by(
                    out("member")
                    .group()
                    .by()
                    .by(
                        project("props", "transient_ids")
                            .by(valueMap(True))
                            .by(
                                out("has_identity").valueMap(True).fold()
                        )
                    ).select(Column.values)
                )
    )


def _build_networkx_graph(g, identity_group_id):
    def get_attributes(attribute_list):
        attrs = {}
        for attr_name, value in attribute_list:
            attr_name = str(attr_name)

            if isinstance(value, Iterable) and not isinstance(value, str):
                for i, single_val in enumerate(value):
                    attrs[f"{attr_name}-{i}"] = single_val
            else:
                if '.' in attr_name:
                    attr_name = attr_name.split('.')[-1]
                attrs[attr_name] = value

        return attrs

    graph = nx.Graph()

    for ig_node in _get_identity_group_hierarchy(g, identity_group_id).toList():
        ig_id = ig_node["props"][T.id]

        graph.add_node(
            ig_id,
            **get_attributes(ig_node["props"].items())
        )

        for persistent_node in ig_node["persistent_ids"]:
            p_id = persistent_node["props"][T.id]
            graph.add_node(
                p_id,
                **get_attributes(persistent_node["props"].items())
            )
            graph.add_edge(ig_id, p_id, label="member")

            for transient_node_map in persistent_node["transient_ids"]:
                transient_id = transient_node_map[T.id]
                graph.add_node(
                    transient_id,
                    **get_attributes(transient_node_map.items())
                )
                graph.add_edge(transient_id, p_id, label="has_identity")

    return graph

Use case: user has visited a travel agency website recently. Advertisers want to display ads about travel promotions to all members of his household. Given transient id, get all transient ids from its household. # =========================== # Everything below was added to introspect the query results via visualisations