"""Agent 图缓存行为测试。"""

from datetime import datetime
from types import SimpleNamespace
from unittest.mock import AsyncMock, patch

import pytest
from langchain_core.messages import AIMessage, HumanMessage

from app.agent import MoviePilotAgent, ReplyMode, _CompiledAgentBundle


@pytest.fixture
def anyio_backend():
    """使用 asyncio 后端运行 anyio 异步测试。"""
    return "asyncio"


class _FakeGraphState:
    """提供 LangGraph get_state 测试替身。"""

    def __init__(self, messages):
        """保存测试消息状态。"""
        self.values = {"messages": messages}


class _CapturingAgent:
    """捕获传入消息的非流式 Agent 测试替身。"""

    def __init__(self):
        """初始化捕获容器。"""
        self.payload = None

    async def ainvoke(self, payload, config=None):
        """记录 Agent 调用输入。"""
        self.payload = payload

    def get_state(self, _config):
        """返回包含最终 AI 回复的图状态。"""
        return _FakeGraphState([AIMessage(content="ok")])


@pytest.mark.anyio
async def test_create_agent_reuses_cached_graph_when_signature_matches():
    """构造签名一致时应直接复用已编译 Agent 图。"""
    cached_graph = object()
    agent = MoviePilotAgent(session_id="cache-hit", user_id="user-1")
    agent._compiled_agent_bundle = _CompiledAgentBundle(
        signature=("sig",),
        agent=cached_graph,
        streaming=False,
        created_at=datetime.now(),
    )

    with patch.object(
        agent,
        "_agent_bundle_signature",
        new=AsyncMock(return_value=("sig",)),
    ), patch("app.agent.create_agent") as create_agent:
        graph = await agent._create_agent(streaming=False)

    assert graph is cached_graph
    assert agent._last_agent_cache_hit is True
    create_agent.assert_not_called()


@pytest.mark.anyio
async def test_execute_agent_sends_only_latest_message_on_cache_hit():
    """缓存命中时只把本轮新消息交给 LangGraph，避免重复提交历史。"""
    fake_graph = _CapturingAgent()
    agent = MoviePilotAgent(session_id="cache-hit", user_id="user-1")
    agent.reply_mode = ReplyMode.CAPTURE_ONLY
    agent._tool_context = {"user_reply_sent": False}
    agent._streamed_output = ""
    agent._should_stream = lambda: False
    agent.stream_handler = SimpleNamespace(
        stop_streaming=AsyncMock(return_value=(False, ""))
    )

    async def _create_agent(streaming=False):
        """模拟缓存命中后的 Agent 创建结果。"""
        agent._last_agent_cache_hit = True
        return fake_graph

    agent._create_agent = _create_agent
    messages = [HumanMessage(content="上一轮"), HumanMessage(content="本轮")]

    with patch("app.agent.eventmanager.send_event"):
        await agent._execute_agent(messages)

    assert agent._streamed_output == "ok"
    assert fake_graph.payload["messages"] == [messages[-1]]
