"""Tests for hybrid search, RRF merging, and filtering."""

import pytest

from kb_search.search import (
    _escape_fts_query,
    _rank_results,
    _rrf_merge,
    _single_source_results,
)


class TestEscapeFtsQuery:
    def test_plain_query(self):
        assert _escape_fts_query("install git") == "install git"

    def test_special_chars(self):
        result = _escape_fts_query('install "git" (latest)')
        assert '"' not in result
        assert "(" not in result
        assert ")" not in result

    def test_collapses_spaces(self):
        assert _escape_fts_query("  too   many   spaces  ") == "too many spaces"

    def test_empty(self):
        assert _escape_fts_query("") == ""


class TestRankResults:
    def test_basic_ranking(self):
        results = {1: 0.9, 2: 0.5, 3: 0.7}
        ranked = _rank_results(results)
        assert ranked[1] == 1  # highest score = rank 1
        assert ranked[3] == 2
        assert ranked[2] == 3

    def test_empty(self):
        assert _rank_results({}) == {}


class TestRRFMerge:
    def test_basic_merge(self):
        fts = {1: 0.9, 2: 0.5}
        vec = {1: 0.8, 3: 0.7}
        merged = _rrf_merge(fts, vec, k=60)

        scores = {r["chunk_id"]: r["score"] for r in merged}
        # Chunk 1 appears in both — should have highest score
        assert scores[1] > scores[2]
        assert scores[1] > scores[3]

    def test_no_overlap(self):
        fts = {1: 0.9}
        vec = {2: 0.8}
        merged = _rrf_merge(fts, vec, k=60)
        assert len(merged) == 2

    def test_score_breakdown(self):
        fts = {1: 0.9}
        vec = {1: 0.8}
        merged = _rrf_merge(fts, vec, k=60)
        assert len(merged) == 1
        assert merged[0]["score_breakdown"]["fts"] is not None
        assert merged[0]["score_breakdown"]["vector"] is not None

    def test_single_source_fts(self):
        fts = {1: 0.9, 2: 0.5}
        merged = _rrf_merge(fts, {}, k=60)
        for r in merged:
            assert r["score_breakdown"]["vector"] is None
            assert r["score_breakdown"]["fts"] is not None

    def test_empty_both(self):
        merged = _rrf_merge({}, {}, k=60)
        assert merged == []


class TestSingleSourceResults:
    def test_fts_only(self):
        results = _single_source_results({1: 0.9, 2: 0.5}, "fts")
        assert len(results) == 2
        for r in results:
            assert r["score_breakdown"]["vector"] is None
            assert r["score_breakdown"]["fts"] is not None

    def test_vec_only(self):
        results = _single_source_results({1: 0.8}, "vector")
        assert len(results) == 1
        assert results[0]["score_breakdown"]["fts"] is None
        assert results[0]["score_breakdown"]["vector"] is not None
