"""Main client protocol definitions.

This module defines the top-level client protocols for the Pinecone SDK.
"""

from typing import Protocol, runtime_checkable

from pinecone.__interface__.backups import BackupNamespaceProtocol
from pinecone.__interface__.collections import CollectionNamespaceProtocol
from pinecone.__interface__.index import AsyncIndexProtocol, IndexProtocol
from pinecone.__interface__.indexes import (
    AsyncIndexNamespaceProtocol,
    IndexNamespaceProtocol,
)
from pinecone.__interface__.inference import (
    AsyncInferenceNamespaceProtocol,
    InferenceNamespaceProtocol,
)


@runtime_checkable
class PineconeProtocol(Protocol):
    """Main Pinecone client protocol.

    This protocol defines the top-level interface for interacting with Pinecone.
    It provides access to indexes, collections, backups, and inference operations.

    Example:
        >>> from pinecone import Pinecone
        >>> pc = Pinecone(api_key="your-api-key")
        >>>
        >>> # Access index management
        >>> indexes = pc.indexes.list()
        >>>
        >>> # Get an index client for data operations
        >>> index = pc.index(host="my-index-abc123.svc.pinecone.io")
        >>>
        >>> # Use inference
        >>> embeddings = pc.inference.embed(model="multilingual-e5-large", texts=["Hello world"])
    """

    @property
    def indexes(self) -> IndexNamespaceProtocol:
        """Index management namespace.

        Provides CRUD operations for managing indexes.

        Returns:
            IndexNamespace for index management operations.

        Example:
            >>> pc.indexes.list()
            >>> pc.indexes.create(name="my-index", dimension=128, ...)
            >>> pc.indexes.delete("my-index")
        """
        ...

    @property
    def collections(self) -> CollectionNamespaceProtocol:
        """Collection management namespace.

        Provides operations for managing collections (static copies of indexes).

        Returns:
            CollectionNamespace for collection management operations.

        Example:
            >>> pc.collections.create(name="my-backup", source="my-index")
            >>> pc.collections.list()
            >>> pc.collections.delete("my-backup")
        """
        ...

    @property
    def backups(self) -> BackupNamespaceProtocol:
        """Backup management namespace.

        Provides operations for managing index backups.

        Returns:
            BackupNamespace for backup management operations.

        Example:
            >>> pc.backups.create(name="my-backup", source="my-index")
            >>> pc.backups.list()
            >>> pc.backups.delete("my-backup")
        """
        ...

    @property
    def inference(self) -> InferenceNamespaceProtocol:
        """Inference operations namespace.

        Provides access to embedding generation and reranking operations.

        Returns:
            InferenceNamespace for inference operations.

        Example:
            >>> response = pc.inference.embed(model="multilingual-e5-large", texts=["Hello", "World"])
            >>>
            >>> response = pc.inference.rerank(
            ...     model="bge-reranker-v2-m3", query="What is AI?", documents=["AI is...", "ML is..."]
            ... )
        """
        ...

    def index(self, *, host: str | None = None, name: str | None = None) -> IndexProtocol:
        """Get an index client for data plane operations.

        Creates an Index client connected to a specific index host. Either
        ``host`` or ``name`` must be provided. Using ``host`` is recommended
        because it avoids a control plane call.

        Args:
            host: Index host URL (recommended). Avoids a control plane call.
            name: Index name. If provided without host, the host is resolved
                via a describe call to the control plane.

        Returns:
            Index client for vector CRUD operations.

        Raises:
            ValueError: If neither host nor name is provided.

        Example:
            >>> pc = Pinecone(api_key="...")
            >>> index = pc.index(host="my-index-abc123.svc.pinecone.io")
            >>> index.upsert(vectors=[{"id": "vec1", "values": [0.1, 0.2, 0.3]}])
            >>> results = index.query(vector=[0.1, 0.2, 0.3], top_k=10)
        """
        ...


@runtime_checkable
class AsyncPineconeProtocol(Protocol):
    """Async Pinecone client protocol.

    This protocol mirrors PineconeProtocol but provides async/await support
    for all I/O operations.

    Example:
        >>> from pinecone import AsyncPinecone
        >>> pc = AsyncPinecone(api_key="your-api-key")
        >>>
        >>> # Get an async index client
        >>> index = pc.index(host="my-index-abc123.svc.pinecone.io")
        >>>
        >>> # Use async/await for operations
        >>> await index.upsert(vectors=[{"id": "vec1", "values": [0.1, 0.2, 0.3]}])
        >>>
        >>> results = await index.query(vector=[0.1, 0.2, 0.3], top_k=10)
    """

    @property
    def indexes(self) -> AsyncIndexNamespaceProtocol:
        """Index management namespace (async operations).

        Returns:
            AsyncIndexNamespace for async index management operations.

        Example:
            >>> indexes = await pc.indexes.list()
            >>> async for index in indexes:
            ...     print(index.name)
            >>>
            >>> info = await pc.indexes.create(name="my-index", dimension=128, spec={...})
        """
        ...

    @property
    def collections(self) -> CollectionNamespaceProtocol:
        """Collection management namespace (sync operations).

        Returns:
            CollectionNamespace for collection management operations.

        Example:
            >>> collections = pc.collections.list()
            >>> pc.collections.create(name="my-backup", source="my-index")
        """
        ...

    @property
    def backups(self) -> BackupNamespaceProtocol:
        """Backup management namespace (sync operations).

        Returns:
            BackupNamespace for backup management operations.

        Example:
            >>> backups = pc.backups.list()
            >>> pc.backups.create(name="my-backup", source="my-index")
        """
        ...

    @property
    def inference(self) -> AsyncInferenceNamespaceProtocol:
        """Inference operations namespace (async operations).

        Returns:
            AsyncInferenceNamespace for async inference operations.

        Example:
            >>> response = await pc.inference.embed(
            ...     model="multilingual-e5-large", texts=["Hello world"]
            ... )
        """
        ...

    def index(self, *, host: str | None = None, name: str | None = None) -> AsyncIndexProtocol:
        """Get an async index client for data plane operations.

        Creates an AsyncIndex client connected to a specific index host. Either
        ``host`` or ``name`` must be provided. Using ``host`` is recommended
        because it avoids a control plane call.

        Args:
            host: Index host URL (recommended). Avoids a control plane call.
            name: Index name. If provided without host, the host is resolved
                via a describe call to the control plane.

        Returns:
            Async index client for vector CRUD operations.

        Raises:
            ValueError: If neither host nor name is provided.

        Example:
            >>> pc = AsyncPinecone(api_key="...")
            >>> index = pc.index(host="my-index-abc123.svc.pinecone.io")
            >>> await index.upsert(vectors=[{"id": "vec1", "values": [0.1, 0.2, 0.3]}])
            >>> results = await index.query(vector=[0.1, 0.2, 0.3], top_k=10)
        """
        ...
