"""rag-ci adapter. Wire the two methods below to your own pipeline."""

from ragci.contract import Chunk, ParamSpec, RetrievalTrace, Step, adapter


@adapter(
    # Changing these forces a reindex; the sweep groups by them to rebuild as rarely as possible.
    index_time_params=[
        ParamSpec(name="chunk_size", values=[256, 512, 1024]),
    ],
    # These are free to vary against an existing index.
    query_time_params=[
        ParamSpec(name="top_k", values=[5, 10, 20]),
    ],
    primary_metric="recall@10",
)
class MyRag:
    # Optional. Implement it if rag-ci can rebuild your index — that is what lets a sweep
    # vary index-time parameters. `run` calls it once before the cases; `sweep` calls it
    # once per distinct index. Omit it entirely to evaluate an index you already have,
    # and `index` below simply arrives as None.
    # def build_index(self, corpus, config: dict):
    #     ...

    def retrieve(self, query: str, index, config: dict) -> RetrievalTrace:
        """Return what your pipeline retrieved for this query.

        `index` is whatever build_index returned, or None if you did not implement it.
        Build nothing here: rag-ci runs cases concurrently, so constructing a client per
        call means constructing several at once, which some vector stores do not survive.

        Report char_start/char_end whenever you can: exact offsets let rag-ci match
        chunks to passages precisely instead of falling back to token overlap.

        May be `async def` — rag-ci awaits it. The same goes for answer() and
        build_index(), so an async pipeline needs no wrapper.
        """
        raise NotImplementedError

    # Optional: implement to unlock tier-2 generation metrics.
    # def answer(self, query: str, trace: RetrievalTrace, config: dict) -> Answer:
    #     ...
