"""Two-panel illustration of the proof of Lemma 5.2 (a Heawood-constant
Kempe cycle does not admit the clause-(3) arc of Conjecture 5.1).

Each panel shows two consecutive vertices v_0, v_1 on the {a, b}-Kempe
cycle K, joined by an edge e, with h(v_0) = h(v_1) = +1: i.e., both
have the same clockwise colour order (a, b, c). The would-be witness
edges (b-edges in Case A, a-edges in Case B) lie on opposite sides of
e, so no face of the graph contains both of them.

Left panel (Case A): phi(e) = a.  The b-edges at v_0, v_1 are on
                     opposite sides of e (one south, one north).

Right panel (Case B): phi(e) = b. The a-edges at v_0, v_1 are on
                      opposite sides of e.

Produces fig_lemma_kempe_heawood.png.
"""
import math
import os
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon

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

DARK = '#374151'
GRAY = '#9ca3af'

COL_A = '#ea580c'   # 'a'
COL_B = '#2563eb'   # 'b'
COL_C = '#16a34a'   # 'c'

FACE_FILL_R = '#fef3c7'   # F_R shading (south)
FACE_FILL_L = '#dbeafe'   # F_L shading (north)

V0 = (-1.6, 0.0)
V1 = ( 1.6, 0.0)


def edge_at(v, angle_deg, length=1.4):
    a = math.radians(angle_deg)
    return (v[0] + length * math.cos(a), v[1] + length * math.sin(a))


def draw_edge(ax, p, q, color, lw=2.6, zorder=2):
    ax.plot([p[0], q[0]], [p[1], q[1]], color=color, lw=lw,
            solid_capstyle='round', zorder=zorder)


def draw_vertex(ax, p, color=DARK, size=110, zorder=4):
    ax.scatter([p[0]], [p[1]], s=size, color=color, zorder=zorder)


def draw_stub(ax, p, color=DARK, size=45, zorder=4):
    ax.scatter([p[0]], [p[1]], s=size, color=color, zorder=zorder)


def label_text(ax, p, text, color=DARK, fontsize=12, dx=0, dy=0,
               weight='normal'):
    ax.text(p[0] + dx, p[1] + dy, text, ha='center', va='center',
            fontsize=fontsize, color=color, zorder=6, weight=weight,
            bbox=dict(boxstyle='round,pad=0.18', facecolor='white',
                      edgecolor='none', alpha=0.85))


def label_edge_midpoint(ax, p, q, text, color, fontsize=10, offset=(0, 0)):
    mid = ((p[0] + q[0]) / 2 + offset[0],
           (p[1] + q[1]) / 2 + offset[1])
    ax.text(mid[0], mid[1], text, ha='center', va='center',
            fontsize=fontsize, color=color, zorder=6,
            bbox=dict(boxstyle='round,pad=0.16', facecolor='white',
                      edgecolor='none', alpha=0.9))


def shade_face(ax, pts, color, alpha=0.55):
    poly = Polygon(pts, facecolor=color, edgecolor='none',
                   alpha=alpha, zorder=1)
    ax.add_patch(poly)


def panel_case_A(ax):
    # Same Heawood: v_0 and v_1 both have CW order (a, b, c) with e = a.
    #   v_0: e at 0 deg (east), b at 300 deg (south), c at 60 deg (north).
    #   v_1: e at 180 deg (west), b at 90 deg (north), c at 270 deg (south).
    # The b-edges land on opposite sides of e (south of v_0, north of v_1).
    b0 = edge_at(V0, 300)   # south of v_0
    c0 = edge_at(V0, 60)    # north of v_0
    b1 = edge_at(V1, 90)    # north of v_1
    c1 = edge_at(V1, 270)   # south of v_1

    # Shade both F_R (south) and F_L (north) lightly.
    shade_face(ax, [V0, V1, c1, (c1[0] + 0.3, c1[1] - 0.6),
                    (b0[0] - 0.3, b0[1] - 0.6), b0], color=FACE_FILL_R)
    shade_face(ax, [V0, c0, (c0[0] - 0.3, c0[1] + 0.6),
                    (b1[0] + 0.3, b1[1] + 0.6), b1, V1], color=FACE_FILL_L)
    label_text(ax, ((V0[0] + V1[0]) / 2, -1.7), '$F_R$', color=DARK,
               fontsize=11, weight='bold')
    label_text(ax, ((V0[0] + V1[0]) / 2, 1.7), '$F_L$', color=DARK,
               fontsize=11, weight='bold')

    draw_edge(ax, V0, V1, COL_A)
    draw_edge(ax, V0, b0, COL_B)
    draw_edge(ax, V0, c0, COL_C)
    draw_edge(ax, V1, b1, COL_B)
    draw_edge(ax, V1, c1, COL_C)

    draw_vertex(ax, V0, DARK); draw_vertex(ax, V1, DARK)
    draw_stub(ax, b0); draw_stub(ax, c0)
    draw_stub(ax, b1); draw_stub(ax, c1)

    label_text(ax, V0, '$v_0$', dy=0.28, fontsize=12)
    label_text(ax, (V0[0] - 0.05, V0[1] - 0.28), '$h_\\varphi\\!=\\!+1$',
               color=DARK, fontsize=9)
    label_text(ax, V1, '$v_1$', dy=0.28, fontsize=12)
    label_text(ax, (V1[0] + 0.05, V1[1] - 0.28), '$h_\\varphi\\!=\\!+1$',
               color=DARK, fontsize=9)

    label_edge_midpoint(ax, V0, V1, '$e\\!=\\!a$', color=COL_A,
                        offset=(0, 0.18))
    label_edge_midpoint(ax, V0, b0, '$b$', color=COL_B,
                        offset=(-0.15, 0))
    label_edge_midpoint(ax, V0, c0, '$c$', color=COL_C,
                        offset=(-0.15, 0))
    label_edge_midpoint(ax, V1, b1, '$b$', color=COL_B,
                        offset=(0.15, 0))
    label_edge_midpoint(ax, V1, c1, '$c$', color=COL_C,
                        offset=(0.15, 0))

    ax.set_title('Case A: $\\varphi(e) = a$.  The two $b$-edges are on\n'
                 'opposite sides of $e$ -- no common face',
                 fontsize=11, color=DARK, pad=8, fontweight='bold')


