#!/usr/bin/env python3
"""
8-Strand Chiral Torus DAG — full search on provider-nixos.

Runs the dual-model DAG with:
  - 8 strands × 2 moduli = 16 coprime moduli (prime-product method)
  - Axis-swap braid generators (YB-verified)
  - Adjustment crossings with capacity tracking
  - Multi-seed Sidon search (4 different A₀ sets)
  - BFS up to max_steps=12, max_branch=100

Output: per-seed JSON + summary JSON to docs/diagrams/
"""
import sys, math, json, time
sys.path.insert(0, '/home/allaun/SilverSight/scripts')
from full_chiral_dag import ChiralDAG, BraidDAGNode, chiral_pairs

SEEDS = [
    {"id": "canonical", "A": [1, 2, 5, 6], "S": 7},
    {"id": "sparse", "A": [0, 1, 3, 8, 13], "S": 27},
    {"id": "five_element", "A": [1, 4, 9, 11, 16], "S": 20},
    {"id": "seven_element", "A": [2, 3, 7, 10, 14, 18, 21], "S": 24},
]

def run_search(seed, n_strands=3, max_steps=8, max_branch=60, spacing=200):
    """Run a single DAG search with given parameters."""
    dag = ChiralDAG(seed["A"], seed["S"], n_strands=n_strands,
                    max_steps=max_steps, max_branch=max_branch,
                    min_spacing=spacing)
    # Use small initial pairs for the wrapping regime
    init_pairs = chiral_pairs(n_strands)
    dag.root = BraidDAGNode(init_pairs, seed["A"], seed["S"])
    dag.all_nodes = {dag.root.key(): dag.root}
    dag.n_strands = n_strands

    start = time.time()
    dag.build(use_axis_swap=True, use_adjustment=True, bypass_preservation=True)
    elapsed = time.time() - start

    result = {
        "seed_id": seed["id"],
        "A0": seed["A"],
        "S": seed["S"],
        "n_strands": n_strands,
        "max_steps": max_steps,
        "max_branch": max_branch,
        "elapsed_s": round(elapsed, 2),
        "stats": dag.stats,
        "nodes_total": len(dag.all_nodes),
        "sidon_paths": [],
        "root_moduli": dag.root.moduli,
        "root_capacity": dag.root.capacity_left,
        "root_spacing": dag.root._spacing if hasattr(dag.root, '_spacing') else None,
    }

    for path in dag.sidon_paths:
        result["sidon_paths"].append({
            "braid_word": path[-1].braid_word,
            "steps": len(path) - 1,
            "final_A": path[-1].A,
            "final_M": path[-1].M,
            "final_capacity": path[-1].capacity_left,
            "node_count": len(path),
        })

    if result["sidon_paths"]:
        shortest = min(result["sidon_paths"], key=lambda p: p["steps"])
        result["shortest_path"] = shortest["braid_word"]
        result["shortest_steps"] = shortest["steps"]
    else:
        result["shortest_path"] = None
        result["shortest_steps"] = None

    return result, dag


def run_8strand_validation():
    """Validate that the 8-strand config is constructible and compute bounds."""
    pairs = chiral_pairs(8)
    mods = []
    for p in pairs:
        mods.extend(p)
    from full_chiral_dag import pairwise_coprime, compute_spacing, remaining_capacity
    return {
        "n_moduli": len(mods),
        "coprime": pairwise_coprime(mods),
        "moduli": mods,
        "pairs": pairs,
        "min_spacing": compute_spacing(pairs)["min_spacing"],
        "capacity": remaining_capacity(pairs),
        "max_modulus": max(mods),
        "max_modulus_ok": max(mods) < 32767,
    }


if __name__ == "__main__":
    print("=" * 60)
    print("8-STRAND CHIRAL TORUS DAG - FULL SEARCH")
    print("=" * 60)
    print()

    # 1. Validate 8-strand construction
    print("--- 8-Strand Configuration Validation ---")
    v8 = run_8strand_validation()
    print(f"  Moduli: {v8['n_moduli']} (8 strands × 2)")
    print(f"  Coprime: {v8['coprime']}")
    print(f"  Min spacing: {v8['min_spacing']}")
    print(f"  Capacity: {v8['capacity']}")
    print(f"  Max modulus: {v8['max_modulus']} < 32767: {v8['max_modulus_ok']}")
    print()

    # 2. Run searches at increasing strand counts
    all_results = {"8strand_config": v8, "seeds": []}
    configs = [
        (3, 8, 80, "3-strand, 8 steps"),
        (4, 8, 60, "4-strand, 8 steps"),
        (6, 6, 40, "6-strand, 6 steps"),
        (8, 5, 30, "8-strand, 5 steps"),
    ]

    for n_strands, max_steps, max_branch, label in configs:
        print(f"--- {label} ---")
        for seed in SEEDS:
            result, dag = run_search(seed, n_strands, max_steps, max_branch)
            print(f"  Seed '{seed['id']}': "
                  f"nodes={result['nodes_total']}, "
                  f"sidon={result['stats']['sidon_found']}, "
                  f"shortest={result['shortest_path'] or 'NONE'}, "
                  f"{result['elapsed_s']}s")
            all_results["seeds"].append(result)

        # Per-strand-count summary
        seed_results = [r for r in all_results["seeds"] if r["n_strands"] == n_strands]
        found = sum(1 for r in seed_results if r["sidon_paths"])
        total_nodes = sum(r["nodes_total"] for r in seed_results)
        total_time = sum(r["elapsed_s"] for r in seed_results)
        print(f"  [{label}] Total: {found}/{len(SEEDS)} seeds found Sidon, "
              f"{total_nodes} nodes, {total_time:.1f}s")
        print()

    # 3. Overall summary
    print("=" * 60)
    print("SUMMARY")
    print("=" * 60)
    total_seeds = sum(1 for r in all_results["seeds"] if r["sidon_paths"])
    total_found = len([r for r in all_results["seeds"] if r["sidon_paths"]])
    print(f"  Total runs: {len(all_results['seeds'])}")
    print(f"  Seeds with Sidon paths: {total_seeds}")
    print(f"  Shortest paths across all: ", end="")
    shortest = min((r for r in all_results["seeds"] if r["sidon_paths"]),
                   key=lambda r: r["shortest_steps"], default=None)
    if shortest:
        print(f"{shortest['shortest_path']} ({shortest['shortest_steps']} steps, "
              f"seed={shortest['seed_id']}, {shortest['n_strands']} strands)")
    else:
        print("NONE")

    # 4. Write results
    path = "/home/allaun/SilverSight/docs/diagrams/8strand_search_results.json"
    with open(path, 'w') as f:
        json.dump(all_results, f, indent=2)
    print(f"\n  Results written to {path}")
