"""Tests for RAG agent integration: RAGMemory, rag_tool, Agent.knowledge()."""
import pytest

from logos_adk.memory import MemoryEntry
from logos_adk.rag.knowledge_base import KnowledgeBase
from logos_adk.rag.memory import RAGMemory
from logos_adk.rag.tool import rag_tool
from logos_adk.rag.vector_store import InMemoryVectorStore
from logos_adk.state import AgentState
from logos_adk.types import Message, Response, Usage


async def _fake_embed(text: str) -> list[float]:
    return [float(len(text)), 1.0]


@pytest.fixture
def store():
    return InMemoryVectorStore()


@pytest.fixture
def kb(store):
    return KnowledgeBase(store=store, embed_fn=_fake_embed)


class TestRAGMemory:
    @pytest.mark.asyncio
    async def test_remember_returns_entries(self, kb):
        await kb.ingest_text("Python is a programming language")
        mem = RAGMemory(kb, limit=3)
        messages = [Message(role="user", content="Tell me about Python")]
        entries = await mem.remember(messages, AgentState())
        assert len(entries) >= 1
        assert isinstance(entries[0], MemoryEntry)
        assert "Python" in entries[0].content

    @pytest.mark.asyncio
    async def test_remember_empty_query(self, kb):
        mem = RAGMemory(kb, limit=3)
        messages = [Message(role="system", content="system prompt")]
        entries = await mem.remember(messages, AgentState())
        assert entries == []

    @pytest.mark.asyncio
    async def test_remember_respects_limit(self, kb):
        for i in range(10):
            await kb.ingest_text(f"Document number {i}")
        mem = RAGMemory(kb, limit=3)
        messages = [Message(role="user", content="document")]
        entries = await mem.remember(messages, AgentState())
        assert len(entries) <= 3

    @pytest.mark.asyncio
    async def test_remember_with_filter(self, kb):
        await kb.ingest_text("Science text", metadata={"topic": "science"})
        await kb.ingest_text("Art text", metadata={"topic": "art"})
        mem = RAGMemory(kb, limit=5, filter={"topic": "science"})
        messages = [Message(role="user", content="text")]
        entries = await mem.remember(messages, AgentState())
        assert all(e.metadata.get("topic") == "science" for e in entries)

    @pytest.mark.asyncio
    async def test_commit_is_noop(self, kb):
        mem = RAGMemory(kb)
        await mem.commit(
            messages=[Message(role="user", content="hi")],
            response=Response(content="hello", tool_calls=[], usage=Usage(input_tokens=0, output_tokens=0), raw={}),
            state=AgentState(),
        )


class TestRAGTool:
    @pytest.mark.asyncio
    async def test_retrieve_returns_content(self, kb):
        await kb.ingest_text("The capital of France is Paris")
        t = rag_tool(kb, limit=3)
        result = await t(query="capital of France")
        assert "Paris" in result

    @pytest.mark.asyncio
    async def test_retrieve_no_results(self):
        store = InMemoryVectorStore()
        kb = KnowledgeBase(store=store, embed_fn=_fake_embed)
        t = rag_tool(kb, limit=3)
        result = await t(query="anything")
        assert result == "No relevant information found."

    def test_tool_name_and_description(self, kb):
        t = rag_tool(kb)
        assert t.name == "retrieve"
        assert "knowledge base" in t.description.lower()


class TestAgentKnowledge:
    def test_knowledge_memory_mode(self, kb):
        from logos_adk.agent import Agent
        agent = Agent("test", model="mock")
        agent.knowledge(kb, mode="memory", limit=3)
        assert agent._config.knowledge_base is kb
        assert any(
            isinstance(m, RAGMemory) for m in agent._config.memories
        )

    def test_knowledge_tool_mode(self, kb):
        from logos_adk.agent import Agent
        agent = Agent("test", model="mock")
        agent.knowledge(kb, mode="tool", limit=3)
        assert agent._config.knowledge_base is kb
        assert any(t.name == "retrieve" for t in agent._config.tools)

    def test_knowledge_both_mode(self, kb):
        from logos_adk.agent import Agent
        agent = Agent("test", model="mock")
        agent.knowledge(kb, mode="both", limit=3)
        assert any(isinstance(m, RAGMemory) for m in agent._config.memories)
        assert any(t.name == "retrieve" for t in agent._config.tools)

    def test_knowledge_returns_self(self, kb):
        from logos_adk.agent import Agent
        agent = Agent("test", model="mock")
        result = agent.knowledge(kb)
        assert result is agent
