"""Create for model method for async indexes namespace."""

from __future__ import annotations

import re

from typing import TYPE_CHECKING, Any, cast

import orjson

from pinecone._internal.constants import INDEXES_API_VERSION
from pinecone._internal.logging import get_logger
from pinecone._internal.validation import require_non_empty


if TYPE_CHECKING:
    from pinecone.__interface__.indexes import IndexInfoProtocol


logger = get_logger(__name__)


async def create_for_model(  # noqa: PLR0912
    self: Any,
    name: str,
    cloud: str,
    region: str,
    *,
    embed: dict[str, Any],
    deletion_protection: str = "disabled",
    tags: dict[str, str] | None = None,
    schema: dict[str, Any] | None = None,
    read_capacity: dict[str, Any] | None = None,
    timeout: int | None = None,
) -> IndexInfoProtocol:
    """Create index with integrated embedding model.

    Creates a serverless index with automatic text embedding using a hosted model.
    The model's dimension and metric are automatically configured.

    Args:
        name: Unique index name (1-45 chars, lowercase alphanumeric or '-')
        cloud: Cloud provider ("aws", "gcp", or "azure")
        region: Region for deployment
        embed: Embedding configuration with required fields:
            - model: Model name (e.g., "multilingual-e5-large")
            - field_map: {"text": "your-field-name"} mapping to text field
            - Optional: read_parameters, write_parameters, dimension, metric
        deletion_protection: "disabled" or "enabled" (default: "disabled")
        tags: Optional key-value tags
        schema: Optional metadata schema for indexing specific fields
        read_capacity: Optional read capacity configuration for dedicated nodes
        timeout: Optional timeout in seconds

    Returns:
        IndexInfo with created index metadata

    Raises:
        BadRequestError: If parameters are invalid
        ConflictError: If index name already exists
        NotFoundError: If cloud/region combination is invalid
        APIError: If the API returns an error response
        APIConnectionError: If the request fails to connect
        TimeoutError: If the request times out

    Example:
        >>> # Create with multilingual embedding model
        >>> info = await pc.indexes.create_for_model(
        ...     name="semantic-search",
        ...     cloud="aws",
        ...     region="us-east-1",
        ...     embed={"model": "multilingual-e5-large", "field_map": {"text": "content"}},
        ... )

    Example with custom parameters:
        >>> # Create with custom parameters
        >>> info = await pc.indexes.create_for_model(
        ...     name="custom-search",
        ...     cloud="gcp",
        ...     region="us-east1",
        ...     embed={
        ...         "model": "llama-text-embed-v2",
        ...         "field_map": {"text": "text_content"},
        ...         "read_parameters": {"input_type": "query", "truncate": "NONE"},
        ...         "write_parameters": {"input_type": "passage"},
        ...     },
        ...     deletion_protection="enabled",
        ...     tags={"environment": "production"},
        ... )
    """
    # 1. Validate inputs
    require_non_empty("name", name)
    require_non_empty("cloud", cloud)
    require_non_empty("region", region)

    # Validate index name format
    if len(name) > 45:
        raise ValueError(f"Index name '{name}' exceeds 45 character limit ({len(name)} chars)")

    if not re.match(r"^[a-z0-9-]+$", name):
        raise ValueError(
            f"Index name '{name}' contains invalid characters. "
            "Name must contain only lowercase letters, numbers, and hyphens."
        )

    # Validate embed configuration
    if not embed or not isinstance(embed, dict):
        raise ValueError("embed configuration is required and must be a dictionary")

    if "model" not in embed:
        raise ValueError("embed configuration must include 'model' field")

    if "field_map" not in embed:
        raise ValueError("embed configuration must include 'field_map' field")

    # Validate tags
    if tags:
        for key, value in tags.items():
            if len(key) > 80:
                raise ValueError(f"Tag key '{key}' exceeds 80 character limit ({len(key)} chars)")
            if len(value) > 120:
                raise ValueError(
                    f"Tag value for key '{key}' exceeds 120 character limit ({len(value)} chars)"
                )

    # 2. Log operation start
    logger.info(
        "Creating index with embedding model",
        name=name,
        cloud=cloud,
        region=region,
        model=embed.get("model"),
    )

    # 3. Build request body
    request_body: dict[str, Any] = {
        "name": name,
        "cloud": cloud,
        "region": region,
        "embed": embed,
        "deletion_protection": deletion_protection,
    }

    if tags:
        request_body["tags"] = tags

    if schema:
        request_body["schema"] = schema

    if read_capacity:
        request_body["read_capacity"] = read_capacity

    try:
        # 4. Make HTTP request
        response = await self._http.post(
            f"{self._base_url}/indexes/create-for-model",
            content=orjson.dumps(request_body),
            headers={
                "Content-Type": "application/json",
                "X-Pinecone-Api-Version": INDEXES_API_VERSION,
            },
            timeout=timeout,
        )

        # 5. Transform response via adapter
        data = orjson.loads(response.content)
        result = self._adapter.to_index_model(data)

        # 6. Log success
        logger.debug(
            "Index with embedding model created successfully",
            name=name,
            host=result.host,
        )

        return cast("IndexInfoProtocol", result)

    except Exception:
        # 7. Log failure with context
        logger.exception(
            "Failed to create index with embedding model",
            name=name,
            cloud=cloud,
            region=region,
        )
        raise
