import pytest

import networkx as nx


def test_tikz_attributes():
    G = nx.path_graph(4, create_using=nx.DiGraph)
    pos = {n: (n, n) for n in G}

    G.add_edge(0, 0)
    G.edges[(0, 0)]["label"] = "Loop"
    G.edges[(0, 0)]["label_options"] = "midway"

    G.nodes[0]["style"] = "blue"
    G.nodes[1]["style"] = "line width=3,draw"
    G.nodes[2]["style"] = "circle,draw,blue!50"
    G.nodes[3]["label"] = "Stop"
    G.edges[(0, 1)]["label"] = "1st Step"
    G.edges[(0, 1)]["label_options"] = "near end"
    G.edges[(2, 3)]["label"] = "3rd Step"
    G.edges[(2, 3)]["label_options"] = "near start"
    G.edges[(2, 3)]["style"] = "bend left,green"
    G.edges[(1, 2)]["label"] = "2nd"
    G.edges[(1, 2)]["label_options"] = "pos=0.5"
    G.edges[(1, 2)]["style"] = ">->,bend right,line width=3,green!90"

    output_tex = nx.to_latex(
        G,
        pos=pos,
        as_document=False,
        tikz_options="[scale=3]",
        node_options="style",
        edge_options="style",
        node_label="label",
        edge_label="label",
        edge_label_options="label_options",
    )
    expected_tex = r"""\begin{figure}
  \begin{tikzpicture}[scale=3]
      \draw
        (0, 0) node[blue] (0){0}
        (1, 1) node[line width=3,draw] (1){1}
        (2, 2) node[circle,draw,blue!50] (2){2}
        (3, 3) node (3){Stop};
      \begin{scope}[->]
        \draw (0) to node[near end] {1st Step} (1);
        \draw[loop,] (0) to node[midway] {Loop} (0);
        \draw[>->,bend right,line width=3,green!90] (1) to node[pos=0.5] {2nd} (2);
        \draw[bend left,green] (2) to node[near start] {3rd Step} (3);
      \end{scope}
    \end{tikzpicture}
\end{figure}"""

    # First, check for consistency line-by-line - if this fails, the mismatched
    # line will be shown explicitly in the failure summary
    for expected, actual in zip(expected_tex.split("\n"), output_tex.split("\n")):
        assert expected == actual

    assert output_tex == expected_tex


def test_basic_multiple_graphs():
    H1 = nx.path_graph(4)
    H2 = nx.complete_graph(4)
    H3 = nx.path_graph(8)
    H4 = nx.complete_graph(8)
    captions = [
        "Path on 4 nodes",
        "Complete graph on 4 nodes",
        "Path on 8 nodes",
        "Complete graph on 8 nodes",
    ]
    labels = ["fig2a", "fig2b", "fig2c", "fig2d"]
    latex_code = nx.to_latex(
        [H1, H2, H3, H4],
        n_rows=2,
        sub_captions=captions,
        sub_labels=labels,
    )
    assert "begin{document}" in latex_code
    assert "begin{figure}" in latex_code
    assert latex_code.count("begin{subfigure}") == 4
    assert latex_code.count("tikzpicture") == 8
    assert latex_code.count("[-]") == 4


