from __future__ import annotations

import asyncio
from types import SimpleNamespace

from beaver.skills.learning.replay import ReplayArmRequest, ReplayRunner


class FakeAgentLoop:
    def boot(self):
        return SimpleNamespace(tool_executor=SimpleNamespace(), tool_registry=SimpleNamespace(get=lambda name: None))

    async def process_direct(self, task: str, **kwargs):
        executor = kwargs["tool_executor_override"]
        await executor.execute("mcp_outlook_send_email", {"to": "ada@example.com"})
        return SimpleNamespace(session_id="session-replay", run_id="run-replay", output_text="done", finish_reason="stop")


class FakeRunningAgentLoop(FakeAgentLoop):
    def __init__(self) -> None:
        self.process_direct_calls = 0
        self.submit_direct_calls: list[tuple[str, dict]] = []

    async def process_direct(self, task: str, **kwargs):
        self.process_direct_calls += 1
        raise RuntimeError(
            "AgentLoop.process_direct() is disabled while run() is active; "
            "submit tasks via submit_direct() instead."
        )

    async def submit_direct(self, task: str, **kwargs):
        self.submit_direct_calls.append((task, kwargs))
        executor = kwargs["tool_executor_override"]
        await executor.execute("mcp_outlook_send_email", {"to": "ada@example.com"})
        return SimpleNamespace(session_id="session-queued", run_id="run-queued", output_text="queued done", finish_reason="stop")


def test_replay_runner_returns_arm_report_with_tool_trace() -> None:
    runner = ReplayRunner(agent_loop=FakeAgentLoop())
    request = ReplayArmRequest(
        case_id="case-1",
        arm="candidate",
        task_text="Send a status email to Ada.",
        pinned_skill_names=[],
        pinned_skill_contexts=[],
        provider_bundle=object(),
        model_settings={"max_tool_iterations": 2},
    )

    report = asyncio.run(runner.run_arm(request))

    assert report["case_id"] == "case-1"
    assert report["arm"] == "candidate"
    assert report["finish_reason"] == "stop"
    assert report["tool_calls"][0]["tool_name"] == "mcp_outlook_send_email"


def test_replay_runner_queues_arm_when_agent_loop_is_running() -> None:
    agent_loop = FakeRunningAgentLoop()
    runner = ReplayRunner(agent_loop=agent_loop)
    request = ReplayArmRequest(
        case_id="case-queued",
        arm="baseline",
        task_text="Send a status email to Ada.",
        pinned_skill_names=["filesystem-operation"],
        pinned_skill_contexts=[{"name": "filesystem-operation"}],
        provider_bundle=object(),
        model_settings={"max_tool_iterations": 3, "temperature": 0.1},
    )

    report = asyncio.run(runner.run_arm(request))

    assert agent_loop.process_direct_calls == 1
    assert len(agent_loop.submit_direct_calls) == 1
    queued_task, queued_kwargs = agent_loop.submit_direct_calls[0]
    assert queued_task == "Send a status email to Ada."
    assert queued_kwargs["source"] == "skill_replay_eval"
    assert queued_kwargs["include_skill_assembly"] is False
    assert queued_kwargs["include_tools"] is True
    assert queued_kwargs["pinned_skill_names"] == ["filesystem-operation"]
    assert queued_kwargs["max_tool_iterations"] == 3
    assert queued_kwargs["temperature"] == 0.1
    assert report["session_id"] == "session-queued"
    assert report["run_id"] == "run-queued"
    assert report["tool_calls"][0]["tool_name"] == "mcp_outlook_send_email"
