"""Empirical check of Lemma 5.8 (good contraction).

For every md4 plane triangulation iso-class at n in {7, 8, 9, 10, 11},
verify that there exists a degree-4 vertex v with cyclic neighbors
(a, b, c, d) and a diagonal (a, c) such that:
  (1) (a, c) is not an edge of T,
  (2) deg(b) >= 5 and deg(d) >= 5.

Equivalently, the contracted triangulation T_{v, (a,c)} has min deg >= 4.

Reports:
  - Total md4 iso-classes at each n
  - How many have at least one good contraction
  - Iso-classes without a good contraction (if any)
  - For each iso-class, how many degree-4 vertices admit a good contraction
"""
import sys, os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import networkx as nx
from triangulation_gen import enumerate_all_triangulations
from triangulation_gen_fast import enumerate_all_triangulations_fast


def is_md4(T):
    return min(T.degree(v) for v in T.nodes()) >= 4


def cyclic_neighbors(G, v):
    ip, emb = nx.check_planarity(G)
    if not ip:
        return None
    return list(emb.neighbors_cw_order(v))


def good_contractions_for_vertex(T, v):
    """Return list of valid diagonals (u, w) such that contracting v
    along (u, w) preserves md4."""
    if T.degree(v) != 4:
        return []
    cyc = cyclic_neighbors(T, v)
    if cyc is None or len(cyc) != 4:
        return []
    a, b, c, d = cyc
    good = []
    for (u, w, opp1, opp2) in [(a, c, b, d), (b, d, a, c)]:
        if T.has_edge(u, w):
            continue
        # After contraction, opp1 and opp2 lose 1 degree each.
        if T.degree(opp1) - 1 < 4:
            continue
        if T.degree(opp2) - 1 < 4:
            continue
        good.append((u, w))
    return good


def check_n(n):
    if n >= 11:
        isos = enumerate_all_triangulations_fast(n)
    else:
        isos = enumerate_all_triangulations(n)
    md4 = [(i, T) for i, T in enumerate(isos) if is_md4(T)]
    total = len(md4)
    with_good = 0
    no_good = []
    counts_per_class = []
    for idx, T in md4:
        deg4_verts = [v for v in T.nodes() if T.degree(v) == 4]
        good_count_for_class = 0
        for v in deg4_verts:
            good = good_contractions_for_vertex(T, v)
            if good:
                good_count_for_class += 1
        if good_count_for_class > 0:
            with_good += 1
        else:
            no_good.append(idx)
        counts_per_class.append(good_count_for_class)
    print(f"n={n}: {total} md4 iso-classes")
    print(f"  with at least one good contraction: {with_good} / {total}")
    if no_good:
        print(f"  iso-classes WITHOUT a good contraction: {no_good}")
    if counts_per_class:
        print(f"  good-deg-4-vertices per class: "
              f"min={min(counts_per_class)}, "
              f"max={max(counts_per_class)}, "
              f"median={sorted(counts_per_class)[len(counts_per_class)//2]}")


if __name__ == "__main__":
    ns = [int(x) for x in sys.argv[1:]] if len(sys.argv) > 1 \
        else [7, 8, 9, 10, 11]
    for n in ns:
        check_n(n)
