import json
import pytest
from unittest.mock import AsyncMock, MagicMock

from app.services.relevance_filter import RelevanceFilter


def _make_chunks():
    return [
        ("Chunk A text", {"filename": "doc1.pdf", "chunk_index": 0}),
        ("Chunk B text", {"filename": "doc1.pdf", "chunk_index": 1}),
        ("Chunk C text", {"filename": "doc2.pdf", "chunk_index": 2}),
    ]


async def test_filter_basic_returns_only_above_threshold():
    chunks = _make_chunks()
    llm = MagicMock()
    llm.complete = AsyncMock(return_value="[8.5, 3.2, 9.0]")

    rf = RelevanceFilter(llm)
    result = await rf.filter("What is this about?", chunks, threshold=7.0)

    expected = [chunks[0], chunks[2]]
    assert result == expected
    llm.complete.assert_called_once()

    called_prompt = llm.complete.call_args[0][0]
    assert "What is this about?" in called_prompt
    for t in ["Chunk A text", "Chunk B text", "Chunk C text"]:
        assert t in called_prompt


async def test_filter_empty_chunks_returns_empty_and_no_llm_call():
    llm = MagicMock()
    llm.complete = AsyncMock()
    rf = RelevanceFilter(llm)
    result = await rf.filter("Question", [], threshold=7.0)
    assert result == []
    llm.complete.assert_not_called()


async def test_filter_invalid_json_returns_empty():
    chunks = _make_chunks()
    llm = MagicMock()
    llm.complete = AsyncMock(return_value="not json")

    rf = RelevanceFilter(llm)
    result = await rf.filter("Question", chunks, threshold=7.0)
    assert result == []


async def test_filter_length_mismatch_returns_empty():
    chunks = _make_chunks()[:2]
    llm = MagicMock()
    llm.complete = AsyncMock(return_value="[5, 6]")
    rf = RelevanceFilter(llm)
    result = await rf.filter("Question", chunks, threshold=7.0)
    assert result == []


async def test_filter_all_outside_threshold():
    chunks = _make_chunks()
    llm = MagicMock()
    llm.complete = AsyncMock(return_value="[1.0, 2.0, 3.0]")
    rf = RelevanceFilter(llm)
    result = await rf.filter("Question", chunks, threshold=5.0)
    assert result == []


async def test_filter_json_in_markdown_code_block():
    chunks = _make_chunks()
    llm = MagicMock()
    llm.complete = AsyncMock(return_value="```json\n[8.0, 3.0, 9.0]\n```")

    rf = RelevanceFilter(llm)
    result = await rf.filter("Question", chunks, threshold=7.0)

    expected = [chunks[0], chunks[2]]
    assert result == expected
