"""Step definitions for TDD Bug #797 — actor list should not cause a database update.

These steps verify that ``agents actor list`` does **not** trigger
``upsert_actor()`` or ``set_default_actor()`` — both are database write
operations.  They are regression guards for bug #797.
"""

from __future__ import annotations

from unittest.mock import patch

from behave import given, then, when  # type: ignore[import-untyped]
from behave.runner import Context  # type: ignore[import-untyped]
from typer.testing import CliRunner

from cleveragents.cli.commands.actor import app as actor_app
from features.mocks.fake_provider import FakeProviderInfo, make_registry

_PATCH_TARGET: str = "cleveragents.cli.commands.actor._get_services"

_DEFAULT_PROVIDERS: list[FakeProviderInfo] = [
    FakeProviderInfo(
        name="FakeProvider",
        default_model="fake-org/fake-model-v1",
    ),
]


# ---------------------------------------------------------------------------
# Given
# ---------------------------------------------------------------------------


@given(
    "a mock actor service with a fake provider registry for tdd-actor-list-no-db-update"
)
def step_given_mock_service(context: Context) -> None:
    """Set up a ``MagicMock`` actor service wired to a fake provider registry."""
    mock_service, registry = make_registry(_DEFAULT_PROVIDERS)
    context.mock_service = mock_service
    context.registry = registry
    context.runner = CliRunner()


# ---------------------------------------------------------------------------
# When
# ---------------------------------------------------------------------------


@when("the actor list command is invoked for tdd-actor-list-no-db-update")
def step_when_invoke_actor_list(context: Context) -> None:
    """Invoke ``actor list`` through the Typer test runner."""
    with patch(
        _PATCH_TARGET,
        return_value=(context.mock_service, context.registry),
    ):
        context.result = context.runner.invoke(actor_app, ["list"])


# ---------------------------------------------------------------------------
# Then
# ---------------------------------------------------------------------------


@then("upsert_actor should not have been called for tdd-actor-list-no-db-update")
def step_then_no_upsert(context: Context) -> None:
    """Assert that ``upsert_actor`` was never called.

    Bug #797: ``ActorRegistry.list_actors()`` calls
    ``ensure_built_in_actors()`` which invokes ``upsert_actor()`` for
    every configured provider — a database write on a read-only command.
    """
    call_count: int = context.mock_service.upsert_actor.call_count
    assert call_count == 0, (
        f"upsert_actor was called {call_count} time(s) during 'actor list'. "
        f"A read-only list command must not trigger database writes "
        f"(bug #797)."
    )


@then("set_default_actor should not have been called for tdd-actor-list-no-db-update")
def step_then_no_set_default(context: Context) -> None:
    """Assert that ``set_default_actor`` was never called.

    Bug #797: ``ActorRegistry.list_actors()`` calls
    ``ensure_built_in_actors()`` which may invoke
    ``set_default_actor()`` — another database write triggered by a
    read-only list command.
    """
    call_count: int = context.mock_service.set_default_actor.call_count
    assert call_count == 0, (
        f"set_default_actor was called {call_count} time(s) during "
        f"'actor list'. A read-only list command must not trigger "
        f"database writes (bug #797)."
    )
