"""
run.py — High-level execution loop for the Modular Reasoning Scaffold (MRS).

This module ties together the core primitives:
- RecursionNode
- StateTracker
- ConstraintMonitor
- TopologyEngine

It provides a clean, minimal API:

    result = run_mrs(model, input, engine, threshold)

This is the entry point most users will call.
"""

from typing import Any, Callable
from .core import RecursionNode, StateTracker, ConstraintMonitor
from .topology import TopologyEngine


def run_mrs(
    model: Callable,
    x0: Any,
    engine: TopologyEngine,
    threshold: float = 1.0,
    max_steps: int = 12,
) -> Any:
    """
    Execute a full MRS reasoning sequence.

    Parameters
    ----------
    model : Callable
        A function or LLM wrapper that accepts (input, instruction)
        and returns (output, drift).
    x0 : Any
        Initial input to the reasoning scaffold.
    engine : TopologyEngine
        Topology transition controller 𝒯.
    threshold : float
        Maximum allowed drift C(S_n) before halting.
    max_steps : int
        Safety bound on recursion depth.

    Returns
    -------
    Any
        Final output produced by the scaffold.

    Notes
    -----
    MRS is designed for inference-time use — no training required.
    The model must return both content and a drift estimate.
    """
    tracker = StateTracker()
    monitor = ConstraintMonitor(threshold=threshold)

    x = x0

    for _ in range(max_steps):
        # Model call must return output + drift
        output, drift = model(x)

        node = RecursionNode(
            x=x,
            phi="step",
            drift=drift,
            output=output
        )

        tracker.add(node.output)
        monitor.update(node.drift)

        if not monitor.is_stable():
            return tracker.aggregate()

        transition = engine.next_step(node, tracker, monitor)

        if transition.get("halt", False):
            return tracker.aggregate()

        x = transition.get("next_input", node.output)

    return tracker.aggregate()
