"""Step definitions for LSP StdioTransport post-spawn cleanup tests.

Covers issue #7044: subprocess cleanup when post-Popen initialization fails,
plus explicit is_alive() test coverage. Uses the ``ltcov`` prefix on all steps.
Shared helper utilities are imported from :mod:`_ltcov_helpers`.
"""

from __future__ import annotations

from unittest.mock import patch

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

from _ltcov_helpers import make_mock_process as _make_mock_process

# ---------------------------------------------------------------------------
# Given steps
# ---------------------------------------------------------------------------


@given("ltcov Popen is mocked to succeed with a running process")
def step_ltcov_popen_succeed(context: Context) -> None:
    """Mock subprocess.Popen to return a MagicMock (no exception), simulating
    a successful spawn.  The mock is stored on context for assertion.
    """
    proc = _make_mock_process(poll_return=None, returncode=None)

    patcher = patch(
        "cleveragents.lsp.transport.subprocess.Popen",
        return_value=proc,
    )
    patcher.start()
    context.add_cleanup(patcher.stop)
    context._ltcov_mock_popen_return_value = proc


@given("ltcov logger.info after spawn raises RuntimeError")
def step_ltcov_logger_info_raises(context: Context) -> None:
    """Mock ``logger.info`` to raise a RuntimeError, simulating that post-Popen
    initialization (e.g. logging the started message) fails.
    """

    def _info_raises(*args, **kwargs):
        if args and args[0] == "lsp.transport.started":
            raise RuntimeError("simulated post-Popen initialization failure")

    patcher = patch(
        "cleveragents.lsp.transport.logger.info",
        side_effect=_info_raises,
    )
    patcher.start()
    context.add_cleanup(patcher.stop)


# ---------------------------------------------------------------------------
# When steps
# ---------------------------------------------------------------------------


@when("ltcov I check if the transport is alive")
def step_ltcov_check_alive(context: Context) -> None:
    """Call is_alive() and store the boolean result."""
    context.ltcov_is_alive_result = context.ltcov_transport.is_alive


# ---------------------------------------------------------------------------
# Then steps
# ---------------------------------------------------------------------------


@then("ltcov an error occurred during start()")
def step_ltcov_error_occurred(context: Context) -> None:
    """Assert that start() raised some exception (wrapped or unwrapped)."""
    assert context.ltcov_error is not None, "Expected an error but none was raised"


@then("ltcov the mock process should have been terminated")
def step_ltcov_process_terminated(context: Context) -> None:
    """Assert that terminate() was called on the mock subprocess."""
    proc = context._ltcov_mock_popen_return_value
    proc.terminate.assert_called_once(), "Expected the mock process to be terminated"


@then("ltcov the mock process should have been waited on")
def step_ltcov_process_waited(context: Context) -> None:
    """Assert that wait() was called on the mock subprocess."""
    proc = context._ltcov_mock_popen_return_value
    proc.wait.assert_called_once(), "Expected the mock process to be waited on"


@then("ltcov the transport should be alive")
def step_ltcov_transport_alive(context: Context) -> None:
    """Assert that is_alive() returns True."""
    assert context.ltcov_transport.is_alive, (
        "Expected transport to be alive but it reported not alive"
    )


@then("ltcov the internal process should not be None")
def step_ltcov_process_not_none(context: Context) -> None:
    """Assert that _process is set to a non-None value."""
    assert context.ltcov_transport._process is not None, (
        "Expected _process to be set but it is None"
    )


@then("ltcov the is_alive result should be false")
def step_ltcov_alive_result_false(context: Context) -> None:
    """Assert that is_alive() returns False."""
    assert context.ltcov_is_alive_result is False, (
        f"Expected False, got {context.ltcov_is_alive_result}"
    )
