#!/usr/bin/env python3
"""
Comprehensive tests for the Braid Word Solver.
"""
import sys, math
sys.path.insert(0, '/home/allaun/SilverSight/scripts')
from braid_word_solver import *
from verify_wrapping import f_k, is_sidon
from iteration_dag import IterationDAG, AdaptiveRule

passed = 0
failed = 0

def check(name, condition, detail=""):
    global passed, failed
    if condition:
        passed += 1
        print(f"  ✓ {name}")
    else:
        failed += 1
        print(f"  ✗ {name}: {detail}")

print("=" * 60)
print("BRAID WORD SOLVER TESTS")
print("=" * 60)

# --- Test 1: Sidon example ---
print("\n--- Test 1: Sidon example σ₁⁻ ---")
A0, S = [1, 2, 5, 6], 7
result = solve_braid_word(A0, S)
p = result['paths'][0]
check("braid word is σ₁⁻", p['braid_word'] == "σ₁⁻",
      f"got {p['braid_word']}")
check("1 step", p['steps'] == 1, f"got {p['steps']}")
check("final set is Sidon", is_sidon(p['As'][-1]),
      f"A={p['As'][-1]}")
check("final set matches expected", set(p['As'][-1]) == {2, 5, 9, 10},
      f"got {p['As'][-1]}")
check("moduli are [3,4]", p['Ms'][1] == 12,
      f"M={p['Ms'][1]}")

# --- Test 2: Complex set ---
print("\n--- Test 2: Complex set σ₁⁺ ---")
A0, S = [0, 1, 3, 8, 13], 27
result = solve_braid_word(A0, S)
shortest = min(result['paths'], key=lambda x: x['steps'])
check("shortest braid word is σ₁⁺", "σ₁⁺" in shortest['braid_word'],
      f"got {shortest['braid_word']}")
check("final set is Sidon", is_sidon(shortest['As'][-1]),
      f"A={shortest['As'][-1]}")

# --- Test 3: Non-Sidon A that stays non-Sidon ---
print("\n--- Test 3: No-Sidon path ---")
# A set where no modulus in range creates Sidon
A0, S = [0, 1, 2, 4, 8], 12
result = solve_braid_word(A0, S)
check("some paths found", result['summary']['total_paths'] > 0,
      f"no paths")
for p in result['paths']:
    check(f"braid word non-empty", len(p['braid_word']) > 0,
          p['braid_word'])

# --- Test 4: Multi-step path ---
print("\n--- Test 4: Multi-step check ---")
A0, S = [1, 3, 5, 7], 8  # symmetric set, may need multi-step
rule = AdaptiveRule(max_val=20)
dag = IterationDAG(A0, S, rule, max_steps=4, max_branch=50)
dag.build()
if dag.sidon_paths:
    p = min(dag.sidon_paths, key=lambda x: len(x))
    bw = dag_path_to_braid(A0, S, p)
    check(f"multi-step ({len(p)-1} steps) has braid word",
          len(bw) > 0, f"word={bw}")
    check("braid word has correct crossing count",
          bw.count("σ") == len(p) - 1,
          f"{p} stops, word='{bw}'")

# --- Test 5: Over vs Under crossing ---
print("\n--- Test 5: L_id > L_ref → σ⁺, L_id < L_ref → σ⁻ ---")
A0, S = [1, 2, 5, 6], 7
# Directly create nodes and test
from verify_wrapping import f_k, is_sidon
for L_id, L_ref, expected in [(7, 3, "σ₁⁺"), (3, 7, "σ₁⁻"), (5, 2, "σ₁⁺"), (2, 5, "σ₁⁻")]:
    n_mods = [L_id, L_ref]
    n_A = [f_k(a, S, n_mods) for a in A0]
    n_sidon = is_sidon(n_A)
    # Check that the modulus ordering predicts crossing type
    actual = "σ₁⁺" if L_id > L_ref else "σ₁⁻"
    check(f"({L_id},{L_ref}) → {expected}",
          actual == expected, f"got {actual}")

# --- Test 6: Modulus ordering rule ---
print("\n--- Test 6: L_id > L_ref required for Sidon (complex set) ---")
A0, S = [0, 1, 3, 8, 13], 27
for (L_id, L_ref) in [(7, 3), (11, 2), (8, 3), (13, 2)]:
    FA = [f_k(a, S, [L_id, L_ref]) for a in A0]
    sidon = is_sidon(FA)
    check(f"[{L_id},{L_ref}] Sidon={sidon} (L_id>L_ref={L_id>L_ref})",
          sidon, f"FA={FA}")
for (L_id, L_ref) in [(3, 7), (2, 11), (3, 8), (2, 13)]:
    FA = [f_k(a, S, [L_id, L_ref]) for a in A0]
    sidon = is_sidon(FA)
    check(f"[{L_id},{L_ref}] Sidon={sidon} (L_id<L_ref={L_id<L_ref})",
          not sidon, f"FA={FA}")

# --- Test 7: L_id > L_2 rule ---
print("\n--- Test 7: Wrapping works at ANY M > max(A) ---")
A0, S = [1, 2, 5, 6], 7
maxA = max(A0)
for (L_id, L_ref) in [(7, 3), (11, 2), (13, 2), (5, 3)]:
    FA = [f_k(a, S, [L_id, L_ref]) for a in A0]
    M = L_id * L_ref
    sidon = is_sidon(FA)
    regime = "M > 2*maxA (no sum alias)" if M > 2 * maxA else "creation regime"
    check(f"[{L_id},{L_ref}] M={M} ({regime}) Sidon={sidon}",
          M > maxA, f"M={M} should be > maxA={maxA}")

# --- Summary ---
print(f"\n{'='*60}")
print(f"RESULTS: {passed} passed, {failed} failed out of {passed+failed}")
if failed == 0:
    print("ALL TESTS PASSED ✓")
else:
    print(f"{failed} TEST(S) FAILED ✗")
