"""Tests for KnowledgeBase orchestrator."""
import pytest

from logos_adk.rag import Chunk, Document, DocumentLoadError
from logos_adk.rag.knowledge_base import KnowledgeBase
from logos_adk.rag.vector_store import InMemoryVectorStore


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 TestKnowledgeBaseIngest:
    @pytest.mark.asyncio
    async def test_ingest_document(self, kb, store):
        doc = Document(content="Hello world", metadata={"source": "test"})
        ids = await kb.ingest(doc)
        assert len(ids) == 1
        results = await store.search([11.0, 1.0], limit=10)
        assert len(results) >= 1

    @pytest.mark.asyncio
    async def test_ingest_document_list(self, kb, store):
        docs = [
            Document(content="First", metadata={}),
            Document(content="Second", metadata={}),
        ]
        ids = await kb.ingest(docs)
        assert len(ids) == 2
        results = await store.search([5.0, 1.0], limit=10)
        assert len(results) == 2

    @pytest.mark.asyncio
    async def test_ingest_text(self, kb, store):
        doc_id = await kb.ingest_text("Quick text", metadata={"tag": "demo"})
        assert isinstance(doc_id, str)
        results = await store.search([10.0, 1.0], limit=10)
        assert len(results) >= 1

    @pytest.mark.asyncio
    async def test_ingest_file(self, kb, tmp_path):
        f = tmp_path / "data.txt"
        f.write_text("File content here")
        ids = await kb.ingest(str(f))
        assert len(ids) == 1

    @pytest.mark.asyncio
    async def test_ingest_unsupported_file(self, kb):
        with pytest.raises(DocumentLoadError, match="No loader supports"):
            await kb.ingest("/fake/path/file.xyz")


class TestKnowledgeBaseSearch:
    @pytest.mark.asyncio
    async def test_search(self, kb):
        await kb.ingest_text("Python programming")
        results = await kb.search("Python")
        assert len(results) >= 1
        assert isinstance(results[0], Chunk)

    @pytest.mark.asyncio
    async def test_search_limit(self, kb):
        for i in range(5):
            await kb.ingest_text(f"Document {i}")
        results = await kb.search("doc", limit=2)
        assert len(results) == 2

    @pytest.mark.asyncio
    async def test_search_with_filter(self, kb):
        await kb.ingest_text("Science text", metadata={"topic": "science"})
        await kb.ingest_text("Art text", metadata={"topic": "art"})
        results = await kb.search("text", limit=10, filter={"topic": "science"})
        assert all(r.metadata.get("topic") == "science" for r in results)


class TestKnowledgeBaseManagement:
    @pytest.mark.asyncio
    async def test_delete(self, kb, store):
        doc = Document(content="To delete", metadata={})
        ids = await kb.ingest(doc)
        await kb.delete(ids[0])
        results = await store.search([9.0, 1.0], limit=10)
        assert len(results) == 0

    @pytest.mark.asyncio
    async def test_clear(self, kb, store):
        await kb.ingest_text("Something")
        await kb.clear()
        results = await store.search([9.0, 1.0], limit=10)
        assert len(results) == 0

    @pytest.mark.asyncio
    async def test_embeds_chunks(self, kb, store):
        await kb.ingest_text("Hello")
        results = await store.search([5.0, 1.0], limit=1)
        assert results[0].embedding is not None
