"""Draw the claimed (R1) violation: n=9, source=5, depth=1, vertex 9.

The depth-1 component has 9 triangles, and vertex 9 has 4 of them
incident (in two arcs of the rotation around 9, separated by 2
depth-2 faces -- the two triangles of the bowtie at L_2).

The question: is vertex 9 a real "pinch" of the tire, or is it just
a cut-vertex of the inner outerplanar graph O (= the bowtie on
{2, 3, 7, 8, 9}), naturally handled by the relaxed Definition 1.5?
"""
import math
import os
import sys
from collections import defaultdict

from sage.all import Graph
import matplotlib.pyplot as plt
import matplotlib.patches as patches

HERE = os.path.dirname(os.path.abspath(__file__))

EDGES = [(1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9),
         (2, 3), (2, 9), (3, 4), (3, 9), (4, 5), (4, 6), (4, 7), (4, 9),
         (5, 6), (6, 7), (7, 8), (7, 9), (8, 9)]
SOURCE = 5


def main():
    G = Graph(EDGES)
    G.is_planar(set_embedding=True)
    emb = G.get_embedding()
    dist = G.shortest_path_lengths(SOURCE)

    # Pick an external face that doesn't contain source 5 so source
    # ends up in the interior.
    # Faces of G that don't contain 5: triangle {1,2,3} for example.
    pos = G.layout(layout='planar', external_face=(1, 2))
    # Normalise
    xs = [p[0] for p in pos.values()]; ys = [p[1] for p in pos.values()]
    cx, cy = (max(xs)+min(xs))/2, (max(ys)+min(ys))/2
    scale = max(max(xs)-min(xs), max(ys)-min(ys))
    pos = {v: ((p[0]-cx)/scale, (p[1]-cy)/scale) for v, p in pos.items()}

    faces = G.faces(embedding=emb)
    face_depths = []
    for face in faces:
        verts = set()
        for u, v in face:
            verts.add(u); verts.add(v)
        d = min(dist[u] for u in verts)
        face_depths.append((face, d, verts))
    depth1_faces = [fd for fd in face_depths if fd[1] == 1]
    depth2_faces = [fd for fd in face_depths if fd[1] == 2]

    fig, ax = plt.subplots(figsize=(10, 9))

    # Fill depth-1 faces (R_{C'})
    for face, _, _ in depth1_faces:
        verts = [e[0] for e in face]
        xy = [pos[v] for v in verts]
        poly = plt.Polygon(xy, facecolor='#fff3cd', edgecolor='#e8d8a8',
                           linewidth=0.5, alpha=0.85, zorder=1)
        ax.add_patch(poly)

    # Fill depth-2 faces (the bowtie's two triangles) in a different colour
    for face, _, _ in depth2_faces:
        verts = [e[0] for e in face]
        xy = [pos[v] for v in verts]
        poly = plt.Polygon(xy, facecolor='#d62728', edgecolor='#a01818',
                           linewidth=0.5, alpha=0.40, zorder=1)
        ax.add_patch(poly)

    # All edges of G in grey
    for u, v in G.edges(labels=False):
        x1, y1 = pos[u]; x2, y2 = pos[v]
        ax.plot([x1, x2], [y1, y2], color='lightgray', linewidth=1.0,
                zorder=2)

    # Highlight the bowtie edges (= edges of O = G[L_2])
    L2 = [v for v in G.vertices() if dist[v] == 2]
    print(f"L_2 = {sorted(L2)}")
    bowtie_edges = [(u, v) for u, v in G.edges(labels=False)
                    if u in L2 and v in L2]
    print(f"Edges of O = G[L_2]: {bowtie_edges}")
    for u, v in bowtie_edges:
        x1, y1 = pos[u]; x2, y2 = pos[v]
        ax.plot([x1, x2], [y1, y2], color='#a01818', linewidth=3.0,
                zorder=3)

    # Highlight the source-side cycle = G[L_1]
    L1 = [v for v in G.vertices() if dist[v] == 1]
    print(f"L_1 = {sorted(L1)}")
    L1_edges = [(u, v) for u, v in G.edges(labels=False)
                if u in L1 and v in L1]
    print(f"Edges of B_out candidate = G[L_1]: {L1_edges}")
    for u, v in L1_edges:
        x1, y1 = pos[u]; x2, y2 = pos[v]
        ax.plot([x1, x2], [y1, y2], color='#1f77b4', linewidth=3.0,
                zorder=3)

    # Vertices
    level_colors = {0: 'black', 1: '#1f77b4', 2: '#d62728'}
    for v in G.vertices():
        x, y = pos[v]
        c = level_colors.get(dist[v], 'gray')
        ax.plot(x, y, 'o', color=c, markersize=22, zorder=4)
        ax.annotate(f"{v}", (x, y), color='white', ha='center', va='center',
                    fontsize=11, fontweight='bold', zorder=5)

    # Special annotation: vertex 9 is the cut-vertex of O
    if 9 in pos:
        x, y = pos[9]
        ax.annotate('cut-vertex of $O$',
                    xy=(x, y), xytext=(x + 0.10, y + 0.18),
                    fontsize=10, color='#a01818', fontweight='bold',
                    arrowprops=dict(arrowstyle='->', color='#a01818', lw=1.5),
                    zorder=6,
                    bbox=dict(boxstyle='round,pad=0.25',
                              facecolor='white', edgecolor='#a01818',
                              alpha=0.95))

    if SOURCE in pos:
        sx, sy = pos[SOURCE]
        ax.annotate(f'source $v_0={SOURCE}$',
                    xy=(sx, sy), xytext=(sx + 0.08, sy + 0.10),
                    fontsize=10, color='black', fontweight='bold',
                    arrowprops=dict(arrowstyle='->', color='black', lw=1.2),
                    zorder=6,
                    bbox=dict(boxstyle='round,pad=0.2',
                              facecolor='white', edgecolor='gray', alpha=0.95))

    legend_items = [
        plt.Line2D([], [], marker='o', color='w', markerfacecolor='black',
                   markersize=12, label=f'source ($\\ell=0$)'),
        plt.Line2D([], [], marker='o', color='w', markerfacecolor='#1f77b4',
                   markersize=12, label='$\\ell=1$'),
        plt.Line2D([], [], marker='o', color='w', markerfacecolor='#d62728',
                   markersize=12, label='$\\ell=2$'),
        patches.Patch(facecolor='#fff3cd', edgecolor='#e8d8a8',
                      label='$R_{C^\\prime}$ (depth-1 component, '
                            '9 triangles)'),
        patches.Patch(facecolor='#d62728', alpha=0.4,
                      label='depth-2 faces (interior faces of $O$)'),
        plt.Line2D([], [], color='#1f77b4', linewidth=3.0,
                   label='$B_{\\mathrm{out}} = G[L_1]$'),
        plt.Line2D([], [], color='#a01818', linewidth=3.0,
                   label='$O = G[L_2]$ = bowtie with cut-vertex 9'),
    ]
    ax.legend(handles=legend_items, loc='upper right', fontsize=9,
              framealpha=0.95)

    ax.set_title(
        '"(R1) candidate": vertex 9 is a cut-vertex of $O$ (the bowtie),\n'
        'not a true pinch of the tire under the relaxed Definition 1.5\n'
        '(n=9, source $v_0=5$, depth 1)',
        fontsize=11)
    ax.set_aspect('equal')
    ax.axis('off')
    pad = 0.08
    ax.set_xlim(min(p[0] for p in pos.values()) - pad,
                max(p[0] for p in pos.values()) + pad)
    ax.set_ylim(min(p[1] for p in pos.values()) - pad,
                max(p[1] for p in pos.values()) + pad)

    out = os.path.join(HERE, 'r1_candidate.png')
    plt.savefig(out, dpi=160, bbox_inches='tight')
    plt.close()
    print(f"wrote {out}")


if __name__ == '__main__':
    main()
