"""Tests for MemoryCache - in-memory memory query for MCP tools."""

from app.agent.memory_cache import MemoryCache


def test_format_memory_result_handles_empty_and_populated_records():
    cache = MemoryCache()
    assert cache.format_for_display([]) == "没有找到相关记忆。"

    formatted = cache.format_for_display(
        [
            {
                "tick_no": 5,
                "memory_category": "long_term",
                "summary": "Talked with Bob",
                "related_agent_name": "Bob",
            }
        ]
    )

    assert "找到以下记忆：" in formatted
    assert "[Tick 5] [long_term] Talked with Bob" in formatted
    assert "相关人物: Bob" in formatted


def test_search_memories_filters_by_query_and_category():
    """Test searching memories by query string and category."""
    cache_data = {
        "short_term": [
            {
                "id": "mem-short-cafe",
                "content": "Served coffee at the cafe.",
                "summary": "Served coffee",
                "tick_no": 6,
                "memory_category": "short_term",
                "self_relevance": 0.2,
            }
        ],
        "medium_term": [
            {
                "id": "mem-medium-cafe",
                "content": "Bob mentioned the cafe may close soon.",
                "summary": "Cafe may close",
                "tick_no": 7,
                "memory_category": "medium_term",
                "self_relevance": 0.5,
            }
        ],
        "long_term": [
            {
                "id": "mem-long-bob",
                "content": "Talked with Bob about the cafe renovation.",
                "summary": "Talked with Bob",
                "tick_no": 5,
                "memory_category": "long_term",
                "self_relevance": 0.9,
                "related_agent_id": "agent-bob",
                "related_agent_name": "Bob",
            },
            {
                "id": "mem-long-park",
                "content": "Walked alone in the park.",
                "summary": "Park walk",
                "tick_no": 3,
                "memory_category": "long_term",
                "self_relevance": 0.1,
            },
        ],
        "all": [
            {
                "id": "mem-short-cafe",
                "content": "Served coffee at the cafe.",
                "summary": "Served coffee",
                "tick_no": 6,
                "memory_category": "short_term",
                "self_relevance": 0.2,
            },
            {
                "id": "mem-medium-cafe",
                "content": "Bob mentioned the cafe may close soon.",
                "summary": "Cafe may close",
                "tick_no": 7,
                "memory_category": "medium_term",
                "self_relevance": 0.5,
            },
            {
                "id": "mem-long-bob",
                "content": "Talked with Bob about the cafe renovation.",
                "summary": "Talked with Bob",
                "tick_no": 5,
                "memory_category": "long_term",
                "self_relevance": 0.9,
                "related_agent_id": "agent-bob",
                "related_agent_name": "Bob",
            },
            {
                "id": "mem-long-park",
                "content": "Walked alone in the park.",
                "summary": "Park walk",
                "tick_no": 3,
                "memory_category": "long_term",
                "self_relevance": 0.1,
            },
        ],
    }

    cache = MemoryCache(cache_data)

    # Search in long_term only
    results = cache.search_memories(query="Bob", category="long_term", limit=5)
    assert [memory["id"] for memory in results] == ["mem-long-bob"]
    assert results[0]["related_agent_name"] == "Bob"

    # Search in all categories
    results = cache.search_memories(query="cafe", category="all", limit=5)
    assert [memory["id"] for memory in results] == [
        "mem-long-bob",
        "mem-medium-cafe",
        "mem-short-cafe",
    ]

    # Search with no matches
    results = cache.search_memories(query="nonexistent", category="all", limit=5)
    assert results == []


def test_get_recent_memories_respects_category_and_limit():
    """Test getting recent memories with category filter."""
    cache_data = {
        "short_term": [
            {"id": "st1", "tick_no": 10, "memory_category": "short_term"},
            {"id": "st2", "tick_no": 9, "memory_category": "short_term"},
        ],
        "medium_term": [
            {"id": "mt1", "tick_no": 8, "memory_category": "medium_term"},
            {"id": "mt2", "tick_no": 7, "memory_category": "medium_term"},
        ],
        "long_term": [
            {"id": "lt1", "tick_no": 6, "memory_category": "long_term"},
            {"id": "lt2", "tick_no": 5, "memory_category": "long_term"},
            {"id": "lt3", "tick_no": 4, "memory_category": "long_term"},
        ],
        "all": [
            {"id": "st1", "tick_no": 10, "memory_category": "short_term"},
            {"id": "st2", "tick_no": 9, "memory_category": "short_term"},
            {"id": "mt1", "tick_no": 8, "memory_category": "medium_term"},
            {"id": "mt2", "tick_no": 7, "memory_category": "medium_term"},
            {"id": "lt1", "tick_no": 6, "memory_category": "long_term"},
            {"id": "lt2", "tick_no": 5, "memory_category": "long_term"},
            {"id": "lt3", "tick_no": 4, "memory_category": "long_term"},
        ],
    }

    cache = MemoryCache(cache_data)

    # Get all recent
    results = cache.get_recent_memories(category="all", limit=3)
    assert [m["id"] for m in results] == ["st1", "st2", "mt1"]

    # Get medium_term only
    results = cache.get_recent_memories(category="medium_term", limit=2)
    assert [m["id"] for m in results] == ["mt1", "mt2"]

    # Get long_term only
    results = cache.get_recent_memories(category="long_term", limit=2)
    assert [m["id"] for m in results] == ["lt1", "lt2"]

    # Get short_term only
    results = cache.get_recent_memories(category="short_term", limit=5)
    assert [m["id"] for m in results] == ["st1", "st2"]


