"""Data models for embedding generation API.

API Version: 2025-10
"""

from typing import Any

from pinecone.models._base import BaseModel
from pinecone.models._display import render_table
from pinecone.models.inference._common import Usage


class Embedding(BaseModel, kw_only=True):  # pyright: ignore[reportCallIssue]
    """Single embedding vector with metadata.

    Attributes:
        values: The embedding vector
        index: Index of the input text that generated this embedding
    """

    values: list[float]
    index: int

    def __repr__(self) -> str:
        """Return repr with truncated values array for readability."""
        if len(self.values) <= 3:
            values_repr = repr(self.values)
        else:
            # Show first 2 values + ellipsis to avoid overwhelming output
            values_repr = f"[{self.values[0]}, {self.values[1]}, ...]"

        return f"Embedding(values={values_repr}, index={self.index})"


class EmbedRequest(BaseModel, kw_only=True):  # pyright: ignore[reportCallIssue]
    """Request model for embedding generation.

    Attributes:
        model: Name of the embedding model to use
        inputs: List of input objects with text field
        parameters: Optional model-specific parameters
    """

    model: str
    inputs: list[dict[str, str]]
    parameters: dict[str, Any] | None = None


class EmbedResponse(BaseModel, kw_only=True, frozen=False):  # pyright: ignore[reportCallIssue]
    """Response model for embedding generation.

    Attributes:
        data: List of embedding objects
        model: Name of the model used
        vector_type: Indicates whether embeddings are 'dense' or 'sparse'
        usage: Token usage information
        _cached_embeddings: Internal cache for embeddings list (not serialized)
    """

    data: list[Embedding]
    model: str
    vector_type: str
    usage: Usage
    _cached_embeddings: list[list[float]] | None = None

    @property
    def embeddings(self) -> list[list[float]]:
        """Get embeddings as list of vectors (protocol requirement).

        Caches the result to avoid repeated list allocation on multiple accesses.
        """
        if self._cached_embeddings is None:
            self._cached_embeddings = [emb.values for emb in self.data]
        return self._cached_embeddings

    def __repr__(self) -> str:
        """Return summary representation without overwhelming array data."""
        return (
            f"EmbedResponse("
            f"model={self.model!r}, "
            f"embeddings={len(self.data)}, "
            f"usage={self.usage!r})"
        )

    def __dir__(self) -> list[str]:
        """Return public API, hiding cache attributes."""
        attrs = set(super().__dir__())
        public = {name for name in attrs if not name.startswith("_")}
        return sorted(public)

    def _repr_pretty_(self, p: Any, cycle: bool) -> None:
        """IPython pretty-printer support."""
        if cycle:
            p.text("EmbedResponse(...)")
            return

        p.text("EmbedResponse(")
        with p.group(2, "", ")"):
            p.breakable()
            p.text(f"model={self.model!r},")
            p.breakable()
            p.text(f"embeddings={len(self.data)},")
            p.breakable()
            p.text(f"vector_type={self.vector_type!r},")
            p.breakable()
            p.text(f"usage={self.usage!r}")

    def _repr_html_(self) -> str:
        """Jupyter notebook HTML representation."""
        return render_table(
            "EmbedResponse",
            [
                ("Model:", self.model),
                ("Embeddings:", len(self.data)),
                ("Vector Type:", self.vector_type),
                ("Total Tokens:", self.usage.total_tokens),
            ],
        )
