"""Behave step definitions for TDD Issue #9994.

Verifies that LangGraph.execute() raises RuntimeError when StateManager is closed,
preventing silent state corruption after StateManager.close() has been called.
"""

from __future__ import annotations

import asyncio
from unittest.mock import MagicMock

from behave import given, then, when
from behave.runner import Context

from cleveragents.langgraph.graph import GraphConfig, LangGraph
from cleveragents.langgraph.state import GraphState


def _make_graph(name: str = "test-graph") -> LangGraph:
    """Create a minimal LangGraph for testing."""
    config = GraphConfig(name=name)
    graph = LangGraph(config=config)
    graph.is_running = True
    graph.stream_router.send_message = MagicMock()
    return graph


@given("a LangGraph instance in running state with a closed StateManager")
def step_graph_running_with_closed_state_manager(context: Context) -> None:
    context.graph = _make_graph("closed-graph")
    context.graph.state_manager.close()


@when("I attempt to execute the graph after close")
def step_execute_after_close(context: Context) -> None:
    context.execute_error = None
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        loop.run_until_complete(context.graph.execute({"messages": []}))
    except RuntimeError as exc:
        context.execute_error = exc
    finally:
        loop.close()
        replacement_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(replacement_loop)


@then('a RuntimeError should be raised with message "StateManager is closed"')
def step_assert_runtime_error(context: Context) -> None:
    assert context.execute_error is not None, (
        "Expected RuntimeError but no error was raised"
    )
    assert isinstance(context.execute_error, RuntimeError), (
        f"Expected RuntimeError, got {type(context.execute_error).__name__}"
    )
    assert "StateManager is closed" in str(context.execute_error), (
        f'Expected "StateManager is closed" in error message, '
        f"got: {context.execute_error}"
    )


@given("a LangGraph instance in running state with an open StateManager")
def step_graph_running_with_open_state_manager(context: Context) -> None:
    context.graph = _make_graph("open-graph")
    assert not context.graph.state_manager.is_closed


@when("I execute the graph with valid input")
def step_execute_with_valid_input(context: Context) -> None:
    context.execute_result = None
    context.execute_error = None
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        context.execute_result = loop.run_until_complete(
            context.graph.execute({"messages": []})
        )
    except Exception as exc:  # pylint: disable=broad-except
        context.execute_error = exc
    finally:
        loop.close()
        replacement_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(replacement_loop)


@then("the execution should succeed and return a GraphState")
def step_assert_execution_success(context: Context) -> None:
    assert context.execute_error is None, (
        f"Expected no error but got: {context.execute_error}"
    )
    assert context.execute_result is not None, "Expected a GraphState result"
    assert isinstance(context.execute_result, GraphState), (
        f"Expected GraphState, got {type(context.execute_result).__name__}"
    )
