"""Schema models for index field definitions (2026-01.alpha API)."""

from __future__ import annotations

from typing import Any

from pinecone.models._base import BaseModel


class DenseVectorField(BaseModel, tag="dense_vector", tag_field="type"):
    """Dense vector field definition.

    Dense vectors are the traditional fixed-length vectors used for
    similarity search. Each dimension has a floating-point value.

    Attributes:
        dimension: Number of dimensions in the vector (1-20000)
        metric: Distance metric ("cosine", "euclidean", or "dotproduct")
        description: Optional human-readable description

    Note:
        The "type" field is automatically set to "dense_vector" by msgspec's
        tagged union system and should not be included in the struct definition.

    Example:
        >>> field = DenseVectorField(
        ...     dimension=1536, metric="cosine", description="OpenAI ada-002 embeddings"
        ... )
    """

    dimension: int
    metric: str  # cosine, euclidean, dotproduct
    description: str | None = None


class SparseVectorField(BaseModel, tag="sparse_vector", tag_field="type"):
    """Sparse vector field definition.

    Sparse vectors have most values as zero and are represented as
    (indices, values) pairs. Useful for keyword-based search (e.g., BM25).

    Attributes:
        metric: Distance metric (typically "dotproduct")
        description: Optional human-readable description

    Note:
        The "type" field is automatically set to "sparse_vector" by msgspec's
        tagged union system and should not be included in the struct definition.

    Example:
        >>> field = SparseVectorField(metric="dotproduct", description="BM25 sparse embeddings")
    """

    metric: str  # typically dotproduct
    description: str | None = None


class SemanticTextField(BaseModel, tag="semantic_text", tag_field="type"):
    """Semantic text field with integrated embedding.

    Semantic text fields automatically embed text using a specified model,
    eliminating the need to generate embeddings separately. Text is stored
    and embedded using Pinecone's integrated inference.

    Attributes:
        model: Embedding model name (e.g., "multilingual-e5-large")
        metric: Distance metric (typically "cosine")
        description: Optional human-readable description
        read_parameters: Parameters for read operations (e.g., {"input_type": "query"})
        write_parameters: Parameters for write operations (e.g., {"input_type": "passage"})

    Note:
        The "type" field is automatically set to "semantic_text" by msgspec's
        tagged union system and should not be included in the struct definition.

    Example:
        >>> field = SemanticTextField(
        ...     model="multilingual-e5-large",
        ...     metric="cosine",
        ...     description="Product descriptions",
        ...     write_parameters={"input_type": "passage"},
        ...     read_parameters={"input_type": "query", "truncate": "NONE"},
        ... )
    """

    model: str  # e.g., "multilingual-e5-large"
    metric: str  # cosine
    description: str | None = None
    read_parameters: dict[str, Any] | None = None
    write_parameters: dict[str, Any] | None = None


class StringField(BaseModel, tag="string", tag_field="type"):
    """String field for metadata or full-text search.

    String fields can be used for filtering (filterable) or full-text
    search (full_text_searchable). They store text data as metadata.

    Attributes:
        description: Optional human-readable description
        filterable: Whether field can be used in metadata filters
        full_text_searchable: Whether field supports full-text search
        language: Language code for full-text search (e.g., "en", "es")
        stemming: Whether to apply stemming for full-text search
        lowercase: Whether to convert text to lowercase for full-text search
        max_term_len: Maximum term length for full-text search indexing

    Note:
        The "type" field is automatically set to "string" by msgspec's
        tagged union system and should not be included in the struct definition.

        Full-text search parameters (language, stemming, lowercase, max_term_len)
        are only applicable when full_text_searchable=True.

    Example:
        >>> # Filterable string
        >>> category = StringField(filterable=True, description="Product category")
        >>>
        >>> # Full-text searchable string with language
        >>> content = StringField(
        ...     full_text_searchable=True, language="en", description="Document content"
        ... )
    """

    description: str | None = None
    filterable: bool = False
    full_text_searchable: bool = False
    language: str | None = None
    stemming: bool | None = None
    lowercase: bool | None = None
    max_term_len: int | None = None


class IntegerField(BaseModel, tag="integer", tag_field="type"):
    """Integer field for numerical metadata filtering.

    Integer fields store whole numbers and can be used for range filtering
    (e.g., year >= 2020, price < 100).

    Attributes:
        description: Optional human-readable description
        filterable: Whether field can be used in metadata filters

    Note:
        The "type" field is automatically set to "integer" by msgspec's
        tagged union system and should not be included in the struct definition.

    Example:
        >>> field = IntegerField(filterable=True, description="Publication year")
    """

    description: str | None = None
    filterable: bool = False


# Union of all field types
SchemaField = DenseVectorField | SparseVectorField | SemanticTextField | StringField | IntegerField


class Schema(BaseModel):
    """Index schema definition.

    The schema defines all fields in the index, including vector fields,
    text fields, and metadata fields. Each field has a specific type and
    properties that determine how it's indexed and queried.

    Attributes:
        fields: Dictionary mapping field names to field definitions

    Example:
        >>> schema = Schema(
        ...     fields={
        ...         "embedding": DenseVectorField(
        ...             type="dense_vector", dimension=1536, metric="cosine"
        ...         ),
        ...         "title": StringField(type="string", full_text_searchable=True),
        ...         "category": StringField(type="string", filterable=True),
        ...         "year": IntegerField(type="integer", filterable=True),
        ...     }
        ... )
    """

    fields: dict[str, SchemaField]


__all__ = [
    "DenseVectorField",
    "IntegerField",
    "Schema",
    "SchemaField",
    "SemanticTextField",
    "SparseVectorField",
    "StringField",
]
