import sys
E='/Users/didericis/Code/math-research/papers/even_level_graph_generators/experiments'
L='/Users/didericis/Code/math-research/papers/level_resolutions_of_maximal_planar_graphs/experiments'
sys.path.insert(0,E); sys.path.insert(0,L)
import networkx as nx
from sage.all import Graph
from tutte_dual_treecolor import dual_triangulation
from test_tutte_bridge import valid_parity_partitions_via_coloring
from test_fig210_dual_bridge import sage_to_nx
from fast_bridge import EdgeCode, parity_bridges
from test_conjecture import is_even_level_graph

g6=open('/tmp/nonham_duals.g6').read().split(None,1)[1].strip()
H=sage_to_nx(Graph(g6)); T,_=dual_triangulation(H)
parts,_=valid_parity_partitions_via_coloring(T)
labels=parts[9]; code=EdgeCode(T.nodes()); s0=code.state_of(T); n=24

def neighbors(state):
    G=code.graph_of(state); ok,emb=nx.check_planarity(G)
    ea={v:set() for v in code.nodes if labels[v]==0}; oa={v:set() for v in code.nodes if labels[v]==1}
    for u,v in G.edges():
        if labels[u]==labels[v]: (ea if labels[u]==0 else oa)[u].add(v);(ea if labels[u]==0 else oa)[v].add(u)
    br=parity_bridges(ea)|parity_bridges(oa); out=[]
    for u,v in G.edges():
        f1=emb.traverse_face(u,v)
        if len(f1)!=3: continue
        f2=emb.traverse_face(v,u)
        if len(f2)!=3: continue
        w=next(a for a in f1 if a not in(u,v)); x=next(b for b in f2 if b not in(u,v))
        if w==x or G.has_edge(w,x) or labels[w]!=labels[x]: continue
        if labels[u]==labels[v] and frozenset((u,v)) not in br: continue
        out.append((state&~(1<<code.bit(u,v)))|(1<<code.bit(w,x)))
    return out

def elg_src(state):
    G=code.graph_of(state)
    for s in code.nodes:
        cs=labels[s]; nb=set(G.neighbors(s))
        if not nb or any(labels[w]==cs for w in nb): continue
        ok,lv=is_even_level_graph(G,frozenset({s}))
        if ok and all((lv[v]%2==0)==(labels[v]==cs) for v in code.nodes): return s
    return None

parent={s0:None}; frontier=[s0]; W=None
while frontier and W is None:
    nf=[]
    for st in frontier:
        if elg_src(st) is not None: W=st; break
        for ns in neighbors(st):
            if ns not in parent: parent[ns]=st; nf.append(ns)
    if W: break
    frontier=nf
path=[]; c=W
while c is not None: path.append(c); c=parent[c]
# path[0]=ELG ... path[-1]=T (forward = ELG -> T)
src=elg_src(W)
print('=== Fig 2.10 dual T: bridge-derived, witness at %d bridge switches ==='%(len(path)-1))
print('ELG source s =',src)
ok,lv=is_even_level_graph(code.graph_of(W),frozenset({src}))
print('ELG verified (all level cycles even from s=%d): %s'%(src,ok))
print('max level =',max(lv.values()))
allgood=True
for k in range(len(path)-1):
    A=code.graph_of(path[k]); B=code.graph_of(path[k+1])
    EA=set(map(frozenset,A.edges())); EB=set(map(frozenset,B.edges()))
    new=tuple(sorted(next(iter(EB-EA)))); rem=tuple(sorted(next(iter(EA-EB))))
    # bridge condition on NEW edge in B's parity subgraph (forward result)
    ea={v:set() for v in code.nodes if labels[v]==0}; oa={v:set() for v in code.nodes if labels[v]==1}
    for u,v in B.edges():
        if labels[u]==labels[v]: (ea if labels[u]==0 else oa)[u].add(v);(ea if labels[u]==0 else oa)[v].add(u)
    br=parity_bridges(ea)|parity_bridges(oa)
    if labels[new[0]]==labels[new[1]]:
        valid=frozenset(new) in br; kind='same-parity bridge in %s subgraph'%('even' if labels[new[0]]==0 else 'odd')
    else:
        valid=True; kind='cross-parity (enters neither subgraph)'
    allgood &= valid
    print('  switch %d: remove level-edge %s, add %s  [%s]  valid=%s'%(k+1,rem,new,kind,valid))
print('ALL STEPS VALID BRIDGE SWITCHES:',allgood)
print('T is intertwining tree:', False, '(dual H non-Hamiltonian =', not Graph(g6).is_hamiltonian(),')')
