"""Protocol definitions for document operations."""

from typing import Any, Protocol, runtime_checkable


@runtime_checkable
class DocumentOperationsProtocol(Protocol):
    """Protocol for document operations on a Pinecone index."""

    def upsert(
        self,
        *,
        namespace: str,
        documents: list[dict[str, Any]],
    ) -> "DocumentUpsertResponseProtocol":
        """Upsert flat JSON documents into a namespace.

        Args:
            namespace: Target namespace
            documents: List of flat JSON documents, each with an _id field

        Returns:
            DocumentUpsertResponse with upserted count

        Raises:
            ValueError: If namespace is empty or documents list is empty
            BadRequestError: If documents are invalid
        """
        ...

    def search(
        self,
        *,
        namespace: str,
        top_k: int,
        score_by: list[dict[str, Any]],
        include_fields: list[str] | str | None = None,
        filter: dict[str, Any] | None = None,  # noqa: A002
    ) -> "DocumentSearchResponseProtocol":
        """Search documents in a namespace.

        Args:
            namespace: Target namespace
            top_k: Number of results to return (1-10000)
            score_by: Query objects for ranking (text or vector). Must not be empty.
            include_fields: Fields to return ('*' for all, list of names, or None for IDs only)
            filter: Metadata filter expression

        Returns:
            DocumentSearchResponse with matching documents

        Raises:
            ValueError: If namespace is empty, top_k is out of range, or score_by is empty
        """
        ...


@runtime_checkable
class AsyncDocumentOperationsProtocol(Protocol):
    """Async protocol for document operations."""

    async def upsert(
        self,
        *,
        namespace: str,
        documents: list[dict[str, Any]],
    ) -> "DocumentUpsertResponseProtocol":
        """Async upsert flat JSON documents into a namespace.

        Args:
            namespace: Target namespace
            documents: List of flat JSON documents, each with an _id field

        Returns:
            DocumentUpsertResponse with upserted count

        Raises:
            ValueError: If namespace is empty or documents list is empty
            BadRequestError: If documents are invalid

        Example:
            >>> response = await index.documents.upsert(
            ...     namespace="ns",
            ...     documents=[{"_id": "doc1", "text": "hello"}],
            ... )
        """
        ...

    async def search(
        self,
        *,
        namespace: str,
        top_k: int,
        score_by: list[dict[str, Any]],
        include_fields: list[str] | str | None = None,
        filter: dict[str, Any] | None = None,  # noqa: A002
    ) -> "DocumentSearchResponseProtocol":
        """Async search documents in a namespace.

        Args:
            namespace: Target namespace
            top_k: Number of results to return (1-10000)
            score_by: Query objects for ranking (text or vector). Must not be empty.
            include_fields: Fields to return ('*' for all, list of names, or None for IDs only)
            filter: Metadata filter expression

        Returns:
            DocumentSearchResponse with matching documents

        Raises:
            ValueError: If namespace is empty, top_k is out of range, or score_by is empty

        Example:
            >>> response = await index.documents.search(
            ...     namespace="ns",
            ...     top_k=10,
            ...     score_by=[{"type": "text", "field": "title", "text_query": "hello"}],
            ... )
        """
        ...


# Response protocols
@runtime_checkable
class DocumentUpsertResponseProtocol(Protocol):
    """Protocol for document upsert response."""

    @property
    def upserted_count(self) -> int:
        """Number of documents upserted."""
        ...


@runtime_checkable
class DocumentSearchResponseProtocol(Protocol):
    """Protocol for document search response."""

    @property
    def documents(self) -> list["DocumentProtocol"]:
        """List of matching documents."""
        ...

    @property
    def usage(self) -> "UsageProtocol | None":
        """Usage information."""
        ...


@runtime_checkable
class DocumentProtocol(Protocol):
    """Protocol for a document in search results."""

    @property
    def id(self) -> str:
        """Document ID (_id field)."""
        ...

    @property
    def score(self) -> float | None:
        """Relevance score for this document (if applicable)."""
        ...

    # Additional fields accessed via dict-like interface
    def get(self, key: str, default: Any = None) -> Any:
        """Get field value."""
        ...


@runtime_checkable
class UsageProtocol(Protocol):
    """Protocol for usage information."""

    @property
    def read_units(self) -> int | None:
        """Read units consumed."""
        ...
