"""Step definitions for CLI command bus decoupling tests."""

from behave import given, when, then
from cleveragents.cli.command_bus import (
    Command,
    CommandBus,
    get_command_bus,
    set_command_bus,
)


class TestCommand(Command):
    """Test command for BDD tests."""

    def __init__(self, value: str = "test") -> None:
        """Initialize test command."""
        self.value = value


@given("the command bus is initialized")
def step_command_bus_initialized(context):
    """Initialize a fresh command bus."""
    context.bus = CommandBus()


@given("no handlers are registered")
def step_no_handlers_registered(context):
    """Ensure no handlers are registered."""
    if not hasattr(context, "bus"):
        context.bus = CommandBus()


@when("I create a new command bus")
def step_create_command_bus(context):
    """Create a new command bus."""
    context.bus = CommandBus()


@then("the command bus should be empty")
def step_bus_is_empty(context):
    """Verify the command bus is empty."""
    assert isinstance(context.bus, CommandBus)


@then("no handlers should be registered")
def step_no_handlers_registered_check(context):
    """Verify no handlers are registered."""
    assert not context.bus.has_handler(TestCommand)


@given("a command bus")
def step_given_command_bus(context):
    """Given a command bus."""
    context.bus = CommandBus()


@when("I register a handler for a command type")
def step_register_handler(context):
    """Register a handler for a command type."""

    def handler(cmd: TestCommand) -> str:
        return f"Handled: {cmd.value}"

    context.bus.register_handler(TestCommand, handler)
    context.handler = handler


@then("the handler should be registered")
def step_handler_registered(context):
    """Verify the handler is registered."""
    assert context.bus.has_handler(TestCommand)


@then("the command bus should have the handler")
def step_bus_has_handler(context):
    """Verify the bus has the handler."""
    assert context.bus.has_handler(TestCommand)


@given("a command bus with a registered handler")
def step_bus_with_handler(context):
    """Given a command bus with a registered handler."""
    context.bus = CommandBus()

    def handler(cmd: TestCommand) -> str:
        return f"Handled: {cmd.value}"

    context.bus.register_handler(TestCommand, handler)


@when("I dispatch a command")
def step_dispatch_command(context):
    """Dispatch a command."""
    context.command = TestCommand("test_value")
    context.result = context.bus.dispatch(context.command)


@then("the handler should be invoked")
def step_handler_invoked(context):
    """Verify the handler was invoked."""
    assert context.result is not None


@then("the result should be returned")
def step_result_returned(context):
    """Verify the result was returned."""
    assert context.result == "Handled: test_value"


@given("a command bus with no handlers")
def step_bus_no_handlers(context):
    """Given a command bus with no handlers."""
    context.bus = CommandBus()


@when("I dispatch a command without a registered handler")
def step_dispatch_unregistered(context):
    """Dispatch a command without a registered handler."""
    context.command = TestCommand()
    try:
        context.bus.dispatch(context.command)
        context.error_raised = False
    except ValueError as e:
        context.error_raised = True
        context.error = e


@then("a ValueError should be raised for unregistered command dispatch")
def step_value_error_raised(context):
    """Verify a ValueError was raised."""
    assert context.error_raised


@then("the error message should mention the command type")
def step_error_message_check(context):
    """Verify the error message mentions the command type."""
    assert "TestCommand" in str(context.error)


@when("I check if a handler exists for a command type")
def step_check_handler_exists(context):
    """Check if a handler exists."""
    context.bus = CommandBus()

    def handler(cmd: TestCommand) -> str:
        return "handled"

    context.bus.register_handler(TestCommand, handler)
    context.has_handler = context.bus.has_handler(TestCommand)
    context.has_other = context.bus.has_handler(Command)


@then("the result should be accurate")
def step_result_accurate(context):
    """Verify the result is accurate."""
    assert context.has_handler is True


@then("reflect the registration status")
def step_reflect_status(context):
    """Verify it reflects the registration status."""
    assert context.has_other is False


@when("I get the global command bus")
def step_get_global_bus(context):
    """Get the global command bus."""
    context.bus1 = get_command_bus()


@then("I should receive a CommandBus instance")
def step_receive_bus_instance(context):
    """Verify we received a CommandBus instance."""
    assert isinstance(context.bus1, CommandBus)


@then("subsequent calls should return the same instance")
def step_same_instance(context):
    """Verify subsequent calls return the same instance."""
    context.bus2 = get_command_bus()
    assert context.bus1 is context.bus2


@given("a new command bus")
def step_new_command_bus(context):
    """Create a new command bus."""
    context.new_bus = CommandBus()


@when("I set it as the global command bus")
def step_set_global_bus(context):
    """Set it as the global command bus."""
    set_command_bus(context.new_bus)


@then("subsequent calls to get_command_bus should return it")
def step_get_returns_set_bus(context):
    """Verify get_command_bus returns the set bus."""
    retrieved = get_command_bus()
    assert retrieved is context.new_bus


@then("the previous instance should be replaced")
def step_previous_replaced(context):
    """Verify the previous instance was replaced."""
    # This is implicitly verified by the previous step
    pass
