"""Async index management operations (2026-01.alpha API).

This module provides the async schema-driven index management API. Indexes are
defined with field-level schemas instead of top-level dimension/metric parameters.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from pinecone._internal.constants import INDEXES_API_VERSION_ALPHA


if TYPE_CHECKING:
    from pinecone.models.indexes import IndexList, IndexModel
    from pinecone.models.pagination import AsyncPaginator, Page


class AsyncIndexes:
    """Async index management operations.

    This class provides async CRUD operations for managing Pinecone indexes using
    the 2026-01.alpha schema-driven API. All operations are fully async and can
    be used concurrently.

    Access via the ``indexes`` property on an AsyncPinecone instance::

        async with AsyncPinecone(api_key="...") as pc:
            await pc.indexes.create(schema={...})

    Args:
        http_client: Async HTTP client for making requests
        base_url: Base URL for the control plane API

    Example - Create index (defaults to managed if deployment omitted):
        >>> from pinecone import AsyncPinecone
        >>> import asyncio
        >>>
        >>> async def main():
        ...     async with AsyncPinecone(api_key="...") as pc:
        ...         index = await pc.indexes.create(
        ...             name="my-index",
        ...             schema={
        ...                 "fields": {
        ...                     "embedding": {
        ...                         "type": "dense_vector",
        ...                         "dimension": 1536,
        ...                         "metric": "cosine",
        ...                     }
        ...                 }
        ...             },
        ...             deployment={
        ...                 "deployment_type": "managed",
        ...                 "environment": "aped-4627-b74a",
        ...                 "cloud": "aws",
        ...                 "region": "us-east-1",
        ...             },
        ...         )
        >>> asyncio.run(main())

    Example - Concurrent operations:
        >>> async def create_multiple():
        ...     async with AsyncPinecone(api_key="...") as pc:
        ...         tasks = [pc.indexes.create(name=f"index-{i}", schema=schema) for i in range(5)]
        ...         return await asyncio.gather(*tasks)

    Note:
        This is the 2026-01.alpha API. For the legacy 2025-10 API, use
        ``pc.indexes_old``.
    """

    def __init__(self, *, http_client: Any, base_url: str) -> None:
        """Initialize AsyncIndexes namespace.

        Args:
            http_client: Async HTTP client for making requests
            base_url: Base URL for the control plane API
        """
        self._http = http_client
        self._base_url = base_url

    async def _make_indexes_request(
        self,
        method: str,
        path: str,
        **kwargs: Any,
    ) -> Any:
        """Make async HTTP request to indexes API with 2026-01.alpha version header.

        Args:
            method: HTTP method ("get", "post", "patch", "delete")
            path: API path (e.g., "/indexes", "/indexes/my-index")
            **kwargs: Additional arguments to pass to HTTP client

        Returns:
            HTTP response object

        Example:
            >>> response = await self._make_indexes_request(
            ...     "post", "/indexes", headers={"Content-Type": "application/json"}, content=json_bytes
            ... )
        """
        # Get or create headers dict
        headers = kwargs.pop("headers", {})

        # Add API version header
        headers["X-Pinecone-Api-Version"] = INDEXES_API_VERSION_ALPHA

        # Make async request
        return await getattr(self._http, method)(
            f"{self._base_url}{path}",
            headers=headers,
            **kwargs,
        )

    async def create(
        self,
        *,
        schema: dict[str, Any],
        name: str | None = None,
        deployment: dict[str, Any] | None = None,
        read_capacity: dict[str, Any] | None = None,
        deletion_protection: str | None = None,
        tags: dict[str, str] | None = None,
        source_collection: str | None = None,
    ) -> IndexModel:
        """Create a new index with schema-driven configuration.

        The 2026-01.alpha API uses field-level schema definitions instead of
        top-level dimension/metric/vector_type parameters. This enables indexes
        with multiple vector fields, full-text search, and metadata filtering.

        Args:
            schema: Index schema with field definitions. Required.
            name: Index name (auto-generated if not provided)
            deployment: Deployment configuration dict
            read_capacity: Read capacity specification (managed indexes only)
            deletion_protection: "enabled" or "disabled"
            tags: User-defined key-value tags
            source_collection: Create index from existing collection

        Returns:
            IndexModel: Created index description

        Example:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     index = await pc.indexes.create(
            ...         schema={
            ...             "fields": {
            ...                 "embedding": {
            ...                     "type": "dense_vector",
            ...                     "dimension": 1536,
            ...                     "metric": "cosine",
            ...                 }
            ...             }
            ...         }
            ...     )
        """
        from pinecone._internal.adapters.indexes import create_adapter
        from pinecone._internal.validation import (
            convert_with_validation,
            parse_response_with_validation,
        )
        from pinecone.models.indexes import CreateIndexRequest

        # Build request dict then convert to typed model
        # This allows users to pass dicts while ensuring type safety
        # Filter out None values - API expects fields to be omitted, not null
        request_dict = {
            "schema": schema,
            "name": name,
            "deployment": deployment,
            "read_capacity": read_capacity,
            "deletion_protection": deletion_protection,
            "tags": tags,
            "source_collection": source_collection,
        }
        request_dict = {k: v for k, v in request_dict.items() if v is not None}

        # Convert dict to typed model with validation
        request = convert_with_validation(request_dict, CreateIndexRequest, "create index request")

        # Make async HTTP request
        response = await self._make_indexes_request(
            "post",
            "/indexes",
            headers={"Content-Type": "application/json"},
            content=create_adapter.to_request(request),
        )

        # Parse and return response
        return parse_response_with_validation(response, create_adapter, "create index response")

    def list(
        self,
        *,
        limit: int | None = None,
        pagination_token: str | None = None,
    ) -> AsyncPaginator[IndexModel]:
        """List all indexes in the project.

        Returns detailed information about all indexes, including their schema,
        deployment configuration, and operational status.

        Args:
            limit: Maximum number of items to return (across all pages).
            pagination_token: Token to resume pagination from a previous call.

        Returns:
            AsyncPaginator[IndexModel]: Async iterable paginator over index descriptions.
            Iterate directly for items, or use .pages() for page-level access.

        Raises:
            APIError: If API request fails

        Note:
            The 2026-01.alpha indexes API currently returns all indexes in a single
            response. Pagination parameters are supported by the AsyncPaginator for
            consistency with other list methods and future API enhancements.

        Example - Iterate over indexes:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     async for index in pc.indexes.list():
            ...         print(f"{index.name}: {index.status.state}")
            ...         print(f"  Fields: {list(index.schema.fields.keys())}")

        Example - Convert to list:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     # Note: to_list() is async and fetches all pages
            ...     all_indexes = await pc.indexes.list().to_list()
            ...     print(f"Found {len(all_indexes)} indexes")

        Example - Check if index exists:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     existing_indexes = [idx.name async for idx in pc.indexes.list()]
            ...     if "my-index" in existing_indexes:
            ...         print("Index exists")

        Example - Limit results:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     async for index in pc.indexes.list(limit=5):
            ...         print(index.name)

        Example - Page-level access:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     async for page in pc.indexes.list().pages():
            ...         print(f"Retrieved {len(page.items)} indexes")
        """
        from pinecone._internal.adapters.indexes import list_adapter
        from pinecone._internal.validation import (
            parse_response_with_validation,
        )
        from pinecone.models.pagination import AsyncPaginator, Page

        async def fetch_page(token: str | None) -> Page[IndexModel]:
            """Fetch a page of indexes."""
            # Make async HTTP request
            response = await self._make_indexes_request("get", "/indexes")

            # Parse response
            result: IndexList = parse_response_with_validation(
                response, list_adapter, "list indexes response"
            )

            # API currently doesn't support pagination, return all items in one page
            return Page(items=result.indexes, pagination_token=None)

        return AsyncPaginator(
            fetch_page=fetch_page,
            initial_token=pagination_token,
            limit=limit,
            item_type="IndexModel",
        )

    async def describe(self, name: str) -> IndexModel:
        """Get detailed information about a specific index.

        Returns complete index configuration including schema, deployment,
        read capacity, and operational status.

        Args:
            name: Index name

        Returns:
            IndexModel: Full index description

        Example:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     index = await pc.indexes.describe("my-index")
            ...     print(f"Fields: {list(index.schema.fields.keys())}")
        """
        from pinecone._internal.adapters.indexes import describe_adapter
        from pinecone._internal.validation import (
            parse_response_with_validation,
        )

        # Make async HTTP request
        response = await self._make_indexes_request("get", f"/indexes/{name}")

        # Parse and return response
        return parse_response_with_validation(response, describe_adapter, "describe index response")

    async def delete(self, name: str) -> None:
        """Delete an index.

        Permanently deletes an index and all its data. This operation cannot
        be undone. If deletion protection is enabled on the index, this will
        fail.

        Args:
            name: Index name to delete

        Example:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     await pc.indexes.delete("my-index")
        """
        # Make async HTTP request
        await self._make_indexes_request("delete", f"/indexes/{name}")

    async def configure(
        self,
        name: str,
        *,
        schema: dict[str, Any] | None = None,
        deployment: dict[str, Any] | None = None,
        read_capacity: dict[str, Any] | None = None,
        deletion_protection: str | None = None,
        tags: dict[str, str] | None = None,
    ) -> IndexModel:
        """Update index configuration.

        The 2026-01.alpha API supports partial updates to schema, read capacity,
        deployment, deletion protection, and tags. Only provided fields are updated.

        Args:
            name: Index name to configure
            schema: Updated schema (can add new fields)
            deployment: Updated deployment configuration
            read_capacity: Updated read capacity specification
            deletion_protection: "enabled" or "disabled"
            tags: Updated tags

        Returns:
            IndexModel: Updated index description

        Example:
            >>> async with AsyncPinecone(api_key="...") as pc:
            ...     index = await pc.indexes.configure("my-index", deletion_protection="enabled")
        """
        from pinecone._internal.adapters.indexes import configure_adapter
        from pinecone._internal.validation import (
            convert_with_validation,
            parse_response_with_validation,
        )
        from pinecone.models.indexes import ConfigureIndexRequest

        # Build request dict then convert to typed model
        # This allows users to pass dicts while ensuring type safety
        request_dict = {
            "schema": schema,
            "deployment": deployment,
            "read_capacity": read_capacity,
            "deletion_protection": deletion_protection,
            "tags": tags,
        }

        # Convert dict to typed model with validation
        request = convert_with_validation(
            request_dict, ConfigureIndexRequest, "configure index request"
        )

        # Make async HTTP request
        response = await self._make_indexes_request(
            "patch",
            f"/indexes/{name}",
            headers={"Content-Type": "application/json"},
            content=configure_adapter.to_request(request),
        )

        # Parse and return response
        return parse_response_with_validation(
            response, configure_adapter, "configure index response"
        )

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


__all__ = ["AsyncIndexes"]
