"""Sync namespace management operations for a Pinecone index."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

import msgspec
import orjson

from pinecone._internal.constants import DATA_PLANE_HEADERS
from pinecone._internal.validation import require_non_empty
from pinecone.models.namespaces.delete import DeleteNamespaceResponse
from pinecone.models.namespaces.list import ListNamespacesResponse
from pinecone.models.namespaces.namespace import FieldConfig, NamespaceDescription


if TYPE_CHECKING:
    from httpx import Response


__all__ = ["Namespaces"]


# Module-level decoders for hot-path operations
_CREATE_DECODER = msgspec.json.Decoder(NamespaceDescription)
_LIST_DECODER = msgspec.json.Decoder(ListNamespacesResponse)
_DESCRIBE_DECODER = msgspec.json.Decoder(NamespaceDescription)
_DELETE_DECODER = msgspec.json.Decoder(DeleteNamespaceResponse)


class Namespaces:
    """Sub-namespace for namespace management operations on a Pinecone index.

    Access via the ``namespaces`` property on an Index instance::

        index = Index(host="...", api_key="...")
        ns_list = index.namespaces.list()

    Args:
        http: HTTP client for making requests.
        base_url: Base URL for the index data plane API.
    """

    def __init__(self, *, http: Any, base_url: str) -> None:
        self._http = http
        self._base_url = base_url

    def _make_data_plane_request(
        self,
        method: str,
        path: str,
        *,
        body: dict[str, Any] | None = None,
        params: dict[str, Any] | None = None,
    ) -> bytes:
        """Make an HTTP request to the data plane API."""
        url = f"{self._base_url}{path}"
        content = orjson.dumps(body) if body is not None else None

        response: Response
        if method == "GET":
            response = self._http.get(url, headers=DATA_PLANE_HEADERS, params=params)
        elif method == "DELETE":
            response = self._http.request("DELETE", url, headers=DATA_PLANE_HEADERS, params=params)
        else:
            response = self._http.post(
                url, headers=DATA_PLANE_HEADERS, content=content, params=params
            )

        return response.content

    def create(
        self,
        *,
        name: str,
        schema: dict[str, dict[str, bool]] | dict[str, FieldConfig] | None = None,
    ) -> NamespaceDescription:
        """Create a new namespace in the index.

        Args:
            name (str): The name of the namespace to create.
            schema (dict[str, dict[str, bool]] | dict[str, FieldConfig] | None): Optional
                schema definition mapping field names to their configuration.
                Each field maps to a dict with configuration options such as
                ``{"filterable": True}`` or a ``FieldConfig`` object.

        Returns:
            NamespaceDescription for the newly created namespace.

        Raises:
            ValueError: If required parameters are empty.
            PineconeApiException: If the API request fails.

        Examples:
            >>> ns = index.namespaces.create(name="my-namespace")
            >>> ns = index.namespaces.create(
            ...     name="my-namespace",
            ...     schema={"category": {"filterable": True}},
            ... )
        """
        require_non_empty("name", name)
        body: dict[str, Any] = {"name": name}
        if schema is not None:
            fields: dict[str, Any] = {}
            for field_name, config in schema.items():
                if isinstance(config, FieldConfig):
                    fields[field_name] = {"filterable": config.filterable}
                else:
                    fields[field_name] = config
            body["schema"] = {"fields": fields}

        data = self._make_data_plane_request("POST", "/namespaces", body=body)
        return _CREATE_DECODER.decode(data)

    def list(
        self,
        *,
        limit: int | None = None,
        pagination_token: str | None = None,
        prefix: str | None = None,
    ) -> ListNamespacesResponse:
        """List namespaces in the index.

        Args:
            limit (int | None): Maximum number of namespaces to return.
            pagination_token (str | None): Token to resume from a previous call.
            prefix (str | None): Filter namespaces by name prefix.

        Returns:
            ListNamespacesResponse with namespace descriptions and pagination info.

        Raises:
            PineconeApiException: If the API request fails.

        Examples:
            >>> response = index.namespaces.list()
            >>> for ns in response.namespaces:
            ...     print(f"{ns.name}: {ns.record_count} records")
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if pagination_token is not None:
            params["paginationToken"] = pagination_token
        if prefix is not None:
            params["prefix"] = prefix

        data = self._make_data_plane_request("GET", "/namespaces", params=params)
        return _LIST_DECODER.decode(data)

    def describe(self, *, name: str) -> NamespaceDescription:
        """Describe a specific namespace in the index.

        Args:
            name (str): The name of the namespace to describe.

        Returns:
            NamespaceDescription with the namespace details.

        Raises:
            ValueError: If required parameters are empty.
            PineconeApiException: If the API request fails.

        Examples:
            >>> ns = index.namespaces.describe(name="my-namespace")
            >>> print(f"{ns.name}: {ns.record_count} records")
        """
        require_non_empty("name", name)
        data = self._make_data_plane_request("GET", f"/namespaces/{name}")
        return _CREATE_DECODER.decode(data)

    def delete(self, *, name: str) -> DeleteNamespaceResponse:
        """Delete a namespace from the index.

        Args:
            name (str): The name of the namespace to delete.

        Returns:
            DeleteNamespaceResponse (empty on success).

        Raises:
            ValueError: If required parameters are empty.
            PineconeApiException: If the API request fails.

        Examples:
            >>> index.namespaces.delete(name="my-namespace")
        """
        require_non_empty("name", name)
        data = self._make_data_plane_request("DELETE", f"/namespaces/{name}")
        return _DELETE_DECODER.decode(data)

    def __repr__(self) -> str:
        """Return string representation."""
        return f"Namespaces(base_url={self._base_url!r})"