def test_get_memories_about_agent():
    """Test getting memories about a specific agent."""
    cache_data = {
        "about_others": {
            "agent-bob": [
                {"id": "mem-bob-1", "tick_no": 5, "related_agent_id": "agent-bob"},
                {"id": "mem-bob-2", "tick_no": 3, "related_agent_id": "agent-bob"},
            ],
            "agent-charlie": [
                {"id": "mem-charlie-1", "tick_no": 4, "related_agent_id": "agent-charlie"},
            ],
        },
    }

    cache = MemoryCache(cache_data)

    # Get memories about Bob
    results = cache.get_memories_about_agent(other_agent_id="agent-bob", limit=5)
    assert [m["id"] for m in results] == ["mem-bob-1", "mem-bob-2"]

    # Get memories about Charlie with limit
    results = cache.get_memories_about_agent(other_agent_id="agent-charlie", limit=1)
    assert [m["id"] for m in results] == ["mem-charlie-1"]

    # Get memories about non-existent agent
    results = cache.get_memories_about_agent(other_agent_id="agent-none", limit=5)
    assert results == []


def test_get_memories_by_location():
    """Test getting memories by location."""
    cache_data = {
        "all": [
            {"id": "mem-cafe-1", "tick_no": 5, "location_id": "loc-cafe"},
            {"id": "mem-park-1", "tick_no": 4, "location_id": "loc-park"},
            {"id": "mem-cafe-2", "tick_no": 3, "location_id": "loc-cafe"},
            {"id": "mem-home-1", "tick_no": 2, "location_id": "loc-home"},
        ],
    }

    cache = MemoryCache(cache_data)

    # Get memories at cafe
    results = cache.get_memories_by_location(location_id="loc-cafe", limit=5)
    assert [m["id"] for m in results] == ["mem-cafe-1", "mem-cafe-2"]

    # Get memories at park with limit
    results = cache.get_memories_by_location(location_id="loc-park", limit=1)
    assert [m["id"] for m in results] == ["mem-park-1"]

    # Get memories at non-existent location
    results = cache.get_memories_by_location(location_id="loc-none", limit=5)
    assert results == []


def test_memory_cache_with_empty_data():
    """Test MemoryCache handles empty or None data gracefully."""
    # None data
    cache = MemoryCache(None)
    assert cache.search_memories("query") == []
    assert cache.get_recent_memories() == []
    assert cache.get_memories_about_agent("agent") == []
    assert cache.get_memories_by_location("loc") == []

    # Empty dict
    cache = MemoryCache({})
    assert cache.search_memories("query") == []
    assert cache.get_recent_memories() == []


def test_working_memory_can_be_merged_and_retrieved():
    cache = MemoryCache(
        {
            "short_term": [{"id": "st1", "tick_no": 2}],
            "all": [{"id": "st1", "tick_no": 2}],
        }
    )

    merged = cache.with_working_memory(
        {
            "current_focus": "中午一起喝咖啡",
            "latest_other_party_update": "Bob 刚确认了咖啡馆碰头。",
            "repetition_risk": "proposal x2",
        }
    )

    assert merged.get_recent_memories(category="all", limit=1) == [{"id": "st1", "tick_no": 2}]
    assert merged.get_working_memory() == {
        "current_focus": "中午一起喝咖啡",
        "latest_other_party_update": "Bob 刚确认了咖啡馆碰头。",
        "repetition_risk": "proposal x2",
    }


def test_format_working_memory_for_display_handles_empty_and_populated_state():
    cache = MemoryCache()

    assert cache.format_working_memory_for_display({}) == "当前没有可用的短时工作记忆。"

    formatted = cache.format_working_memory_for_display(
        {
            "current_focus": "中午一起喝咖啡",
            "latest_other_party_update": "Bob 刚确认了咖啡馆碰头。",
            "conversation_phase": "closing",
            "repetition_risk": "proposal x2",
        }
    )

    assert "当前短时工作记忆：" in formatted
    assert "- 当前话题: 中午一起喝咖啡" in formatted
    assert "- 对方最新进展: Bob 刚确认了咖啡馆碰头。" in formatted
    assert "- 对话阶段: closing" in formatted
    assert "- 重复风险: proposal x2" in formatted
