"""Rerank method for async inference namespace."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from pinecone._internal.logging import get_logger
from pinecone._internal.validation import require_in_range, require_non_empty
from pinecone.models.inference import RerankDocument, RerankRequest, RerankResponse


if TYPE_CHECKING:
    from pinecone.__interface__.inference import RerankResponseProtocol


logger = get_logger(__name__)


async def rerank(
    self: Any,
    model: str,
    *,
    query: str,
    documents: list[str],
    top_n: int | None = None,
    return_documents: bool = False,
    parameters: dict[str, Any] | None = None,
    timeout: float | None = None,
) -> RerankResponseProtocol:
    """Rerank documents by relevance to a query.

    This async method enables non-blocking reranking operations, useful for
    processing multiple queries concurrently or integrating with async frameworks.

    Args:
            model: Name of the reranking model (e.g., "bge-reranker-v2-m3")
            query: Query text to rank documents against
            documents: List of document texts to rerank (non-empty)
            top_n: Optional number of top results to return
            return_documents: Whether to include document text in results
            parameters: Optional model-specific parameters as a dict. Parameters
                are entirely model-specific - consult model documentation.
            timeout: Optional request timeout in seconds

    Returns:
        RerankResponse containing:
            - results: List of RerankResult with index, score, document
            - model: Name of the model used
            - usage: Token usage information

    Raises:
        ValueError: If inputs are invalid
        APIError: If the API returns an error response
        APIConnectionError: If the request fails to connect
        TimeoutError: If the request times out

    Example:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     response = await pc.inference.rerank(
            ...         model="bge-reranker-v2-m3",
            ...         query="What is machine learning?",
            ...         documents=[
            ...             "Machine learning is a subset of artificial intelligence",
            ...             "Python is a programming language",
            ...             "Deep learning uses neural networks",
            ...         ],
            ...         top_n=2,
            ...     )
            ...     for result in response.results:
            ...         print(f"Document {result.index}: score {result.score:.3f}")

        Example with concurrent queries:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     queries = ["query1", "query2", "query3"]
            ...     tasks = [
            ...         pc.inference.rerank(model="bge-reranker-v2-m3", query=q, documents=docs)
            ...         for q in queries
            ...     ]
            ...     results = await asyncio.gather(*tasks)

        Example with timeout:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     try:
            ...         response = await pc.inference.rerank(
            ...             model="bge-reranker-v2-m3",
            ...             query="What is AI?",
            ...             documents=["AI is...", "ML is..."],
            ...             timeout=5.0,
            ...         )
            ...     except TimeoutError:
            ...         print("Request timed out after 5 seconds")

    Discovery:
        In interactive environments (REPL, notebooks), use these commands to explore:

        >>> from pinecone import AsyncPinecone
        >>> import asyncio
        >>> async def explore():
        ...     async with AsyncPinecone(api_key="...") as pc:
        ...         # See available methods
        ...         print(dir(pc.inference))  # ['embed', 'rerank']
        ...         # Get detailed help
        ...         help(pc.inference.embed)
        >>> asyncio.run(explore())
    """
    # Validation
    require_non_empty("model", model)
    require_non_empty("query", query)
    require_non_empty("documents", documents)

    if top_n is not None:
        require_in_range("top_n", top_n, 1, len(documents))

    logger.info(
        "Reranking documents",
        model=model,
        document_count=len(documents),
        top_n=top_n,
        return_documents=return_documents,
        has_parameters=parameters is not None,
    )

    # Transform documents to structured format
    doc_objects: list[RerankDocument] = [RerankDocument(text=doc) for doc in documents]

    # Build request
    request: RerankRequest = RerankRequest(
        model=model,
        query=query,
        documents=doc_objects,
        top_n=top_n,
        return_documents=return_documents,
        parameters=parameters,
    )

    # Make async HTTP request
    data: dict[str, Any] = await self._make_inference_request("rerank", request, timeout)

    # Transform response via adapter
    result: RerankResponse = self._adapter.to_rerank_response(data)

    logger.debug(
        "Documents reranked successfully",
        model=result.model,
        result_count=len(result.results),
        total_tokens=result.usage.total_tokens,
    )

    return result
