"""Unit and integration tests for HybridSearchService (BM25 + Dense Qdrant + RRF)."""

from __future__ import annotations

from unittest.mock import MagicMock

import pytest

from app.modules.core.application.hybrid_search_service import (
    HybridSearchService,
    bm25_tokenize,
)


def test_strip_accents_and_tokenize():
    text = "Luật Xây Dựng 2025 số 135/2025/QH15 và Cống Bến Kem"
    tokens = bm25_tokenize(text)
    assert "luật" in tokens or "luat" in tokens
    assert "135/2025/qh15" in tokens
    assert "xây" in tokens or "xay" in tokens


@pytest.mark.anyio
async def test_hybrid_search_rrf_scoring():

    mock_qdrant = MagicMock()
    mock_embedding = MagicMock()
    mock_embedding.embed_query.return_value = [0.1] * 768

    # Giả lập 3 kết quả từ Qdrant
    mock_qdrant.search.return_value = [
        {
            "id": "point-1",
            "text": "Nghị định 206/2026/NĐ-CP về quản lý chi phí đầu tư xây dựng công trình.",
            "metadata": {"doc_type": "nghi_dinh", "law_number": "206/2026/ND-CP"},
            "score": 0.88,
        },
        {
            "id": "point-2",
            "text": "Hợp đồng thi công xây dựng hệ thống cống hộp kênh bến Kem xã Kiến Minh.",
            "metadata": {
                "project_code": "DA-KM-BENKEM-2025-2026",
                "document_type": "hop_dong_thi_cong",
            },
            "score": 0.82,
        },
        {
            "id": "point-3",
            "text": "Luật số 135/2025/QH15 Luật Xây dựng 2025 quy định về miễn giấy phép xây dựng.",
            "metadata": {"doc_type": "luat", "law_number": "135/2025/QH15"},
            "score": 0.79,
        },
    ]

    service = HybridSearchService(
        qdrant_store=mock_qdrant, embedding_service=mock_embedding
    )

    # 1. Test hybrid search with exact keyword query matching point-3
    results = await service.search(
        query="135/2025/QH15 miễn giấy phép", top_k=2, mode="hybrid"
    )
    assert len(results) <= 2
    assert results[0]["id"] == "point-3"
    assert "rrf_score" in results[0]
    assert results[0]["bm25_score"] > 0

    # 2. Test dense search mode
    dense_results = await service.search(query="bến Kem", top_k=2, mode="dense")
    assert len(dense_results) == 2
    assert dense_results[0]["id"] == "point-1"

    # 3. Test bm25 search mode
    bm25_results = await service.search(
        query="206/2026/NĐ-CP quản lý chi phí", top_k=1, mode="bm25"
    )
    assert len(bm25_results) == 1
    assert bm25_results[0]["id"] == "point-1"


@pytest.mark.anyio
async def test_hybrid_search_empty_query_and_empty_store():

    mock_qdrant = MagicMock()
    mock_embedding = MagicMock()
    service = HybridSearchService(
        qdrant_store=mock_qdrant, embedding_service=mock_embedding
    )

    empty_res = await service.search(query="", top_k=5)
    assert empty_res == []

    mock_qdrant.search.return_value = []
    no_dense = await service.search(query="tra cuu thong tin", top_k=5)
    assert no_dense == []
