"""Step definitions for exec_env_project_override.feature.

Verifies that plan_env and project_env are threaded from
ToolCallRouter through to the ExecutionEnvironmentResolver
inside ToolRunner.execute().

Issue #1080.
"""

from __future__ import annotations

from typing import Any

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

from cleveragents.tool.registry import ToolRegistry
from cleveragents.tool.router import ToolCallRouter
from cleveragents.tool.runner import ToolRunner
from cleveragents.tool.runtime import ToolSpec

__all__: list[str] = []


def _echo_tool(arguments: dict[str, Any]) -> dict[str, Any]:
    """Simple echo tool for testing."""
    return {"echoed": arguments}


@given("ee1080- a tool registry with a registered echo tool")
def step_ee1080_registry(context: Context) -> None:
    context.ee1080_registry = ToolRegistry()
    spec = ToolSpec(
        name="test/echo",
        description="Echo tool for testing",
        input_schema={"type": "object", "properties": {}},
        handler=_echo_tool,
    )
    context.ee1080_registry.register(spec)


@given("ee1080- a tool runner and resolver spy")
def step_ee1080_runner(context: Context) -> None:
    context.ee1080_runner = ToolRunner(context.ee1080_registry)
    # Spy on _env_resolver.resolve to capture what it receives
    context.ee1080_resolve_calls: list[dict[str, Any]] = []  # type: ignore[annotation-unchecked]
    original_rv = context.ee1080_runner._env_resolver.resolve_and_validate

    def spy_resolve_and_validate(**kwargs: Any) -> tuple[str, str | None]:
        context.ee1080_resolve_calls.append(
            {
                "plan_env": kwargs.get("plan_env"),
                "project_env": kwargs.get("project_env"),
            }
        )
        return original_rv(**kwargs)

    context.ee1080_runner._env_resolver.resolve_and_validate = spy_resolve_and_validate  # type: ignore[method-assign]


@given('ee1080- a ToolCallRouter with project_env "{env}"')
def step_ee1080_router_project(context: Context, env: str) -> None:
    context.ee1080_router = ToolCallRouter(
        registry=context.ee1080_registry,
        runner=context.ee1080_runner,
        plan_id="ee1080-plan",
        project_env=env,
    )


@given('ee1080- a ToolCallRouter with plan_env "{env}"')
def step_ee1080_router_plan(context: Context, env: str) -> None:
    context.ee1080_router = ToolCallRouter(
        registry=context.ee1080_registry,
        runner=context.ee1080_runner,
        plan_id="ee1080-plan",
        plan_env=env,
    )


@given(
    'ee1080- a ToolCallRouter with both plan_env "{plan}" and project_env "{project}"'
)
def step_ee1080_router_both(context: Context, plan: str, project: str) -> None:
    context.ee1080_router = ToolCallRouter(
        registry=context.ee1080_registry,
        runner=context.ee1080_runner,
        plan_id="ee1080-plan",
        plan_env=plan,
        project_env=project,
    )


@given("ee1080- a ToolCallRouter without env params")
def step_ee1080_router_none(context: Context) -> None:
    context.ee1080_router = ToolCallRouter(
        registry=context.ee1080_registry,
        runner=context.ee1080_runner,
        plan_id="ee1080-plan",
    )


@when("ee1080- I route a tool call through the router")
def step_ee1080_route(context: Context) -> None:
    payload = {
        "name": "test/echo",
        "arguments": {"msg": "hello"},
    }
    context.ee1080_result = context.ee1080_router.route(payload)


@then('ee1080- the resolver should have received project_env "{expected}"')
def step_ee1080_check_project_env(context: Context, expected: str) -> None:
    expected_val = None if expected == "None" else expected
    calls = context.ee1080_resolve_calls
    assert len(calls) > 0, "Resolver was never called"
    actual = calls[-1]["project_env"]
    assert actual == expected_val, (
        f"Expected project_env={expected_val!r}, got {actual!r}"
    )


@then('ee1080- the resolver should have received plan_env "{expected}"')
def step_ee1080_check_plan_env(context: Context, expected: str) -> None:
    expected_val = None if expected == "None" else expected
    calls = context.ee1080_resolve_calls
    assert len(calls) > 0, "Resolver was never called"
    actual = calls[-1]["plan_env"]
    assert actual == expected_val, f"Expected plan_env={expected_val!r}, got {actual!r}"
