"""
Practice: hybrid search and reranking, as in Lab 04's 02_advanced_retrieval.py.

Rankings are lists of paragraph ids like "app_0" (article app, paragraph 0), best first.

Fill in the TODOs, then run the tests:
    pytest test_retrieval_practice.py        (locally)
or press "Run tests" on the chapter page.
"""


def rrf(rankings: list[list[str]], k: int = 60, depth: int | None = 20) -> list[str]:
    """Reciprocal rank fusion. For each ranking, every id in its top `depth` (all of it if depth
    is None) gets 1 / (k + rank) points, with rank starting at 1. Add the points up across
    rankings and return the ids sorted by points, highest first (ties: first one seen wins).

    The lab's hybrid_search merges each search's top 20 (depth=20).

    TODO 1
    """
    return rankings[0] if rankings else []


def rank_of(ranking: list[str], right: str, top: int = 10) -> int | None:
    """1-based position of `right` within the first `top` ids, or None if it isn't there.

    TODO 2
    """
    return None


def right_first(rankings: dict[str, list[str]], answers: dict[str, str]) -> int:
    """How many questions have their right id first. An empty ranking never counts."""
    return sum(1 for q, r in rankings.items() if r and r[0] == answers[q])


def rerank(pool: list[str], scores: dict[str, float]) -> list[str]:
    """What a reranker does: reorder the candidate pool by the model's scores, highest first.
    Ties keep the pool's order. A missing score counts as 0. Nothing outside the pool appears.

    TODO 3
    """
    return pool
