#!/usr/bin/env python3
"""Validate that a module contains only contracts (no implementations).

Usage: uv run python tools/validate_contracts_only.py src/lattice/core/search.py

Exits 0 if all function bodies are stubs (...  or raise NotImplementedError).
Exits 1 if any function has a real implementation body.
"""

import ast
import sys


def is_stub_body(body: list[ast.stmt]) -> bool:
    """Check if function body is a stub (docstring + ... or NotImplementedError)."""
    # Filter out docstrings
    stmts = [
        s
        for s in body
        if not (isinstance(s, ast.Expr) and isinstance(s.value, ast.Constant))
    ]
    if not stmts:
        return True  # docstring-only
    if len(stmts) == 1:
        s = stmts[0]
        # Ellipsis: ...
        if (
            isinstance(s, ast.Expr)
            and isinstance(s.value, ast.Constant)
            and s.value.value is ...
        ):
            return True
        # raise NotImplementedError() or raise NotImplementedError
        if isinstance(s, ast.Raise):
            # raise NotImplementedError()
            if isinstance(s.exc, ast.Call):
                if hasattr(s.exc.func, "id") and s.exc.func.id == "NotImplementedError":
                    return True
            # raise NotImplementedError (without parentheses)
            if isinstance(s.exc, ast.Name) and s.exc.id == "NotImplementedError":
                return True
    return False


def main() -> None:
    if len(sys.argv) != 2:
        print(f"Usage: {sys.argv[0]} <file.py>")
        sys.exit(2)

    path = sys.argv[1]
    with open(path) as f:
        tree = ast.parse(f.read())

    violations = []
    for node in ast.walk(tree):
        if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
            if not is_stub_body(node.body):
                violations.append(
                    f"  L{node.lineno}: {node.name}() has implementation body"
                )

    if violations:
        print(f"FAIL: {path}")
        print("\n".join(violations))
        sys.exit(1)
    else:
        print(f"PASS: {path} — all functions are contract stubs")


if __name__ == "__main__":
    main()
