"""Embed method for async inference namespace."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, cast

from pinecone._internal.logging import get_logger
from pinecone._internal.validation import require_non_empty
from pinecone.models.inference import EmbedRequest, EmbedResponse


if TYPE_CHECKING:
    from pinecone.__interface__ import EmbedParameters
    from pinecone.__interface__.inference import EmbeddingResponseProtocol


logger = get_logger(__name__)


async def embed(
    self: Any,
    model: str,
    *,
    texts: list[str],
    parameters: EmbedParameters | dict[str, Any] | None = None,
    timeout: float | None = None,
) -> EmbeddingResponseProtocol:
    """Generate embeddings for texts using specified model.

    This async method enables concurrent embedding operations, making it ideal
    for processing large document batches in parallel or integrating with async
    web frameworks.

    Args:
        model: Name of the embedding model to use (e.g., "multilingual-e5-large")
        texts: List of text strings to embed (non-empty)
        parameters: Optional model-specific parameters. See EmbedParameters for
            common options. Additional parameters can be passed as a dict.
        timeout: Optional request timeout in seconds

    Returns:
        EmbeddingResponse containing:
            - embeddings: List of embedding vectors
            - model: Name of the model used
            - usage: Token usage information

    Raises:
        ValueError: If inputs are invalid (empty texts, missing model)
        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.embed(
        ...         model="multilingual-e5-large",
        ...         texts=["Hello world", "Goodbye world"],
        ...         parameters={"input_type": "passage", "truncate": "END"},
        ...     )
        ...     print(f"Generated {len(response.embeddings)} embeddings")
        ...     print(f"Dimension: {len(response.embeddings[0])}")
        ...     print(f"Tokens used: {response.usage.total_tokens}")

    Example with concurrent batches:
        >>> async with AsyncPinecone(api_key="...") as pc:
        ...     batches = [texts[i : i + 100] for i in range(0, len(texts), 100)]
        ...     tasks = [
        ...         pc.inference.embed(model="multilingual-e5-large", texts=batch)
        ...         for batch in batches
        ...     ]
        ...     results = await asyncio.gather(*tasks)

    Example with timeout:
        >>> async with AsyncPinecone(api_key="...") as pc:
        ...     try:
        ...         response = await pc.inference.embed(
        ...             model="multilingual-e5-large",
        ...             texts=["Hello world"],
        ...             timeout=5.0,
        ...         )
        ...     except TimeoutError:
        ...         print("Request timed out after 5 seconds")
    """
    # Validation
    require_non_empty("model", model)
    require_non_empty("texts", texts)

    logger.info(
        "Generating embeddings",
        model=model,
        text_count=len(texts),
        has_parameters=parameters is not None,
    )

    # Build request - convert texts to input format expected by API
    request: EmbedRequest = EmbedRequest(
        model=model,
        inputs=[{"text": text} for text in texts],
        parameters=cast("dict[str, Any] | None", parameters),
    )

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

    # Transform response via adapter
    result: EmbedResponse = self._adapter.to_embed_response(data)

    logger.debug(
        "Embeddings generated successfully",
        model=result.model,
        embedding_count=len(result.embeddings),
        total_tokens=result.usage.total_tokens,
    )

    return result
