"""Sync sub-namespace for bulk import operations on a Pinecone index."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Literal

import msgspec
import orjson

from pinecone._internal.constants import DATA_PLANE_HEADERS
from pinecone._internal.validation import require_non_empty
from pinecone.models.bulk_imports.cancel import CancelImportResponse
from pinecone.models.bulk_imports.import_model import ImportModel
from pinecone.models.bulk_imports.list import ListImportsResponse
from pinecone.models.bulk_imports.start import StartImportResponse


if TYPE_CHECKING:
    from pinecone._internal.http import HTTPClient


# Module-level decoders
_START_DECODER = msgspec.json.Decoder(StartImportResponse)
_LIST_DECODER = msgspec.json.Decoder(ListImportsResponse)
_DESCRIBE_DECODER = msgspec.json.Decoder(ImportModel)
_CANCEL_DECODER = msgspec.json.Decoder(CancelImportResponse)


class BulkImports:
    """Sub-namespace for bulk import operations on a Pinecone index.

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

        index = Index(host="...", api_key="...")
        imports = index.bulk_imports.list()

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

    def __init__(self, *, http: HTTPClient, 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

        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 start(
        self,
        *,
        uri: str,
        integration_id: str | None = None,
        error_mode: Literal["abort", "continue"] | None = None,
    ) -> StartImportResponse:
        """Start a bulk import operation.

        Args:
            uri: Source URI (S3, GCS, or Azure) containing the data to import.
            integration_id: Storage integration ID for authentication.
            error_mode: How to handle errors during import. Either ``"abort"`` to
                stop on first error, or ``"continue"`` to skip bad records.

        Returns:
            StartImportResponse with the import operation ID.

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

        Examples:
            >>> response = index.bulk_imports.start(uri="s3://my-bucket/my-data/")
            >>> print(f"Import started: {response.id}")
        """
        require_non_empty("uri", uri)

        body: dict[str, Any] = {"uri": uri}
        if integration_id is not None:
            body["integrationId"] = integration_id
        if error_mode is not None:
            body["errorMode"] = {"onError": error_mode}

        data = self._make_data_plane_request("POST", "/bulk/imports", body=body)
        return _START_DECODER.decode(data)

    def list(
        self,
        *,
        limit: int | None = None,
        pagination_token: str | None = None,
    ) -> ListImportsResponse:
        """List bulk import operations.

        Args:
            limit: Maximum number of imports to return (default 100, max 100).
            pagination_token: Token to resume from a previous call.

        Returns:
            ListImportsResponse with import operations and pagination info.

        Raises:
            PineconeApiException: If the API request fails.

        Examples:
            >>> response = index.bulk_imports.list(limit=10)
            >>> for imp in response.data:
            ...     print(f"{imp.id}: {imp.status}")
        """
        params: dict[str, Any] = {}
        if limit is not None:
            params["limit"] = limit
        if pagination_token is not None:
            params["paginationToken"] = pagination_token

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

    def describe(
        self,
        *,
        id: str,  # noqa: A002
    ) -> ImportModel:
        """Describe a bulk import operation.

        Args:
            id: The import operation ID.

        Returns:
            ImportModel with details about the import operation.

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

        Examples:
            >>> imp = index.bulk_imports.describe(id="import-123")
            >>> print(f"{imp.status}: {imp.percent_complete}%")
        """
        require_non_empty("id", id)

        data = self._make_data_plane_request("GET", f"/bulk/imports/{id}")
        return _DESCRIBE_DECODER.decode(data)

    def cancel(
        self,
        *,
        id: str,  # noqa: A002
    ) -> CancelImportResponse:
        """Cancel a bulk import operation.

        Args:
            id: The import operation ID to cancel.

        Returns:
            CancelImportResponse (empty on success).

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

        Examples:
            >>> index.bulk_imports.cancel(id="import-123")
        """
        require_non_empty("id", id)

        data = self._make_data_plane_request("DELETE", f"/bulk/imports/{id}")
        return _CANCEL_DECODER.decode(data)

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