"""Step-verify the bridge-derivability witness for a 5-connected
non-Hamiltonian-dual core. Same outputs as verify_fig210_witness.py
(parity partition, ELG source/max level, both removed and added edges per
forward switch, bridge-condition validity check) but parametrized so it
works on any core's graph6.

Usage:
  sage -python verify_core_witness.py <input_g6_file>
"""
import sys
import os
sys.path.insert(0, '/Users/didericis/Code/math-research/papers/'
                'level_resolutions_of_maximal_planar_graphs/experiments')
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import networkx as nx
from sage.all import Graph  # type: ignore
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
from draw_core_witness import betti, neighbors, elg_src, find_witness


def main():
    if len(sys.argv) < 2:
        print('usage: verify_core_witness.py <input_g6_file>')
        sys.exit(1)
    g6 = open(sys.argv[1]).read().strip()
    T, _ = dual_triangulation(sage_to_nx(Graph(g6)))
    parts, _ = valid_parity_partitions_via_coloring(T)
    order = sorted(range(len(parts)), key=lambda k: betti(T, parts[k]))

    chosen = None
    for k in order[:200]:
        r = find_witness(T, parts[k], cap=40000)
        if r is not None:
            chosen = (k, parts[k], r)
            break
    assert chosen is not None, 'no witness found'
    k, labels, (src, _, _) = chosen

    code = EdgeCode(T.nodes())
    s0 = code.state_of(T)
    parent = {s0: None}
    frontier = [s0]
    W = None
    while frontier and W is None:
        nf = []
        for st in frontier:
            if elg_src(code, labels, st) is not None:
                W = st
                break
            for ns in neighbors(code, labels, 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]

    ok, lv = is_even_level_graph(code.graph_of(W), frozenset({src}))
    print('partition %d, source %d, max level %d, depth %d, ELG verified %s'
          % (k, src, max(lv.values()), len(path) - 1, ok))
    print('parity even =', sorted(v for v in T if labels[v] == 0))
    print('parity odd  =', sorted(v for v in T if labels[v] == 1))

    all_valid = True
    for i in range(len(path) - 1):
        A = set(map(frozenset, code.graph_of(path[i]).edges()))
        B = set(map(frozenset, code.graph_of(path[i + 1]).edges()))
        new = tuple(sorted(next(iter(B - A))))
        rem = tuple(sorted(next(iter(A - B))))
        Gp = code.graph_of(path[i + 1])
        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 Gp.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)'
        all_valid &= valid
        print('  switch %d: remove %s, add %s  [%s]  valid=%s'
              % (i + 1, rem, new, kind, valid))
    print('ALL STEPS VALID BRIDGE SWITCHES:', all_valid)


if __name__ == '__main__':
    main()