def panel_case_B(ax):
    # Same Heawood: v_0 and v_1 both have CW order (a, b, c) with e = b.
    #   v_0: a at 60 deg (north), e (b) at 0 deg (east), c at 300 deg (south).
    #   v_1: a at 270 deg (south), e (b) at 180 deg (west), c at 90 deg (north).
    # The a-edges land on opposite sides of e (north of v_0, south of v_1).
    a0 = edge_at(V0, 60)    # north of v_0
    c0 = edge_at(V0, 300)   # south of v_0
    a1 = edge_at(V1, 270)   # south of v_1
    c1 = edge_at(V1, 90)    # north of v_1

    shade_face(ax, [V0, V1, a1, (a1[0] + 0.3, a1[1] - 0.6),
                    (c0[0] - 0.3, c0[1] - 0.6), c0], color=FACE_FILL_R)
    shade_face(ax, [V0, a0, (a0[0] - 0.3, a0[1] + 0.6),
                    (c1[0] + 0.3, c1[1] + 0.6), c1, V1], color=FACE_FILL_L)
    label_text(ax, ((V0[0] + V1[0]) / 2, -1.7), '$F_R$', color=DARK,
               fontsize=11, weight='bold')
    label_text(ax, ((V0[0] + V1[0]) / 2, 1.7), '$F_L$', color=DARK,
               fontsize=11, weight='bold')

    draw_edge(ax, V0, V1, COL_B)
    draw_edge(ax, V0, a0, COL_A)
    draw_edge(ax, V0, c0, COL_C)
    draw_edge(ax, V1, a1, COL_A)
    draw_edge(ax, V1, c1, COL_C)

    draw_vertex(ax, V0, DARK); draw_vertex(ax, V1, DARK)
    draw_stub(ax, a0); draw_stub(ax, c0)
    draw_stub(ax, a1); draw_stub(ax, c1)

    label_text(ax, V0, '$v_0$', dy=0.28, fontsize=12)
    label_text(ax, (V0[0] - 0.05, V0[1] - 0.28), '$h_\\varphi\\!=\\!+1$',
               color=DARK, fontsize=9)
    label_text(ax, V1, '$v_1$', dy=0.28, fontsize=12)
    label_text(ax, (V1[0] + 0.05, V1[1] - 0.28), '$h_\\varphi\\!=\\!+1$',
               color=DARK, fontsize=9)

    label_edge_midpoint(ax, V0, V1, '$e\\!=\\!b$', color=COL_B,
                        offset=(0, -0.18))
    label_edge_midpoint(ax, V0, a0, '$a$', color=COL_A,
                        offset=(-0.15, 0))
    label_edge_midpoint(ax, V0, c0, '$c$', color=COL_C,
                        offset=(-0.15, 0))
    label_edge_midpoint(ax, V1, a1, '$a$', color=COL_A,
                        offset=(0.15, 0))
    label_edge_midpoint(ax, V1, c1, '$c$', color=COL_C,
                        offset=(0.15, 0))

    ax.set_title('Case B: $\\varphi(e) = b$.  The two $a$-edges are on\n'
                 'opposite sides of $e$ -- no common face',
                 fontsize=11, color=DARK, pad=8, fontweight='bold')


def main():
    fig, axes = plt.subplots(1, 2, figsize=(13, 5.8))
    for ax in axes:
        ax.set_xlim(-3.5, 3.5)
        ax.set_ylim(-2.5, 2.5)
        ax.set_aspect('equal')
        ax.axis('off')
    panel_case_A(axes[0])
    panel_case_B(axes[1])
    plt.subplots_adjust(left=0.02, right=0.98, top=0.90, bottom=0.04,
                        wspace=0.05)
    out = os.path.join(OUT_DIR, 'fig_lemma_kempe_heawood.png')
    plt.savefig(out, dpi=180, bbox_inches='tight')
    print(f"wrote {out}")


if __name__ == '__main__':
    main()
