"""Data models for query operations."""

from typing import Any

from pinecone.models._base import BaseModel
from pinecone.models._display import render_table
from pinecone.models.index._common import DataPlaneUsage, ScoredVector


class QueryRequest(BaseModel, kw_only=True):
    """Request model for vector query.

    Attributes:
        top_k: Number of results to return.
        namespace: Target namespace.
        vector: Dense query vector.
        sparse_vector: Sparse query vector.
        id: Query by existing vector ID.
        filter: Metadata filter expression.
        include_values: Whether to include vector values.
        include_metadata: Whether to include metadata.
    """

    top_k: int = 10
    namespace: str = ""
    vector: list[float] | None = None
    sparse_vector: dict[str, Any] | None = None
    id: str | None = None
    filter: dict[str, Any] | None = None
    include_values: bool = False
    include_metadata: bool = True


class QueryResponse(BaseModel, kw_only=True, rename="camel"):
    """Response model for vector query.

    Attributes:
        matches: List of matching vectors with scores.
        namespace: Namespace queried.
        usage: Read unit usage.
    """

    matches: list[ScoredVector]
    namespace: str = ""
    usage: DataPlaneUsage | None = None

    def __repr__(self) -> str:
        return f"QueryResponse(matches={len(self.matches)}, namespace={self.namespace!r})"

    def __dir__(self) -> list[str]:
        """Return public API, hiding internal 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("QueryResponse(...)")
            return

        p.text("QueryResponse(")
        with p.group(2, "", ")"):
            p.breakable()
            p.text(f"matches={len(self.matches)},")
            p.breakable()
            p.text(f"namespace={self.namespace!r}")
            if self.usage is not None:
                p.breakable()
                p.text(f"usage={self.usage!r}")

    def _repr_html_(self) -> str:
        """Jupyter notebook HTML representation."""
        rows: list[tuple[str, str | int]] = [
            ("Matches:", len(self.matches)),
            ("Namespace:", self.namespace),
        ]

        if self.usage is not None:
            rows.append(("Read Units:", self.usage.read_units))

        return render_table("QueryResponse", rows)
