"""
Generator Sync Test
-------------------
Verifies that Python SDK generator matrices match the Rust server implementation.

This test prevents the generator mismatch bug that was discovered during production
verification on 2026-02-05, where SHELL generator was out of sync between server
and client, causing all Shell requests to fail with topology violations.
"""

import re
from pathlib import Path
from lockstock_core.types import GENERATOR_MATRICES, Matrix


def parse_rust_generators() -> dict:
    """
    Parse generator matrices from src/generator.rs in the Rust server.

    Returns:
        dict: Mapping of task names to Matrix objects as defined in Rust code
    """
    # Find the generator.rs file
    repo_root = Path(__file__).parent.parent.parent
    generator_rs_path = repo_root / "src" / "generator.rs"

    if not generator_rs_path.exists():
        raise FileNotFoundError(
            f"Cannot find Rust generator file at {generator_rs_path}. "
            "This test must be run from within the lockstock repository."
        )

    # Read the file
    rust_code = generator_rs_path.read_text()

    # Parse generator definitions
    # Format: Task::TaskName => Matrix::new(a11, a12, a21, a22),
    pattern = r'Task::(\w+)\s*=>\s*Matrix::new\((\d+),\s*(\d+),\s*(\d+),\s*(\d+)\)'

    rust_generators = {}
    for match in re.finditer(pattern, rust_code):
        task_name = match.group(1).upper()
        a11 = int(match.group(2))
        a12 = int(match.group(3))
        a21 = int(match.group(4))
        a22 = int(match.group(5))
        rust_generators[task_name] = Matrix(a11, a12, a21, a22)

    return rust_generators


def test_generators_match_server():
    """
    CRITICAL TEST: Verify Python generators match Rust server.

    This test prevents generator mismatch bugs that cause topology violations.
    If this test fails, it means the server was updated but the Python SDK was not.

    Historical context:
    - 2026-02-05: Discovered SHELL generator mismatch during production verification
    - Server had Matrix(1, 4, 0, 1), Python SDK had Matrix(1, 1, 0, 1)
    - All Shell requests failed with "Topology violation"
    - This test was added to prevent recurrence
    """
    # Parse Rust generators
    rust_generators = parse_rust_generators()

    # Get Python generators
    python_generators = GENERATOR_MATRICES

    # Check all Rust generators are present in Python
    missing_in_python = set(rust_generators.keys()) - set(python_generators.keys())
    if missing_in_python:
        raise AssertionError(
            f"Python SDK is missing generators: {missing_in_python}. "
            f"Update lockstock_core/types.py GENERATOR_MATRICES to include these tasks."
        )

    # Check all Python generators are present in Rust
    missing_in_rust = set(python_generators.keys()) - set(rust_generators.keys())
    if missing_in_rust:
        raise AssertionError(
            f"Rust server is missing generators: {missing_in_rust}. "
            f"Update src/generator.rs to include these tasks."
        )

    # Compare each generator
    mismatches = []
    for task_name in rust_generators.keys():
        rust_gen = rust_generators[task_name]
        python_gen = python_generators[task_name]

        if rust_gen.to_dict() != python_gen.to_dict():
            mismatches.append({
                'task': task_name,
                'rust': rust_gen.to_dict(),
                'python': python_gen.to_dict()
            })

    # Report mismatches
    if mismatches:
        error_msg = ["CRITICAL: Generator mismatch detected!", ""]
        error_msg.append("The following generators differ between Rust server and Python SDK:")
        error_msg.append("")

        for mismatch in mismatches:
            error_msg.append(f"Task: {mismatch['task']}")
            error_msg.append(f"  Rust:   {mismatch['rust']}")
            error_msg.append(f"  Python: {mismatch['python']}")
            error_msg.append("")

        error_msg.append("ACTION REQUIRED:")
        error_msg.append("1. Update lockstock_core/types.py GENERATOR_MATRICES to match Rust")
        error_msg.append("2. Rebuild and test before publishing")
        error_msg.append("3. This is a BREAKING CHANGE - bump major version")
        error_msg.append("")
        error_msg.append("Historical reference: SHELL mismatch bug (2026-02-05)")

        raise AssertionError("\n".join(error_msg))

    # Success
    print(f"✓ All {len(rust_generators)} generators match between Rust and Python")
    print(f"  Verified: {', '.join(sorted(rust_generators.keys()))}")


def test_all_generators_invertible():
    """
    Verify that all generator matrices are invertible (det != 0 mod 65537).

    This is a mathematical requirement for the group structure.
    Non-invertible matrices would break the topological authentication.
    """
    from lockstock_core.types import MODULUS

    for task_name, matrix in GENERATOR_MATRICES.items():
        # Calculate determinant mod 65537
        det = (matrix.a11 * matrix.a22 - matrix.a12 * matrix.a21) % MODULUS

        assert det != 0, (
            f"Generator matrix for {task_name} is not invertible! "
            f"Determinant is 0 (mod {MODULUS}). "
            f"Matrix: {matrix.to_dict()}"
        )

    print(f"✓ All {len(GENERATOR_MATRICES)} generators are invertible")


if __name__ == "__main__":
    # Run tests
    print("=" * 70)
    print("Generator Sync Test")
    print("=" * 70)
    print()

    try:
        test_generators_match_server()
        test_all_generators_invertible()
        print()
        print("=" * 70)
        print("✓ ALL TESTS PASSED")
        print("=" * 70)
    except AssertionError as e:
        print()
        print("=" * 70)
        print("✗ TEST FAILED")
        print("=" * 70)
        print()
        print(str(e))
        exit(1)
