"""
Models resource classes.

Auto-generated from OpenAPI specification.
"""

from __future__ import annotations

from typing import (
    TYPE_CHECKING,
    Any,
    AsyncIterator,
    Dict,
    Iterator,
    Optional,
)

if TYPE_CHECKING:
    from ..fluent import AsyncModel, Model

from pydantic import BaseModel

from ..errors import ApiError, ClientValidationError
from ..models import (
    ModelCreate,
    ModelResponse,
    ModelUpdate,
    PaginatedResponse,
)


class ModelsResource:
    """Resource class for models operations

    Provides structured Pydantic types for all models API operations.
    All methods return validated Pydantic models with comprehensive error handling.

    Available operations:
        - create(): Create Model
        - list(): List Models
        - get(): Get Model
        - update(): Update Model
        - delete(): Delete Model
    Example:
        >>> client = CredoAI("https://api.example.com", "your-api-key")
        >>> models_resource = client.models
        >>> client.models.create(data=ModelCreate(...))
    """

    def __init__(self, client):
        """Initialize the ModelsResource.

        Args:
            client: The parent client instance providing HTTP functionality.
        """
        self._client = client

    def create(
        self,
        data: ModelCreate,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> ModelResponse:
        """Create Model.

                Create a new model.

        This endpoint creates a new model in the Credo AI model registry.

                Args:
                    data (ModelCreate): Request data as validated Pydantic model.
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    ModelResponse: Validated response data.

                Response Codes:
                    201: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        url = "/models"

        return self._client._make_request(
            method="POST",
            url=url,
            data=data,
            timeout=timeout,
            headers=headers,
            response_model=ModelResponse,
            is_list_response=False,
        )

    def list(
        self,
        page_limit: Optional[Any] = None,
        page_after: Optional[Any] = None,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> PaginatedResponse[ModelResponse]:
        """List Models.

                List all models.

        This endpoint retrieves all models with optional pagination.
        Returns a paginated response with items and pagination metadata.

                Args:
                    page_limit (Any, optional): Parameter
                    page_after (Any, optional): Parameter
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    List[ModelResponse]: Validated response data.

                Response Codes:
                    200: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        url = "/models"

        # Build query parameters
        params: Dict[str, Any] = {}
        if page_limit is not None:
            params["page_limit"] = page_limit
        if page_after is not None:
            params["page_after"] = page_after

        return self._client._make_request(
            method="GET",
            url=url,
            params=params if params else None,
            timeout=timeout,
            headers=headers,
            response_model=PaginatedResponse[ModelResponse],
            is_list_response=False,
        )

    def get(
        self,
        model_id: str,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> ModelResponse:
        """Get Model.

                Get a model by ID.

        This endpoint retrieves an existing model by its ID.

                Args:
                    model_id (str): Parameter
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    ModelResponse: Validated response data.

                Response Codes:
                    200: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        url = "/models/{model_id}"
        url = url.replace("{" + "model_id" + "}", str(model_id))

        return self._client._make_request(
            method="GET",
            url=url,
            timeout=timeout,
            headers=headers,
            response_model=ModelResponse,
            is_list_response=False,
        )

    def update(
        self,
        model_id: str,
        data: ModelUpdate,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> ModelResponse:
        """Update Model.

                Update an existing model.

        This endpoint updates an existing model with the provided data.
        Only the fields provided in the request will be updated.

                Args:
                    model_id (str): Parameter
                    data (ModelUpdate): Request data as validated Pydantic model.
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    ModelResponse: Validated response data.

                Response Codes:
                    200: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        url = "/models/{model_id}"
        url = url.replace("{" + "model_id" + "}", str(model_id))

        return self._client._make_request(
            method="PATCH",
            url=url,
            data=data,
            timeout=timeout,
            headers=headers,
            response_model=ModelResponse,
            is_list_response=False,
        )

    def delete(
        self,
        model_id: str,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> Any:
        """Delete Model.

                Delete a model by ID.

        This endpoint deletes an existing model by its ID.

                Args:
                    model_id (str): Parameter
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    Any: Raw API response data.

                Response Codes:
                    204: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        url = "/models/{model_id}"
        url = url.replace("{" + "model_id" + "}", str(model_id))

        return self._client._make_request(
            method="DELETE",
            url=url,
            timeout=timeout,
            headers=headers,
        )

    def list_all(
        self,
        page_size: int = 100,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> Iterator[ModelResponse]:
        """Iterate through all models with automatic pagination.

        This generator yields items one at a time, automatically fetching
        the next page when needed. Use this for efficiently processing
        large result sets without loading everything into memory.

        Args:
            page_size (int): Number of items to fetch per page. Default: 100
            timeout (float, optional): Request timeout in seconds.
            headers (Dict[str, str], optional): Additional headers to send.

        Yields:
            ModelResponse: Individual items from the list.

        Example:
            >>> for item in client.models.list_all(page_size=50):
            ...     print(item.id)
            >>>
            >>> # Collect all into a list
            >>> all_items = list(client.models.list_all())
        """
        page_after = None
        while True:
            response = self.list(
                page_limit=page_size,
                page_after=page_after,
                timeout=timeout,
                headers=headers,
            )
            # Handle paginated response with items and pagination metadata
            items = response.items
            if not items:
                break
            for item in items:
                yield item
            # Use pagination cursor for next page
            if not response.pagination.has_more:
                break
            page_after = response.pagination.next_cursor

    def __call__(self, model_id: str) -> "Model":
        """Get a fluent accessor for a specific model.

        Enables intuitive subresource access:
            >>> client.models(model_id).questionnaires.list()
            >>> client.models(model_id).questionnaires.add(data)
            >>> client.models(model_id).use_cases.list()
            >>> client.models(model_id).use_cases.add(data)
            >>> client.models(model_id).vendors.list()
            >>> client.models(model_id).vendors.add(data)

        Args:
            model_id: The ID of the model

        Returns:
            Model: Fluent accessor for subresource operations
        """
        from ..fluent import Model

        return Model(self._client, model_id)


class AsyncModelsResource:
    """Async resource class for models operations

    Provides async methods with structured Pydantic types for all models API operations.
    All methods are async and return validated Pydantic models with comprehensive error handling.

    Available async operations:
        - create(): Create Model
        - list(): List Models
        - get(): Get Model
        - update(): Update Model
        - delete(): Delete Model
    Example:
        >>> async_client = AsyncCredoAI("https://api.example.com", "your-api-key")
        >>> models_resource = async_client.models
        >>> result = await async_client.models.create(data=ModelCreate(...))
    """

    def __init__(self, client):
        """Initialize the AsyncModelsResource.

        Args:
            client: The parent async client instance providing HTTP functionality.
        """
        self._client = client

    async def create(
        self,
        data: ModelCreate,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> ModelResponse:
        """Create Model.

                Create a new model.

        This endpoint creates a new model in the Credo AI model registry.

                Args:
                    data (ModelCreate): Request data as validated Pydantic model.
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    ModelResponse: Validated response data.

                Response Codes:
                    201: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        # Prepare URL with path parameters
        url = "/models"

        # Prepare headers
        request_headers = {"Accept": "application/json"}
        if headers:
            request_headers.update(headers)
        # Serialize request data
        json_data = None
        if data is not None:
            if isinstance(data, BaseModel):
                json_data = data.model_dump(exclude_unset=True, by_alias=True)
            else:
                json_data = data
            request_headers["Content-Type"] = "application/json"

        # Make async request
        httpx_client = self._client.get_async_httpx_client()
        response = await httpx_client.request(
            method="POST",
            url=url,
            json=json_data,
            headers=request_headers,
            timeout=timeout,
        )

        # Handle errors
        if response.status_code >= 400:
            raise ApiError(
                status_code=response.status_code,
                message=f"POST {url} failed",
                response=response,
            )

        # Parse and validate response
        if self._client._validate_responses and response.content:
            try:
                response_data = response.json()

                # Handle JSON:API format
                if isinstance(response_data, dict) and "data" in response_data:
                    from ..models import JsonApiResponse

                    jsonapi_response = JsonApiResponse.model_validate(response_data)
                    data = jsonapi_response.data
                    # Check for attributes in both dict and object forms
                    if isinstance(data, dict) and "attributes" in data:
                        # Merge id from data level with attributes
                        merged = {"id": data.get("id"), **data["attributes"]}
                        parsed_data = ModelResponse.model_validate(merged)
                    elif hasattr(data, "attributes"):
                        parsed_data = ModelResponse.model_validate(data.attributes)
                    else:
                        parsed_data = ModelResponse.model_validate(data)
                    return parsed_data
                parsed_data = ModelResponse.model_validate(response_data)
                return parsed_data

            except Exception as e:
                if self._client._validate_responses:
                    raise ClientValidationError(f"Response validation failed: {e}")

        # Return basic response wrapper
        from ..models import ClientResponse

        return ClientResponse.from_httpx_response(
            response, response.json() if response.content else None
        )

    async def list(
        self,
        page_limit: Optional[Any] = None,
        page_after: Optional[Any] = None,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> PaginatedResponse[ModelResponse]:
        """List Models.

                List all models.

        This endpoint retrieves all models with optional pagination.
        Returns a paginated response with items and pagination metadata.

                Args:
                    page_limit (Any, optional): Parameter
                    page_after (Any, optional): Parameter
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    List[ModelResponse]: Validated response data.

                Response Codes:
                    200: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        # Prepare URL with path parameters
        url = "/models"

        # Build query parameters
        params: Dict[str, Any] = {}
        if page_limit is not None:
            params["page_limit"] = page_limit
        if page_after is not None:
            params["page_after"] = page_after

        # Prepare headers
        request_headers = {"Accept": "application/json"}
        if headers:
            request_headers.update(headers)

        # Make async request
        httpx_client = self._client.get_async_httpx_client()
        response = await httpx_client.request(
            method="GET",
            url=url,
            params=params if params else None,
            headers=request_headers,
            timeout=timeout,
        )

        # Handle errors
        if response.status_code >= 400:
            raise ApiError(
                status_code=response.status_code,
                message=f"GET {url} failed",
                response=response,
            )

        # Parse and validate response
        if self._client._validate_responses and response.content:
            try:
                response_data = response.json()

                # Handle JSON:API format
                if isinstance(response_data, dict) and "data" in response_data:
                    from ..models import JsonApiResponse

                    jsonapi_response = JsonApiResponse.model_validate(response_data)
                    data = jsonapi_response.data
                    # Check for attributes in both dict and object forms
                    if isinstance(data, dict) and "attributes" in data:
                        # Merge id from data level with attributes
                        merged = {"id": data.get("id"), **data["attributes"]}
                        parsed_data = ModelResponse.model_validate(merged)
                    elif hasattr(data, "attributes"):
                        parsed_data = ModelResponse.model_validate(data.attributes)
                    else:
                        parsed_data = ModelResponse.model_validate(data)
                    return parsed_data
                # Handle paginated response
                parsed_data = PaginatedResponse[ModelResponse].model_validate(
                    response_data
                )
                return parsed_data

            except Exception as e:
                if self._client._validate_responses:
                    raise ClientValidationError(f"Response validation failed: {e}")

        # Return basic response wrapper
        from ..models import ClientResponse

        return ClientResponse.from_httpx_response(
            response, response.json() if response.content else None
        )

    async def get(
        self,
        model_id: str,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> ModelResponse:
        """Get Model.

                Get a model by ID.

        This endpoint retrieves an existing model by its ID.

                Args:
                    model_id (str): Parameter
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    ModelResponse: Validated response data.

                Response Codes:
                    200: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        # Prepare URL with path parameters
        url = "/models/{model_id}"
        url = url.replace("{" + "model_id" + "}", str(model_id))

        # Prepare headers
        request_headers = {"Accept": "application/json"}
        if headers:
            request_headers.update(headers)

        # Make async request
        httpx_client = self._client.get_async_httpx_client()
        response = await httpx_client.request(
            method="GET", url=url, headers=request_headers, timeout=timeout
        )

        # Handle errors
        if response.status_code >= 400:
            raise ApiError(
                status_code=response.status_code,
                message=f"GET {url} failed",
                response=response,
            )

        # Parse and validate response
        if self._client._validate_responses and response.content:
            try:
                response_data = response.json()

                # Handle JSON:API format
                if isinstance(response_data, dict) and "data" in response_data:
                    from ..models import JsonApiResponse

                    jsonapi_response = JsonApiResponse.model_validate(response_data)
                    data = jsonapi_response.data
                    # Check for attributes in both dict and object forms
                    if isinstance(data, dict) and "attributes" in data:
                        # Merge id from data level with attributes
                        merged = {"id": data.get("id"), **data["attributes"]}
                        parsed_data = ModelResponse.model_validate(merged)
                    elif hasattr(data, "attributes"):
                        parsed_data = ModelResponse.model_validate(data.attributes)
                    else:
                        parsed_data = ModelResponse.model_validate(data)
                    return parsed_data
                parsed_data = ModelResponse.model_validate(response_data)
                return parsed_data

            except Exception as e:
                if self._client._validate_responses:
                    raise ClientValidationError(f"Response validation failed: {e}")

        # Return basic response wrapper
        from ..models import ClientResponse

        return ClientResponse.from_httpx_response(
            response, response.json() if response.content else None
        )

    async def update(
        self,
        model_id: str,
        data: ModelUpdate,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> ModelResponse:
        """Update Model.

                Update an existing model.

        This endpoint updates an existing model with the provided data.
        Only the fields provided in the request will be updated.

                Args:
                    model_id (str): Parameter
                    data (ModelUpdate): Request data as validated Pydantic model.
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    ModelResponse: Validated response data.

                Response Codes:
                    200: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        # Prepare URL with path parameters
        url = "/models/{model_id}"
        url = url.replace("{" + "model_id" + "}", str(model_id))

        # Prepare headers
        request_headers = {"Accept": "application/json"}
        if headers:
            request_headers.update(headers)
        # Serialize request data
        json_data = None
        if data is not None:
            if isinstance(data, BaseModel):
                json_data = data.model_dump(exclude_unset=True, by_alias=True)
            else:
                json_data = data
            request_headers["Content-Type"] = "application/json"

        # Make async request
        httpx_client = self._client.get_async_httpx_client()
        response = await httpx_client.request(
            method="PATCH",
            url=url,
            json=json_data,
            headers=request_headers,
            timeout=timeout,
        )

        # Handle errors
        if response.status_code >= 400:
            raise ApiError(
                status_code=response.status_code,
                message=f"PATCH {url} failed",
                response=response,
            )

        # Parse and validate response
        if self._client._validate_responses and response.content:
            try:
                response_data = response.json()

                # Handle JSON:API format
                if isinstance(response_data, dict) and "data" in response_data:
                    from ..models import JsonApiResponse

                    jsonapi_response = JsonApiResponse.model_validate(response_data)
                    data = jsonapi_response.data
                    # Check for attributes in both dict and object forms
                    if isinstance(data, dict) and "attributes" in data:
                        # Merge id from data level with attributes
                        merged = {"id": data.get("id"), **data["attributes"]}
                        parsed_data = ModelResponse.model_validate(merged)
                    elif hasattr(data, "attributes"):
                        parsed_data = ModelResponse.model_validate(data.attributes)
                    else:
                        parsed_data = ModelResponse.model_validate(data)
                    return parsed_data
                parsed_data = ModelResponse.model_validate(response_data)
                return parsed_data

            except Exception as e:
                if self._client._validate_responses:
                    raise ClientValidationError(f"Response validation failed: {e}")

        # Return basic response wrapper
        from ..models import ClientResponse

        return ClientResponse.from_httpx_response(
            response, response.json() if response.content else None
        )

    async def delete(
        self,
        model_id: str,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> Any:
        """Delete Model.

                Delete a model by ID.

        This endpoint deletes an existing model by its ID.

                Args:
                    model_id (str): Parameter
                    timeout (float, optional): Request timeout in seconds.
                    headers (Dict[str, str], optional): Additional headers to send.

                Returns:
                    Any: Raw API response data.

                Response Codes:
                    204: Successful Response
                    422: Error

                Raises:
                    ApiError: When the API returns an error status code.
                    ClientValidationError: When response validation fails.
                    httpx.TimeoutException: When request times out."""
        # Prepare URL with path parameters
        url = "/models/{model_id}"
        url = url.replace("{" + "model_id" + "}", str(model_id))

        # Prepare headers
        request_headers = {"Accept": "application/json"}
        if headers:
            request_headers.update(headers)

        # Make async request
        httpx_client = self._client.get_async_httpx_client()
        response = await httpx_client.request(
            method="DELETE", url=url, headers=request_headers, timeout=timeout
        )

        # Handle errors
        if response.status_code >= 400:
            raise ApiError(
                status_code=response.status_code,
                message=f"DELETE {url} failed",
                response=response,
            )

        # Parse and validate response

        # Return basic response wrapper
        from ..models import ClientResponse

        return ClientResponse.from_httpx_response(
            response, response.json() if response.content else None
        )

    async def list_all(
        self,
        page_size: int = 100,
        *,
        timeout: Optional[float] = None,
        headers: Optional[Dict[str, str]] = None,
    ) -> AsyncIterator[ModelResponse]:
        """Asynchronously iterate through all models with automatic pagination.

        This async generator yields items one at a time, automatically fetching
        the next page when needed. Use this for efficiently processing
        large result sets without loading everything into memory.

        Args:
            page_size (int): Number of items to fetch per page. Default: 100
            timeout (float, optional): Request timeout in seconds.
            headers (Dict[str, str], optional): Additional headers to send.

        Yields:
            ModelResponse: Individual items from the list.

        Example:
            >>> async for item in client.models.list_all(page_size=50):
            ...     print(item.id)
            >>>
            >>> # Collect all into a list
            >>> all_items = [item async for item in client.models.list_all()]
        """
        page_after = None
        while True:
            response = await self.list(
                page_limit=page_size,
                page_after=page_after,
                timeout=timeout,
                headers=headers,
            )
            # Handle paginated response with items and pagination metadata
            items = response.items
            if not items:
                break
            for item in items:
                yield item
            # Use pagination cursor for next page
            if not response.pagination.has_more:
                break
            page_after = response.pagination.next_cursor

    def __call__(self, model_id: str) -> "AsyncModel":
        """Get an async fluent accessor for a specific model.

        Enables intuitive subresource access with async/await:
            >>> await client.models(model_id).questionnaires.list()
            >>> await client.models(model_id).questionnaires.add(data)
            >>> await client.models(model_id).use_cases.list()
            >>> await client.models(model_id).use_cases.add(data)
            >>> await client.models(model_id).vendors.list()
            >>> await client.models(model_id).vendors.add(data)

        Args:
            model_id: The ID of the model

        Returns:
            AsyncModel: Async fluent accessor for subresource operations
        """
        from ..fluent import AsyncModel

        return AsyncModel(self._client, model_id)
