"""Schematic illustration of an (R2)-violating tire component.

A connected depth-d face component R_{C'} that has THREE boundary
components: one toward the source side (level d cycle), and two toward
the depth->d side (two distinct deeper lobes each enclosed by R_{C'}).

This is the topological "pair of pants" / trinion: a planar 2-manifold
with three boundary curves, Euler characteristic -1.
"""
import math
import os
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.patches import Circle, Polygon, FancyArrowPatch


def draw_r2_violation(filename):
    fig, ax = plt.subplots(figsize=(8.5, 7))

    # Outer boundary of R_{C'} -- a large ellipse-like blob
    outer_r = 3.2

    # Three holes
    # Source hole on the left
    source_center = (-1.6, 0.2)
    source_r = 0.7

    # Two deeper lobes on the right
    lobe1_center = (1.3, 1.1)
    lobe1_r = 0.55

    lobe2_center = (1.3, -1.1)
    lobe2_r = 0.55

    # Draw the filled R_{C'} region: outer ellipse minus three discs.
    # Using a Path with the outer circle and three reversed inner circles.
    from matplotlib.path import Path
    import numpy as np

    def circle_verts(cx, cy, r, n=80, reverse=False):
        ts = np.linspace(0, 2 * np.pi, n, endpoint=False)
        if reverse:
            ts = ts[::-1]
        return [(cx + r * np.cos(t), cy + r * np.sin(t)) for t in ts]

    outer_verts = circle_verts(0, 0, outer_r, n=120)
    # Make outer ellipse instead of circle
    outer_verts = [(1.4 * x, y) for (x, y) in outer_verts]

    inner1 = circle_verts(*source_center, source_r, n=60, reverse=True)
    inner2 = circle_verts(*lobe1_center, lobe1_r, n=60, reverse=True)
    inner3 = circle_verts(*lobe2_center, lobe2_r, n=60, reverse=True)

    verts = (outer_verts + [outer_verts[0]]
             + inner1 + [inner1[0]]
             + inner2 + [inner2[0]]
             + inner3 + [inner3[0]])

    codes = ([Path.MOVETO] + [Path.LINETO] * (len(outer_verts) - 1) + [Path.CLOSEPOLY]
             + [Path.MOVETO] + [Path.LINETO] * (len(inner1) - 1) + [Path.CLOSEPOLY]
             + [Path.MOVETO] + [Path.LINETO] * (len(inner2) - 1) + [Path.CLOSEPOLY]
             + [Path.MOVETO] + [Path.LINETO] * (len(inner3) - 1) + [Path.CLOSEPOLY])

    path = Path(verts, codes)
    patch = patches.PathPatch(path, facecolor='#fff3cd', edgecolor='none',
                              alpha=0.85, zorder=1)
    ax.add_patch(patch)

    # Draw the three boundary curves on top
    def plot_curve(verts, color, lw=2.5, label_pt=None, label_text=None,
                   label_offset=(0, 0), label_color=None):
        xs = [v[0] for v in verts] + [verts[0][0]]
        ys = [v[1] for v in verts] + [verts[0][1]]
        ax.plot(xs, ys, color=color, linewidth=lw, zorder=2)
        if label_pt is not None and label_text is not None:
            ax.annotate(label_text, xy=label_pt,
                        xytext=(label_pt[0] + label_offset[0],
                                label_pt[1] + label_offset[1]),
                        fontsize=11, ha='center', va='center',
                        color=label_color or color, zorder=3,
                        bbox=dict(boxstyle='round,pad=0.3',
                                  edgecolor='none', facecolor='white',
                                  alpha=0.85))

    plot_curve(outer_verts, '#1f77b4', lw=2.8)
    plot_curve(inner1, '#d62728', lw=2.5)
    plot_curve(inner2, '#d62728', lw=2.5)
    plot_curve(inner3, '#d62728', lw=2.5)

    # Source vertex marker in the source hole
    sx, sy = source_center
    ax.plot(sx, sy, 'o', color='black', markersize=12, zorder=4)
    ax.annotate(r'$S = \{v_0\}$', xy=(sx, sy),
                xytext=(sx, sy - 0.32),
                fontsize=11, ha='center', va='top', zorder=4,
                bbox=dict(boxstyle='round,pad=0.25',
                          edgecolor='gray', facecolor='white', alpha=0.95))

    # Region labels
    ax.annotate(r'$R_{C^\prime}$  (depth-$d$ region)',
                xy=(-3.5, 2.6), fontsize=14, ha='left', va='center',
                color='#9a7d2a', fontweight='bold')

    # Labels for the three boundary cycles
    ax.annotate(r'outer boundary' + '\n' + r'on $L_{d}$ (source side)',
                xy=(-1.6 + 0.7 + 0.05, 0.2), xytext=(-2.0, -1.6),
                fontsize=10, ha='center', color='#d62728',
                arrowprops=dict(arrowstyle='->', color='#d62728', lw=1.2))

    ax.annotate(r'lobe boundary on $L_{d+1}$',
                xy=(1.3 + 0.55 - 0.05, 1.1), xytext=(3.0, 2.4),
                fontsize=10, ha='left', color='#d62728',
                arrowprops=dict(arrowstyle='->', color='#d62728', lw=1.2))

    ax.annotate(r'lobe boundary on $L_{d+1}$',
                xy=(1.3 + 0.55 - 0.05, -1.1), xytext=(3.0, -2.4),
                fontsize=10, ha='left', color='#d62728',
                arrowprops=dict(arrowstyle='->', color='#d62728', lw=1.2))

    ax.annotate(r'outer ellipse $=$' + '\n' + r'outer face of $\Pi_G$',
                xy=(-3.5 * 1.4 + 0.2, 0), xytext=(-4.8, 0),
                fontsize=10, ha='center', color='#1f77b4',
                arrowprops=dict(arrowstyle='->', color='#1f77b4', lw=1.2))

    # Lobe interior annotations
    ax.annotate('depth-$> d$\nlobe A',
                xy=lobe1_center, fontsize=10, ha='center', va='center',
                color='#444', style='italic')
    ax.annotate('depth-$> d$\nlobe B',
                xy=lobe2_center, fontsize=10, ha='center', va='center',
                color='#444', style='italic')

    # Title / caption text
    ax.text(0, 3.4,
            '(R2) violation: $R_{C^\\prime}$ has 3 boundary components',
            fontsize=13, ha='center', fontweight='bold')
    ax.text(0, -3.2,
            r'$\chi(R_{C^\prime}) = V - E + F = 2 - n_{\mathrm{bdy}} = -1$',
            fontsize=11, ha='center', color='#666')

    ax.set_xlim(-5.5, 5.5)
    ax.set_ylim(-3.6, 3.7)
    ax.set_aspect('equal')
    ax.axis('off')

    plt.savefig(filename, dpi=160, bbox_inches='tight')
    plt.close()


if __name__ == '__main__':
    here = os.path.dirname(os.path.abspath(__file__))
    out = os.path.join(here, 'r2_violation_schematic.png')
    draw_r2_violation(out)
    print(f'wrote {out}')