def test_basic_tikz():
    expected_tex = r"""\documentclass{report}
\usepackage{tikz}
\usepackage{subcaption}

\begin{document}
\begin{figure}
  \begin{subfigure}{0.5\textwidth}
  \begin{tikzpicture}[scale=2]
      \draw[gray!90]
        (0.749, 0.702) node[red!90] (0){0}
        (1.0, -0.014) node[red!90] (1){1}
        (-0.777, -0.705) node (2){2}
        (-0.984, 0.042) node (3){3}
        (-0.028, 0.375) node[cyan!90] (4){4}
        (-0.412, 0.888) node (5){5}
        (0.448, -0.856) node (6){6}
        (0.003, -0.431) node[cyan!90] (7){7};
      \begin{scope}[->,gray!90]
        \draw (0) to (4);
        \draw (0) to (5);
        \draw (0) to (6);
        \draw (0) to (7);
        \draw (1) to (4);
        \draw (1) to (5);
        \draw (1) to (6);
        \draw (1) to (7);
        \draw (2) to (4);
        \draw (2) to (5);
        \draw (2) to (6);
        \draw (2) to (7);
        \draw (3) to (4);
        \draw (3) to (5);
        \draw (3) to (6);
        \draw (3) to (7);
      \end{scope}
    \end{tikzpicture}
    \caption{My tikz number 1 of 2}\label{tikz_1_2}
  \end{subfigure}
  \begin{subfigure}{0.5\textwidth}
  \begin{tikzpicture}[scale=2]
      \draw[gray!90]
        (0.749, 0.702) node[green!90] (0){0}
        (1.0, -0.014) node[green!90] (1){1}
        (-0.777, -0.705) node (2){2}
        (-0.984, 0.042) node (3){3}
        (-0.028, 0.375) node[purple!90] (4){4}
        (-0.412, 0.888) node (5){5}
        (0.448, -0.856) node (6){6}
        (0.003, -0.431) node[purple!90] (7){7};
      \begin{scope}[->,gray!90]
        \draw (0) to (4);
        \draw (0) to (5);
        \draw (0) to (6);
        \draw (0) to (7);
        \draw (1) to (4);
        \draw (1) to (5);
        \draw (1) to (6);
        \draw (1) to (7);
        \draw (2) to (4);
        \draw (2) to (5);
        \draw (2) to (6);
        \draw (2) to (7);
        \draw (3) to (4);
        \draw (3) to (5);
        \draw (3) to (6);
        \draw (3) to (7);
      \end{scope}
    \end{tikzpicture}
    \caption{My tikz number 2 of 2}\label{tikz_2_2}
  \end{subfigure}
  \caption{A graph generated with python and latex.}
\end{figure}
\end{document}"""

    edges = [
        (0, 4),
        (0, 5),
        (0, 6),
        (0, 7),
        (1, 4),
        (1, 5),
        (1, 6),
        (1, 7),
        (2, 4),
        (2, 5),
        (2, 6),
        (2, 7),
        (3, 4),
        (3, 5),
        (3, 6),
        (3, 7),
    ]
    G = nx.DiGraph()
    G.add_nodes_from(range(8))
    G.add_edges_from(edges)
    pos = {
        0: (0.7490296171687696, 0.702353520257394),
        1: (1.0, -0.014221357723796535),
        2: (-0.7765783344161441, -0.7054170966808919),
        3: (-0.9842690223417624, 0.04177547602465483),
        4: (-0.02768523817180917, 0.3745724439551441),
        5: (-0.41154855146767433, 0.8880106515525136),
        6: (0.44780153389148264, -0.8561492709269164),
        7: (0.0032499953371383505, -0.43092436645809945),
    }

    rc_node_color = {0: "red!90", 1: "red!90", 4: "cyan!90", 7: "cyan!90"}
    gp_node_color = {0: "green!90", 1: "green!90", 4: "purple!90", 7: "purple!90"}

    H = G.copy()
    nx.set_node_attributes(G, rc_node_color, "color")
    nx.set_node_attributes(H, gp_node_color, "color")

    sub_captions = ["My tikz number 1 of 2", "My tikz number 2 of 2"]
    sub_labels = ["tikz_1_2", "tikz_2_2"]

    output_tex = nx.to_latex(
        [G, H],
        [pos, pos],
        tikz_options="[scale=2]",
        default_node_options="gray!90",
        default_edge_options="gray!90",
        node_options="color",
        sub_captions=sub_captions,
        sub_labels=sub_labels,
        caption="A graph generated with python and latex.",
        n_rows=2,
        as_document=True,
    )

    # First, check for consistency line-by-line - if this fails, the mismatched
    # line will be shown explicitly in the failure summary
    for expected, actual in zip(expected_tex.split("\n"), output_tex.split("\n")):
        assert expected == actual
    # Double-check for document-level consistency
    assert output_tex == expected_tex


def test_exception_pos_single_graph(to_latex=nx.to_latex):
    # smoke test that pos can be a string
    G = nx.path_graph(4)
    to_latex(G, pos="pos")

    # must include all nodes
    pos = {0: (1, 2), 1: (0, 1), 2: (2, 1)}
    with pytest.raises(nx.NetworkXError):
        to_latex(G, pos)

    # must have 2 values
    pos[3] = (1, 2, 3)
    with pytest.raises(nx.NetworkXError):
        to_latex(G, pos)
    pos[3] = 2
    with pytest.raises(nx.NetworkXError):
        to_latex(G, pos)

    # check that passes with 2 values
    pos[3] = (3, 2)
    to_latex(G, pos)


def test_exception_multiple_graphs(to_latex=nx.to_latex):
    G = nx.path_graph(3)
    pos_bad = {0: (1, 2), 1: (0, 1)}
    pos_OK = {0: (1, 2), 1: (0, 1), 2: (2, 1)}
    fourG = [G, G, G, G]
    fourpos = [pos_OK, pos_OK, pos_OK, pos_OK]

    # input single dict to use for all graphs
    to_latex(fourG, pos_OK)
    with pytest.raises(nx.NetworkXError):
        to_latex(fourG, pos_bad)

    # input list of dicts to use for all graphs
    to_latex(fourG, fourpos)
    with pytest.raises(nx.NetworkXError):
        to_latex(fourG, [pos_bad, pos_bad, pos_bad, pos_bad])

    # every pos dict must include all nodes
    with pytest.raises(nx.NetworkXError):
        to_latex(fourG, [pos_OK, pos_OK, pos_bad, pos_OK])

    # test sub_captions and sub_labels (len must match Gbunch)
    with pytest.raises(nx.NetworkXError):
        to_latex(fourG, fourpos, sub_captions=["hi", "hi"])

    with pytest.raises(nx.NetworkXError):
        to_latex(fourG, fourpos, sub_labels=["hi", "hi"])

    # all pass
    to_latex(fourG, fourpos, sub_captions=["hi"] * 4, sub_labels=["lbl"] * 4)


def test_exception_multigraph():
    G = nx.path_graph(4, create_using=nx.MultiGraph)
    G.add_edge(1, 2)
    with pytest.raises(nx.NetworkXNotImplemented):
        nx.to_latex(G)
