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

import typing
from json.decoder import JSONDecodeError

from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
from ..core.jsonable_encoder import jsonable_encoder
from ..core.pagination import AsyncPager, SyncPager
from ..core.request_options import RequestOptions
from ..core.serialization import convert_and_respect_annotation_metadata
from ..core.unchecked_base_model import construct_type
from .types.call_telephony_request_properties import CallTelephonyRequestProperties
from .types.call_telephony_request_sip import CallTelephonyRequestSip
from .types.call_telephony_response import CallTelephonyResponse
from .types.get_telephony_response import GetTelephonyResponse
from .types.hangup_telephony_response import HangupTelephonyResponse
from .types.list_telephony_request_type import ListTelephonyRequestType
from .types.list_telephony_response import ListTelephonyResponse
from .types.list_telephony_response_data_list_item import ListTelephonyResponseDataListItem

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


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

    def list(
        self,
        appid: str,
        *,
        number: typing.Optional[str] = None,
        from_time: typing.Optional[int] = None,
        to_time: typing.Optional[int] = None,
        type: typing.Optional[ListTelephonyRequestType] = None,
        limit: typing.Optional[int] = None,
        cursor: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> SyncPager[ListTelephonyResponseDataListItem, ListTelephonyResponse]:
        """
        Query historical call records for a specified appid based on the filter criteria.

        Parameters
        ----------
        appid : str
            The App ID of the project.

        number : typing.Optional[str]
            Filter by phone number. Can be either the calling number or the called number.

        from_time : typing.Optional[int]
            Query list start timestamp (in seconds). Default is 60 days ago.

        to_time : typing.Optional[int]
            Query list end timestamp (in seconds). Default is current time.

        type : typing.Optional[ListTelephonyRequestType]
            Call type filter:
            - `inbound`: Inbound call.
            - `outbound`: Outbound call.

            If not specified, all call types are returned.

        limit : typing.Optional[int]
            Maximum number of items returned in a single page.

        cursor : typing.Optional[str]
            Pagination cursor. Use the `agent_id` from the previous page as the cursor for the next page.

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

        Returns
        -------
        SyncPager[ListTelephonyResponseDataListItem, ListTelephonyResponse]
            Request was successful. The response body contains the result of the request.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/projects/{jsonable_encoder(appid)}/call",
            method="GET",
            params={
                "number": number,
                "from_time": from_time,
                "to_time": to_time,
                "type": type,
                "limit": limit,
                "cursor": cursor,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListTelephonyResponse,
                    construct_type(
                        type_=ListTelephonyResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.data.list_ if _parsed_response.data is not None else []

                _has_next = False
                _get_next = None
                if _parsed_response.meta is not None:
                    _parsed_next = _parsed_response.meta.cursor
                    _has_next = _parsed_next is not None and _parsed_next != ""
                    _get_next = lambda: self.list(
                        appid,
                        number=number,
                        from_time=from_time,
                        to_time=to_time,
                        type=type,
                        limit=limit,
                        cursor=_parsed_next,
                        request_options=request_options,
                    )
                return SyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response)
            _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 call(
        self,
        appid: str,
        *,
        name: str,
        sip: CallTelephonyRequestSip,
        properties: CallTelephonyRequestProperties,
        pipeline_id: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[CallTelephonyResponse]:
        """
        Initiate an outbound call to a specified number and create an agent to join the specified RTC channel.

        Use this endpoint to initiate an outbound call to the specified number and create an agent that joins the target RTC channel. The agent waits for the callee to answer.

        Parameters
        ----------
        appid : str
            The App ID of the project.

        name : str
            The name identifier of the call session.

        sip : CallTelephonyRequestSip
            SIP (Session Initiation Protocol) call configuration object.

        properties : CallTelephonyRequestProperties
            Call attribute configuration. The content of this field varies depending on the invocation method:
            - **Using pipeline ID**: Simply pass in `channel`, `token`, `agent_rtc_uid`, and `remote_rtc_uids`.
            - **Using complete configuration**: Pass in the complete parameters of the [Start a conversational AI agent](https://docs.agora.io/en/conversational-ai/rest-api/agent/join) `properties`, including all required fields such as `channel`, `token`, `agent_rtc_uid`, `remote_rtc_uids`, `tts`, and `llm`.

        pipeline_id : typing.Optional[str]
            The unique ID of a published project in AI Studio.

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

        Returns
        -------
        HttpResponse[CallTelephonyResponse]
            Request was successful. The response body contains the result of the request.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/projects/{jsonable_encoder(appid)}/call",
            method="POST",
            json={
                "name": name,
                "sip": convert_and_respect_annotation_metadata(
                    object_=sip, annotation=CallTelephonyRequestSip, direction="write"
                ),
                "pipeline_id": pipeline_id,
                "properties": convert_and_respect_annotation_metadata(
                    object_=properties, annotation=CallTelephonyRequestProperties, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CallTelephonyResponse,
                    construct_type(
                        type_=CallTelephonyResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 get(
        self, appid: str, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[GetTelephonyResponse]:
        """
        Retrieve the call status and related information of a specified agent.

        Parameters
        ----------
        appid : str
            The App ID of the project.

        agent_id : str
            The agent ID you obtained after successfully calling the API to initiate an outbound call.

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

        Returns
        -------
        HttpResponse[GetTelephonyResponse]
            Request was successful. The response body contains the result of the request.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/projects/{jsonable_encoder(appid)}/calls/{jsonable_encoder(agent_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    GetTelephonyResponse,
                    construct_type(
                        type_=GetTelephonyResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 hangup(
        self, appid: str, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[HangupTelephonyResponse]:
        """
        Instruct the agent to proactively hang up the ongoing call and leave the RTC channel.

        Parameters
        ----------
        appid : str
            The App ID of the project.

        agent_id : str
            The agent ID you obtained after successfully calling the API to initiate an outbound call.

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

        Returns
        -------
        HttpResponse[HangupTelephonyResponse]
            Request was successful. The response body is empty.
        """
        _response = self._client_wrapper.httpx_client.request(
            f"v2/projects/{jsonable_encoder(appid)}/calls/{jsonable_encoder(agent_id)}/hangup",
            method="POST",
            json={},
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    HangupTelephonyResponse,
                    construct_type(
                        type_=HangupTelephonyResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            _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 AsyncRawTelephonyClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def list(
        self,
        appid: str,
        *,
        number: typing.Optional[str] = None,
        from_time: typing.Optional[int] = None,
        to_time: typing.Optional[int] = None,
        type: typing.Optional[ListTelephonyRequestType] = None,
        limit: typing.Optional[int] = None,
        cursor: typing.Optional[str] = None,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncPager[ListTelephonyResponseDataListItem, ListTelephonyResponse]:
        """
        Query historical call records for a specified appid based on the filter criteria.

        Parameters
        ----------
        appid : str
            The App ID of the project.

        number : typing.Optional[str]
            Filter by phone number. Can be either the calling number or the called number.

        from_time : typing.Optional[int]
            Query list start timestamp (in seconds). Default is 60 days ago.

        to_time : typing.Optional[int]
            Query list end timestamp (in seconds). Default is current time.

        type : typing.Optional[ListTelephonyRequestType]
            Call type filter:
            - `inbound`: Inbound call.
            - `outbound`: Outbound call.

            If not specified, all call types are returned.

        limit : typing.Optional[int]
            Maximum number of items returned in a single page.

        cursor : typing.Optional[str]
            Pagination cursor. Use the `agent_id` from the previous page as the cursor for the next page.

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

        Returns
        -------
        AsyncPager[ListTelephonyResponseDataListItem, ListTelephonyResponse]
            Request was successful. The response body contains the result of the request.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/projects/{jsonable_encoder(appid)}/call",
            method="GET",
            params={
                "number": number,
                "from_time": from_time,
                "to_time": to_time,
                "type": type,
                "limit": limit,
                "cursor": cursor,
            },
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _parsed_response = typing.cast(
                    ListTelephonyResponse,
                    construct_type(
                        type_=ListTelephonyResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                _items = _parsed_response.data.list_ if _parsed_response.data is not None else []

                _has_next = False
                _get_next = None
                if _parsed_response.meta is not None:
                    _parsed_next = _parsed_response.meta.cursor
                    _has_next = _parsed_next is not None and _parsed_next != ""

                    async def _get_next():
                        return await self.list(
                            appid,
                            number=number,
                            from_time=from_time,
                            to_time=to_time,
                            type=type,
                            limit=limit,
                            cursor=_parsed_next,
                            request_options=request_options,
                        )

                return AsyncPager(has_next=_has_next, items=_items, get_next=_get_next, response=_parsed_response)
            _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 call(
        self,
        appid: str,
        *,
        name: str,
        sip: CallTelephonyRequestSip,
        properties: CallTelephonyRequestProperties,
        pipeline_id: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[CallTelephonyResponse]:
        """
        Initiate an outbound call to a specified number and create an agent to join the specified RTC channel.

        Use this endpoint to initiate an outbound call to the specified number and create an agent that joins the target RTC channel. The agent waits for the callee to answer.

        Parameters
        ----------
        appid : str
            The App ID of the project.

        name : str
            The name identifier of the call session.

        sip : CallTelephonyRequestSip
            SIP (Session Initiation Protocol) call configuration object.

        properties : CallTelephonyRequestProperties
            Call attribute configuration. The content of this field varies depending on the invocation method:
            - **Using pipeline ID**: Simply pass in `channel`, `token`, `agent_rtc_uid`, and `remote_rtc_uids`.
            - **Using complete configuration**: Pass in the complete parameters of the [Start a conversational AI agent](https://docs.agora.io/en/conversational-ai/rest-api/agent/join) `properties`, including all required fields such as `channel`, `token`, `agent_rtc_uid`, `remote_rtc_uids`, `tts`, and `llm`.

        pipeline_id : typing.Optional[str]
            The unique ID of a published project in AI Studio.

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

        Returns
        -------
        AsyncHttpResponse[CallTelephonyResponse]
            Request was successful. The response body contains the result of the request.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/projects/{jsonable_encoder(appid)}/call",
            method="POST",
            json={
                "name": name,
                "sip": convert_and_respect_annotation_metadata(
                    object_=sip, annotation=CallTelephonyRequestSip, direction="write"
                ),
                "pipeline_id": pipeline_id,
                "properties": convert_and_respect_annotation_metadata(
                    object_=properties, annotation=CallTelephonyRequestProperties, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    CallTelephonyResponse,
                    construct_type(
                        type_=CallTelephonyResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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 get(
        self, appid: str, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[GetTelephonyResponse]:
        """
        Retrieve the call status and related information of a specified agent.

        Parameters
        ----------
        appid : str
            The App ID of the project.

        agent_id : str
            The agent ID you obtained after successfully calling the API to initiate an outbound call.

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

        Returns
        -------
        AsyncHttpResponse[GetTelephonyResponse]
            Request was successful. The response body contains the result of the request.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/projects/{jsonable_encoder(appid)}/calls/{jsonable_encoder(agent_id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    GetTelephonyResponse,
                    construct_type(
                        type_=GetTelephonyResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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 hangup(
        self, appid: str, agent_id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[HangupTelephonyResponse]:
        """
        Instruct the agent to proactively hang up the ongoing call and leave the RTC channel.

        Parameters
        ----------
        appid : str
            The App ID of the project.

        agent_id : str
            The agent ID you obtained after successfully calling the API to initiate an outbound call.

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

        Returns
        -------
        AsyncHttpResponse[HangupTelephonyResponse]
            Request was successful. The response body is empty.
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"v2/projects/{jsonable_encoder(appid)}/calls/{jsonable_encoder(agent_id)}/hangup",
            method="POST",
            json={},
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    HangupTelephonyResponse,
                    construct_type(
                        type_=HangupTelephonyResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            _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)
