"""Step definitions for tdd_slash_overlay_keyboard_nav.feature.

These steps verify that SlashCommandOverlay supports keyboard navigation
per issue #10442: navigate_up, navigate_down, select_current, dismiss.
"""

from __future__ import annotations

from behave import given, then, when

from cleveragents.tui.slash_catalog import SlashCommandSpec

_TEST_COMMANDS: list[SlashCommandSpec] = [
    SlashCommandSpec(command="help", group="Utility", description="Show help"),
    SlashCommandSpec(command="settings", group="Utility", description="Open settings"),
    SlashCommandSpec(command="clear", group="Utility", description="Clear display"),
]


@given("the overlay has commands loaded")
def step_overlay_has_commands(context: object) -> None:
    """Load test commands into the overlay."""
    context.overlay._commands = _TEST_COMMANDS
    context.overlay._visible = True
    context.overlay.selected_index = 0
    context.test_commands = _TEST_COMMANDS


@given("the overlay selected_index is set to {index:d}")
def step_set_selected_index(context: object, index: int) -> None:
    """Set the overlay selected_index to a specific value."""
    context.overlay.selected_index = index


@when("I call navigate_down on the overlay")
def step_navigate_down(context: object) -> None:
    """Call navigate_down on the overlay."""
    context.overlay.navigate_down()


@when("I call navigate_up on the overlay")
def step_navigate_up(context: object) -> None:
    """Call navigate_up on the overlay."""
    context.overlay.navigate_up()


@when("I call navigate_down on the overlay many times")
def step_navigate_down_many(context: object) -> None:
    """Call navigate_down many times to test boundary."""
    for _ in range(20):
        context.overlay.navigate_down()


@when("I call select_current on the overlay")
def step_select_current(context: object) -> None:
    """Call select_current on the overlay and store result."""
    context.selected_command = context.overlay.select_current()


@then("the overlay should have a navigate_up method")
def step_has_navigate_up(context: object) -> None:
    """Verify navigate_up method exists."""
    assert hasattr(context.overlay, "navigate_up"), "Must have navigate_up"
    assert callable(context.overlay.navigate_up), "navigate_up must be callable"


@then("the overlay should have a navigate_down method")
def step_has_navigate_down(context: object) -> None:
    """Verify navigate_down method exists."""
    assert hasattr(context.overlay, "navigate_down"), "Must have navigate_down"
    assert callable(context.overlay.navigate_down), "navigate_down must be callable"


@then("the overlay should have a select_current method")
def step_has_select_current(context: object) -> None:
    """Verify select_current method exists."""
    assert hasattr(context.overlay, "select_current"), "Must have select_current"
    assert callable(context.overlay.select_current), "select_current must be callable"


@then("the overlay should have a dismiss method")
def step_has_dismiss(context: object) -> None:
    """Verify dismiss method exists."""
    assert hasattr(context.overlay, "dismiss"), "Must have dismiss"
    assert callable(context.overlay.dismiss), "dismiss must be callable"


@then("the overlay should have a selected_index attribute")
def step_has_selected_index(context: object) -> None:
    """Verify selected_index attribute exists."""
    assert hasattr(context.overlay, "selected_index"), "Must have selected_index"


@then("the overlay selected_index should be {expected:d}")
def step_selected_index_equals(context: object, expected: int) -> None:
    """Verify the overlay selected_index equals the expected value."""
    actual = context.overlay.selected_index
    assert actual == expected, f"Expected selected_index={expected}, got {actual}"


@then("the overlay selected_index should not exceed the command count")
def step_selected_index_bounded(context: object) -> None:
    """Verify selected_index does not exceed the number of commands."""
    count = len(context.test_commands)
    actual = context.overlay.selected_index
    assert actual < count, f"selected_index={actual} must be < command count={count}"


@then("the selected command should be the second command in the list")
def step_selected_is_second(context: object) -> None:
    """Verify select_current returned the second command."""
    expected = context.test_commands[1]
    assert context.selected_command == expected, (
        f"Expected {expected!r}, got {context.selected_command!r}"
    )
