"""
Fast coverage analysis using WL hash for iso-class lookup.
"""
import sys; sys.path.insert(0, '/home/claude/build')
import networkx as nx
import time
from collections import defaultdict
from level_cycles import all_level_resolutions
from triangulation_gen_fast import enumerate_all_triangulations_fast, wl_hash


def build_iso_index(reps):
    """Map WL hash -> list of (idx, G) so iso-checks only run within hash bucket."""
    idx = defaultdict(list)
    for i, G in enumerate(reps):
        idx[wl_hash(G)].append((i, G))
    return idx


def iso_class_fast(G, iso_index):
    h = wl_hash(G)
    for i, R in iso_index.get(h, []):
        if nx.is_isomorphic(G, R):
            return i
    return -1


def resolution_classes_fast(G, iso_index):
    return {iso_class_fast(Gp, iso_index)
            for Gp, _, _, _ in all_level_resolutions(G)
            if iso_class_fast(Gp, iso_index) >= 0}


def min_degree(G):
    return min(d for _, d in G.degree())


def coverage_at(n, report_every=100):
    t0 = time.time()
    reps = enumerate_all_triangulations_fast(n)
    iso_index = build_iso_index(reps)
    print(f"n={n}: {len(reps)} iso-classes enumerated and indexed "
          f"({time.time()-t0:.1f}s)")
    md4_idx = set(i for i, G in enumerate(reps) if min_degree(G) >= 4)

    t1 = time.time()
    produced_by = {}
    for i, G in enumerate(reps):
        produced_by[i] = resolution_classes_fast(G, iso_index)
        if (i + 1) % report_every == 0:
            elapsed = time.time() - t1
            eta = elapsed * (len(reps) - i - 1) / (i + 1)
            print(f"  {i+1}/{len(reps)}  ({elapsed:.0f}s, ETA {eta:.0f}s)")
    print(f"Resolution computation: {time.time()-t1:.1f}s")

    all_prod = set().union(*produced_by.values())
    uncovered = set(range(len(reps))) - all_prod
    md4_reached = set().union(*(produced_by[i] & md4_idx
                                for i in range(len(reps))))
    md4_uncov = md4_idx - md4_reached

    print(f"\nGeneral coverage: {len(reps) - len(uncovered)}/{len(reps)}")
    if uncovered:
        for i in sorted(uncovered):
            deg = sorted((d for _, d in reps[i].degree()), reverse=True)
            print(f"  uncovered T{i}: degree {deg}")
    print(f"md4 coverage:     {len(md4_idx) - len(md4_uncov)}/{len(md4_idx)}")
    if md4_uncov:
        for i in sorted(md4_uncov):
            deg = sorted((d for _, d in reps[i].degree()), reverse=True)
            print(f"  uncovered md4 T{i}: degree {deg}")
    print(f"Total: {time.time()-t0:.1f}s")


if __name__ == "__main__":
    for n in [11]:
        print("=" * 60)
        coverage_at(n, report_every=100)
