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

import typing
import urllib.parse
from json.decoder import JSONDecodeError

from ..commons.errors.server_error import ServerError
from ..commons.errors.unauthorized_error import UnauthorizedError
from ..commons.types.custom_tool import CustomTool
from ..commons.types.error_body import ErrorBody
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.jsonable_encoder import jsonable_encoder
from ..core.pydantic_utilities import pydantic_v1
from ..core.remove_none_from_dict import remove_none_from_dict
from ..core.request_options import RequestOptions
from .types.create_web_agent_response import CreateWebAgentResponse

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


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

    def create(
        self,
        *,
        prompt: str,
        voice: typing.Optional[str] = OMIT,
        analysis_schema: typing.Optional[typing.Any] = OMIT,
        metadata: typing.Optional[typing.Any] = OMIT,
        pathway_id: typing.Optional[str] = OMIT,
        language: typing.Optional[str] = OMIT,
        model: typing.Optional[str] = OMIT,
        first_sentence: typing.Optional[str] = OMIT,
        tools: typing.Optional[typing.Sequence[CustomTool]] = OMIT,
        dynamic_data: typing.Optional[typing.Any] = OMIT,
        interruption_threshold: typing.Optional[int] = OMIT,
        max_duration: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> CreateWebAgentResponse:
        """
        Configure all of the settings for a new web agent.

        Parameters
        ----------
        prompt : str
            Provide instructions, relevant information, and examples of the ideal conversation flow.

        voice : typing.Optional[str]
            Set your agent's voice - all available voices can be found with the [List Voices](https://docs.bland.ai/api-v1/get/voices) endpoint.

        analysis_schema : typing.Optional[typing.Any]
            Define a JSON schema for how you want to get information about the call - information like email addresses, names, appointment times or any other type of custom data.

            In the webhook response or whenever you retrieve call data later, you’ll get the data you defined back under analysis.

        metadata : typing.Optional[typing.Any]
            Add any additional information you want to associate with the call. This can be useful for tracking or categorizing calls.

        pathway_id : typing.Optional[str]
            Set the pathway that your agent will follow. This will override the prompt field, so there is no need to pass the ‘prompt’ field if you are setting a pathway.

            Warning: Setting a pathway will set the following fields to null / their default value - prompt, first_sentence, model, dynamic_data, tools

            Set to null or an empty string to clear the pathway.

        language : typing.Optional[str]
            Select a supported language of your choice. Optimizes every part of our API for that language - transcription, speech, and other inner workings.

            Supported Languages and their codes:

            English: ENG
            Spanish: ESP
            French: FRE
            Polish: POL
            German: GER
            Italian: ITA
            Brazilian Portuguese: PBR
            Portuguese: POR

        model : typing.Optional[str]
            Select a model to use for your call.

            Options: base, turbo and enhanced.

            In nearly all cases, enhanced is the best choice for now.

        first_sentence : typing.Optional[str]
            A phrase that your call will start with instead of a generating one on the fly. This works both with and without wait_for_greeting. Can be more than one sentence, but must be less than 200 characters.

            To remove, set to null or an empty string.

        tools : typing.Optional[typing.Sequence[CustomTool]]
            Interact with the real world through API calls.

            Detailed tutorial here: [Custom Tools](https://docs.bland.ai/tutorials/custom-tools)

        dynamic_data : typing.Optional[typing.Any]
            Integrate data from external APIs into your agent’s knowledge.

            Set to null or an empty string to clear dynamic data settings.

            Detailed usage in the [Send Call](https://docs.bland.ai/api-v1/post/calls) endpoint.

        interruption_threshold : typing.Optional[int]
            When you increase the interruption latency, you force the AI phone agent to listen longer before responding. In practice, increasing the threshold results in less interruptions and more latency.

            Try setting the threshold to 500 milliseconds. You’ll encounter higher latency, but you’ll be interrupted less frequently.

            Set to null to reset to default.

        max_duration : typing.Optional[int]
            Set the maximum duration of the call in seconds. The call will be automatically disconnected after this time.

            Set to null to reset to default.

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

        Returns
        -------
        CreateWebAgentResponse

        Examples
        --------
        from bland import CustomTool
        from bland.client import BlandAI

        client = BlandAI(
            api_key="YOUR_API_KEY",
        )
        client.web_agents.create(
            prompt="string",
            voice="string",
            analysis_schema={"key": "value"},
            metadata={"key": "value"},
            pathway_id="string",
            language="string",
            model="string",
            first_sentence="string",
            tools=[
                CustomTool(
                    name="string",
                    description="string",
                    input_schema={"key": "value"},
                    speech="string",
                    response_data=[{"key": "value"}],
                )
            ],
            dynamic_data={"key": "value"},
            interruption_threshold=1,
            max_duration=1,
        )
        """
        _request: typing.Dict[str, typing.Any] = {"prompt": prompt}
        if voice is not OMIT:
            _request["voice"] = voice
        if analysis_schema is not OMIT:
            _request["analysis_schema"] = analysis_schema
        if metadata is not OMIT:
            _request["metadata"] = metadata
        if pathway_id is not OMIT:
            _request["pathway_id"] = pathway_id
        if language is not OMIT:
            _request["language"] = language
        if model is not OMIT:
            _request["model"] = model
        if first_sentence is not OMIT:
            _request["first_sentence"] = first_sentence
        if tools is not OMIT:
            _request["tools"] = tools
        if dynamic_data is not OMIT:
            _request["dynamic_data"] = dynamic_data
        if interruption_threshold is not OMIT:
            _request["interruption_threshold"] = interruption_threshold
        if max_duration is not OMIT:
            _request["max_duration"] = max_duration
        _response = self._client_wrapper.httpx_client.request(
            method="POST",
            url=urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v1/agents/agents"),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            json=jsonable_encoder(_request)
            if request_options is None or request_options.get("additional_body_parameters") is None
            else {
                **jsonable_encoder(_request),
                **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
            },
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(CreateWebAgentResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)


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

    async def create(
        self,
        *,
        prompt: str,
        voice: typing.Optional[str] = OMIT,
        analysis_schema: typing.Optional[typing.Any] = OMIT,
        metadata: typing.Optional[typing.Any] = OMIT,
        pathway_id: typing.Optional[str] = OMIT,
        language: typing.Optional[str] = OMIT,
        model: typing.Optional[str] = OMIT,
        first_sentence: typing.Optional[str] = OMIT,
        tools: typing.Optional[typing.Sequence[CustomTool]] = OMIT,
        dynamic_data: typing.Optional[typing.Any] = OMIT,
        interruption_threshold: typing.Optional[int] = OMIT,
        max_duration: typing.Optional[int] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> CreateWebAgentResponse:
        """
        Configure all of the settings for a new web agent.

        Parameters
        ----------
        prompt : str
            Provide instructions, relevant information, and examples of the ideal conversation flow.

        voice : typing.Optional[str]
            Set your agent's voice - all available voices can be found with the [List Voices](https://docs.bland.ai/api-v1/get/voices) endpoint.

        analysis_schema : typing.Optional[typing.Any]
            Define a JSON schema for how you want to get information about the call - information like email addresses, names, appointment times or any other type of custom data.

            In the webhook response or whenever you retrieve call data later, you’ll get the data you defined back under analysis.

        metadata : typing.Optional[typing.Any]
            Add any additional information you want to associate with the call. This can be useful for tracking or categorizing calls.

        pathway_id : typing.Optional[str]
            Set the pathway that your agent will follow. This will override the prompt field, so there is no need to pass the ‘prompt’ field if you are setting a pathway.

            Warning: Setting a pathway will set the following fields to null / their default value - prompt, first_sentence, model, dynamic_data, tools

            Set to null or an empty string to clear the pathway.

        language : typing.Optional[str]
            Select a supported language of your choice. Optimizes every part of our API for that language - transcription, speech, and other inner workings.

            Supported Languages and their codes:

            English: ENG
            Spanish: ESP
            French: FRE
            Polish: POL
            German: GER
            Italian: ITA
            Brazilian Portuguese: PBR
            Portuguese: POR

        model : typing.Optional[str]
            Select a model to use for your call.

            Options: base, turbo and enhanced.

            In nearly all cases, enhanced is the best choice for now.

        first_sentence : typing.Optional[str]
            A phrase that your call will start with instead of a generating one on the fly. This works both with and without wait_for_greeting. Can be more than one sentence, but must be less than 200 characters.

            To remove, set to null or an empty string.

        tools : typing.Optional[typing.Sequence[CustomTool]]
            Interact with the real world through API calls.

            Detailed tutorial here: [Custom Tools](https://docs.bland.ai/tutorials/custom-tools)

        dynamic_data : typing.Optional[typing.Any]
            Integrate data from external APIs into your agent’s knowledge.

            Set to null or an empty string to clear dynamic data settings.

            Detailed usage in the [Send Call](https://docs.bland.ai/api-v1/post/calls) endpoint.

        interruption_threshold : typing.Optional[int]
            When you increase the interruption latency, you force the AI phone agent to listen longer before responding. In practice, increasing the threshold results in less interruptions and more latency.

            Try setting the threshold to 500 milliseconds. You’ll encounter higher latency, but you’ll be interrupted less frequently.

            Set to null to reset to default.

        max_duration : typing.Optional[int]
            Set the maximum duration of the call in seconds. The call will be automatically disconnected after this time.

            Set to null to reset to default.

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

        Returns
        -------
        CreateWebAgentResponse

        Examples
        --------
        from bland import CustomTool
        from bland.client import AsyncBlandAI

        client = AsyncBlandAI(
            api_key="YOUR_API_KEY",
        )
        await client.web_agents.create(
            prompt="string",
            voice="string",
            analysis_schema={"key": "value"},
            metadata={"key": "value"},
            pathway_id="string",
            language="string",
            model="string",
            first_sentence="string",
            tools=[
                CustomTool(
                    name="string",
                    description="string",
                    input_schema={"key": "value"},
                    speech="string",
                    response_data=[{"key": "value"}],
                )
            ],
            dynamic_data={"key": "value"},
            interruption_threshold=1,
            max_duration=1,
        )
        """
        _request: typing.Dict[str, typing.Any] = {"prompt": prompt}
        if voice is not OMIT:
            _request["voice"] = voice
        if analysis_schema is not OMIT:
            _request["analysis_schema"] = analysis_schema
        if metadata is not OMIT:
            _request["metadata"] = metadata
        if pathway_id is not OMIT:
            _request["pathway_id"] = pathway_id
        if language is not OMIT:
            _request["language"] = language
        if model is not OMIT:
            _request["model"] = model
        if first_sentence is not OMIT:
            _request["first_sentence"] = first_sentence
        if tools is not OMIT:
            _request["tools"] = tools
        if dynamic_data is not OMIT:
            _request["dynamic_data"] = dynamic_data
        if interruption_threshold is not OMIT:
            _request["interruption_threshold"] = interruption_threshold
        if max_duration is not OMIT:
            _request["max_duration"] = max_duration
        _response = await self._client_wrapper.httpx_client.request(
            method="POST",
            url=urllib.parse.urljoin(f"{self._client_wrapper.get_base_url()}/", "v1/agents/agents"),
            params=jsonable_encoder(
                request_options.get("additional_query_parameters") if request_options is not None else None
            ),
            json=jsonable_encoder(_request)
            if request_options is None or request_options.get("additional_body_parameters") is None
            else {
                **jsonable_encoder(_request),
                **(jsonable_encoder(remove_none_from_dict(request_options.get("additional_body_parameters", {})))),
            },
            headers=jsonable_encoder(
                remove_none_from_dict(
                    {
                        **self._client_wrapper.get_headers(),
                        **(request_options.get("additional_headers", {}) if request_options is not None else {}),
                    }
                )
            ),
            timeout=request_options.get("timeout_in_seconds")
            if request_options is not None and request_options.get("timeout_in_seconds") is not None
            else self._client_wrapper.get_timeout(),
            retries=0,
            max_retries=request_options.get("max_retries") if request_options is not None else 0,  # type: ignore
        )
        if 200 <= _response.status_code < 300:
            return pydantic_v1.parse_obj_as(CreateWebAgentResponse, _response.json())  # type: ignore
        if _response.status_code == 500:
            raise ServerError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        if _response.status_code == 401:
            raise UnauthorizedError(pydantic_v1.parse_obj_as(ErrorBody, _response.json()))  # type: ignore
        try:
            _response_json = _response.json()
        except JSONDecodeError:
            raise ApiError(status_code=_response.status_code, body=_response.text)
        raise ApiError(status_code=_response.status_code, body=_response_json)
