"""Step definitions for the fast sleep patch type-safe implementation tests.

These scenarios verify the observable behaviour of ``_install_fast_sleep_patch()``
after the ``# type: ignore`` suppressions were replaced with type-safe
``setattr()`` calls and local typed variables (issue #9993).
"""

from __future__ import annotations

import asyncio
import time

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

from features.environment import _install_fast_sleep_patch


@when("I call time.sleep with {seconds:f} seconds")
def step_call_time_sleep(context: Context, seconds: float) -> None:
    """Call the (patched) time.sleep and record elapsed wall-clock time."""
    start = time.monotonic()
    time.sleep(seconds)
    context.elapsed_seconds = time.monotonic() - start


@then("the call should complete in under 500ms")
def step_call_completes_quickly(context: Context) -> None:
    """Assert the patched sleep completed well under the requested duration."""
    elapsed: float = context.elapsed_seconds
    assert elapsed < 0.5, (
        f"Expected patched time.sleep to complete in under 500ms, "
        f"but it took {elapsed * 1000:.1f}ms"
    )


@then("time._original_sleep should be a callable")
def step_time_original_sleep_callable(context: Context) -> None:
    """Assert time._original_sleep was stored by the patch and is callable."""
    original = getattr(time, "_original_sleep", None)
    assert callable(original), (
        f"Expected time._original_sleep to be callable after patch installation, "
        f"got {original!r}"
    )


@then("asyncio._original_sleep should be a callable")
def step_asyncio_original_sleep_callable(context: Context) -> None:
    """Assert asyncio._original_sleep was stored by the patch and is callable."""
    original = getattr(asyncio, "_original_sleep", None)
    assert callable(original), (
        f"Expected asyncio._original_sleep to be callable after patch installation, "
        f"got {original!r}"
    )


@when("I call _install_fast_sleep_patch a second time")
def step_call_patch_second_time(context: Context) -> None:
    """Record the current _original_sleep, then call the patch again."""
    context.original_sleep_before_second_call = getattr(time, "_original_sleep", None)
    _install_fast_sleep_patch()


@then("time._original_sleep should remain the same callable after the second call")
def step_original_sleep_unchanged(context: Context) -> None:
    """Assert idempotency: a second patch call must not replace _original_sleep."""
    original_after = getattr(time, "_original_sleep", None)
    assert original_after is context.original_sleep_before_second_call, (
        "Expected time._original_sleep to remain the same callable after a "
        "second call to _install_fast_sleep_patch() (idempotency guard), "
        "but it was replaced"
    )
