# This file was auto-generated by Fern from our API Definition.

import contextlib
import typing
from json.decoder import JSONDecodeError
from logging import error, warning

from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
from ..core.http_sse._api import EventSource
from ..core.jsonable_encoder import jsonable_encoder
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..errors.unprocessable_entity_error import UnprocessableEntityError
from ..types.deploy_stream_event import DeployStreamEvent
from ..types.http_validation_error import HttpValidationError
from ..types.register_container_response import RegisterContainerResponse
from ..types.version_metrics_response import VersionMetricsResponse
from ..types.version_response import VersionResponse

# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)


class RawVersionsClient:
    def __init__(self, *, client_wrapper: SyncClientWrapper):
        self._client_wrapper = client_wrapper

    def register(
        self,
        *,
        acp_url: str,
        branch_id: str,
        version_id: str,
        registration_token: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[RegisterContainerResponse]:
        """
        Register an agent container that has started up.

            Called by the agent container on startup to:
            1. Register its ACP URL with the platform
            2. Receive its API key for authenticating subsequent requests

            This endpoint should be called from within the container's entrypoint
            after the ACP server is ready to receive traffic.

        Parameters
        ----------
        acp_url : str
            ACP server URL (e.g., 'http://agent-main-abc123.agents.svc.cluster.local:8000')

        branch_id : str
            Branch ID

        version_id : str
            Version ID being registered

        registration_token : typing.Optional[str]
            Single-use registration token provided during deployment (required when configured)

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[RegisterContainerResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            "versions/register",
            method="POST",
            json={
                "acp_url": acp_url,
                "branch_id": branch_id,
                "registration_token": registration_token,
                "version_id": version_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RegisterContainerResponse,
                    parse_obj_as(
                        type_=RegisterContainerResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        HttpValidationError,
                        parse_obj_as(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    def retrieve(
        self, version_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[VersionResponse]:
        """
        Get version details by ID.

        Parameters
        ----------
        version_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[VersionResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"versions/{jsonable_encoder(version_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    VersionResponse,
                    parse_obj_as(
                        type_=VersionResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        HttpValidationError,
                        parse_obj_as(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    @contextlib.contextmanager
    def deploy_stream(
        self, version_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> typing.Iterator[HttpResponse[typing.Iterator[DeployStreamEvent]]]:
        """
        SSE endpoint for real-time deployment progress events.

        Parameters
        ----------
        version_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Yields
        ------
        typing.Iterator[HttpResponse[typing.Iterator[DeployStreamEvent]]]
            SSE stream of deployment events
        """
        with self._client_wrapper.httpx_client.stream(
            f"versions/{jsonable_encoder(version_id)}/deploy/events",
            method="GET",
            request_options=request_options,
        ) as _response:

            def _stream() -> HttpResponse[typing.Iterator[DeployStreamEvent]]:
                try:
                    if 200 <= _response.status_code < 300:

                        def _iter():
                            _event_source = EventSource(_response)
                            for _sse in _event_source.iter_sse():
                                if _sse.data == None:
                                    return
                                try:
                                    yield typing.cast(
                                        DeployStreamEvent,
                                        parse_obj_as(
                                            type_=DeployStreamEvent,  # type: ignore
                                            object_=_sse.json(),
                                        ),
                                    )
                                except JSONDecodeError as e:
                                    warning(f"Skipping SSE event with invalid JSON: {e}, sse: {_sse!r}")
                                except (TypeError, ValueError, KeyError, AttributeError) as e:
                                    warning(
                                        f"Skipping SSE event due to model construction error: {type(e).__name__}: {e}, sse: {_sse!r}"
                                    )
                                except Exception as e:
                                    error(
                                        f"Unexpected error processing SSE event: {type(e).__name__}: {e}, sse: {_sse!r}"
                                    )
                            return

                        return HttpResponse(response=_response, data=_iter())
                    _response.read()
                    if _response.status_code == 422:
                        raise UnprocessableEntityError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                HttpValidationError,
                                parse_obj_as(
                                    type_=HttpValidationError,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(
                        status_code=_response.status_code, headers=dict(_response.headers), body=_response.text
                    )
                raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

            yield _stream()

    def metrics(
        self, version_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[VersionMetricsResponse]:
        """
        Get deployment metrics for a specific version.

            Returns metrics related to the deployment process for this version,
            including average and P95 deployment durations queried from ClickHouse traces.

        Parameters
        ----------
        version_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        HttpResponse[VersionMetricsResponse]
            Successful Response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"versions/{jsonable_encoder(version_id)}/metrics",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    VersionMetricsResponse,
                    parse_obj_as(
                        type_=VersionMetricsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        HttpValidationError,
                        parse_obj_as(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)


class AsyncRawVersionsClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def register(
        self,
        *,
        acp_url: str,
        branch_id: str,
        version_id: str,
        registration_token: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[RegisterContainerResponse]:
        """
        Register an agent container that has started up.

            Called by the agent container on startup to:
            1. Register its ACP URL with the platform
            2. Receive its API key for authenticating subsequent requests

            This endpoint should be called from within the container's entrypoint
            after the ACP server is ready to receive traffic.

        Parameters
        ----------
        acp_url : str
            ACP server URL (e.g., 'http://agent-main-abc123.agents.svc.cluster.local:8000')

        branch_id : str
            Branch ID

        version_id : str
            Version ID being registered

        registration_token : typing.Optional[str]
            Single-use registration token provided during deployment (required when configured)

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[RegisterContainerResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            "versions/register",
            method="POST",
            json={
                "acp_url": acp_url,
                "branch_id": branch_id,
                "registration_token": registration_token,
                "version_id": version_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    RegisterContainerResponse,
                    parse_obj_as(
                        type_=RegisterContainerResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        HttpValidationError,
                        parse_obj_as(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    async def retrieve(
        self, version_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[VersionResponse]:
        """
        Get version details by ID.

        Parameters
        ----------
        version_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[VersionResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"versions/{jsonable_encoder(version_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    VersionResponse,
                    parse_obj_as(
                        type_=VersionResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        HttpValidationError,
                        parse_obj_as(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

    @contextlib.asynccontextmanager
    async def deploy_stream(
        self, version_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[DeployStreamEvent]]]:
        """
        SSE endpoint for real-time deployment progress events.

        Parameters
        ----------
        version_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Yields
        ------
        typing.AsyncIterator[AsyncHttpResponse[typing.AsyncIterator[DeployStreamEvent]]]
            SSE stream of deployment events
        """
        async with self._client_wrapper.httpx_client.stream(
            f"versions/{jsonable_encoder(version_id)}/deploy/events",
            method="GET",
            request_options=request_options,
        ) as _response:

            async def _stream() -> AsyncHttpResponse[typing.AsyncIterator[DeployStreamEvent]]:
                try:
                    if 200 <= _response.status_code < 300:

                        async def _iter():
                            _event_source = EventSource(_response)
                            async for _sse in _event_source.aiter_sse():
                                if _sse.data == None:
                                    return
                                try:
                                    yield typing.cast(
                                        DeployStreamEvent,
                                        parse_obj_as(
                                            type_=DeployStreamEvent,  # type: ignore
                                            object_=_sse.json(),
                                        ),
                                    )
                                except JSONDecodeError as e:
                                    warning(f"Skipping SSE event with invalid JSON: {e}, sse: {_sse!r}")
                                except (TypeError, ValueError, KeyError, AttributeError) as e:
                                    warning(
                                        f"Skipping SSE event due to model construction error: {type(e).__name__}: {e}, sse: {_sse!r}"
                                    )
                                except Exception as e:
                                    error(
                                        f"Unexpected error processing SSE event: {type(e).__name__}: {e}, sse: {_sse!r}"
                                    )
                            return

                        return AsyncHttpResponse(response=_response, data=_iter())
                    await _response.aread()
                    if _response.status_code == 422:
                        raise UnprocessableEntityError(
                            headers=dict(_response.headers),
                            body=typing.cast(
                                HttpValidationError,
                                parse_obj_as(
                                    type_=HttpValidationError,  # type: ignore
                                    object_=_response.json(),
                                ),
                            ),
                        )
                    _response_json = _response.json()
                except JSONDecodeError:
                    raise ApiError(
                        status_code=_response.status_code, headers=dict(_response.headers), body=_response.text
                    )
                raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)

            yield await _stream()

    async def metrics(
        self, version_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[VersionMetricsResponse]:
        """
        Get deployment metrics for a specific version.

            Returns metrics related to the deployment process for this version,
            including average and P95 deployment durations queried from ClickHouse traces.

        Parameters
        ----------
        version_id : str

        request_options : typing.Optional[RequestOptions]
            Request-specific configuration.

        Returns
        -------
        AsyncHttpResponse[VersionMetricsResponse]
            Successful Response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"versions/{jsonable_encoder(version_id)}/metrics",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    VersionMetricsResponse,
                    parse_obj_as(
                        type_=VersionMetricsResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 422:
                raise UnprocessableEntityError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        HttpValidationError,
                        parse_obj_as(
                            type_=HttpValidationError,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
        raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
