"""Step definitions for TDD Bug #10861 - agents actor run returns nothing.

These steps verify that resolve_config_files synthesises a v3 type: llm YAML
when the actor has a built-in config_blob with provider and model but no type
field. This is the regression guard for bug #10861.
"""

from __future__ import annotations

import yaml
from pathlib import Path
from unittest.mock import MagicMock, patch

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

from cleveragents.cli.commands._resolve_actor import resolve_config_files


@given("a built-in actor with provider and model but no type field for tdd-10861")
def step_given_builtin_actor(context: Context) -> None:
    """Set up a mock built-in actor with provider/model but no type field."""
    mock_actor = MagicMock()
    mock_actor.name = "anthropic/claude-sonnet-4-20250514"
    mock_actor.yaml_text = ""
    mock_actor.config_blob = {
        "provider": "anthropic",
        "model": "claude-sonnet-4-20250514",
        "capabilities": {},
        "unsafe": False,
        "source": "provider-registry",
    }
    mock_registry = MagicMock()
    mock_registry.get.return_value = mock_actor
    mock_container = MagicMock()
    mock_container.actor_registry.return_value = mock_registry
    context.mock_actor = mock_actor
    context.mock_container = mock_container


@given("an actor with existing yaml_text for tdd-10861")
def step_given_actor_with_yaml_text(context: Context) -> None:
    """Set up a mock actor that already has yaml_text."""
    mock_actor = MagicMock()
    mock_actor.name = "local/my-custom-actor"
    mock_actor.yaml_text = (
        "name: local/my-custom-actor\ntype: llm\nprovider: openai\nmodel: gpt-4\n"
    )
    mock_actor.config_blob = None
    mock_registry = MagicMock()
    mock_registry.get.return_value = mock_actor
    mock_container = MagicMock()
    mock_container.actor_registry.return_value = mock_registry
    context.mock_actor = mock_actor
    context.mock_container = mock_container


@when("resolve_config_files is called with the built-in actor name for tdd-10861")
def step_when_resolve_builtin(context: Context) -> None:
    """Call resolve_config_files with the built-in actor name."""
    with patch(
        "cleveragents.cli.commands._resolve_actor.get_container",
        return_value=context.mock_container,
    ):
        context.result_paths = resolve_config_files(
            "anthropic/claude-sonnet-4-20250514", []
        )
    context.add_cleanup(
        lambda: [p.unlink(missing_ok=True) for p in context.result_paths]
    )


@when("resolve_config_files is called with the actor name for tdd-10861")
def step_when_resolve_actor(context: Context) -> None:
    """Call resolve_config_files with the actor name."""
    with patch(
        "cleveragents.cli.commands._resolve_actor.get_container",
        return_value=context.mock_container,
    ):
        context.result_paths = resolve_config_files("local/my-custom-actor", [])
    context.add_cleanup(
        lambda: [p.unlink(missing_ok=True) for p in context.result_paths]
    )


@then("the resulting YAML file contains type llm for tdd-10861")
def step_then_yaml_contains_type_llm(context: Context) -> None:
    """Assert the synthesised YAML contains type: llm."""
    assert len(context.result_paths) == 1
    tmp_path: Path = context.result_paths[0]
    assert tmp_path.exists(), f"Temp file does not exist: {tmp_path}"
    content = tmp_path.read_text(encoding="utf-8")
    parsed = yaml.safe_load(content)
    assert isinstance(parsed, dict), f"Expected dict, got {type(parsed)}"
    assert parsed.get("type") == "llm", (
        "Expected type: llm in synthesised YAML, got: "
        + str(parsed.get("type"))
        + "\nFull content:\n"
        + content
    )


@then("the resulting YAML file contains the provider and model for tdd-10861")
def step_then_yaml_contains_provider_model(context: Context) -> None:
    """Assert the synthesised YAML contains the correct provider and model."""
    tmp_path: Path = context.result_paths[0]
    content = tmp_path.read_text(encoding="utf-8")
    parsed = yaml.safe_load(content)
    assert parsed.get("provider") == "anthropic", (
        "Expected provider: anthropic, got: " + str(parsed.get("provider"))
    )
    assert parsed.get("model") == "claude-sonnet-4-20250514", (
        "Expected model: claude-sonnet-4-20250514, got: " + str(parsed.get("model"))
    )


@then("the resulting YAML file is parseable as a v3 llm actor config for tdd-10861")
def step_then_yaml_parseable_as_v3(context: Context) -> None:
    """Assert the synthesised YAML is parseable by ReactiveConfigParser."""
    from cleveragents.reactive.config_parser import ReactiveConfigParser

    tmp_path: Path = context.result_paths[0]
    parser = ReactiveConfigParser()
    rc = parser.parse_files([tmp_path])

    assert rc.agents, (
        "ReactiveConfigParser produced no agents from synthesised YAML. "
        "This means run_single_shot() would return empty string (bug #10861)."
    )
    assert rc.routes, (
        "ReactiveConfigParser produced no routes from synthesised YAML. "
        "This means run_single_shot() would return empty string (bug #10861)."
    )


@then("the original yaml_text is used without modification for tdd-10861")
def step_then_original_yaml_used(context: Context) -> None:
    """Assert that actors with existing yaml_text are not affected by the fix."""
    tmp_path: Path = context.result_paths[0]
    assert tmp_path.exists(), f"Temp file does not exist: {tmp_path}"
    content = tmp_path.read_text(encoding="utf-8")
    assert "local/my-custom-actor" in content, (
        "Expected original yaml_text content, got: " + content
    )
    assert "type: llm" in content, (
        "Expected type: llm from original yaml_text, got: " + content
    )
    assert "provider: openai" in content, (
        "Expected provider: openai from original yaml_text, got: " + content
    )
