# 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.request_options import RequestOptions
from ...core.serialization import convert_and_respect_annotation_metadata
from ...core.unchecked_base_model import construct_type
from ..errors.bad_request_error import BadRequestError
from ..errors.not_found_error import NotFoundError
from ..errors.unauthorized_error import UnauthorizedError
from ..jobs.types.jobs import Jobs
from ..types.create_ticket_request_assignment import CreateTicketRequestAssignment
from ..types.create_ticket_request_contacts_item import CreateTicketRequestContactsItem
from ..types.error import Error
from ..types.search_request_query import SearchRequestQuery
from ..types.starting_after_paging import StartingAfterPaging
from ..types.ticket_list import TicketList
from ..types.ticket_reply import TicketReply
from .types.delete_ticket_response import DeleteTicketResponse
from .types.reply_ticket_request_body import ReplyTicketRequestBody
from .types.ticket import Ticket

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


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

    def reply_ticket(
        self, id: str, *, request: ReplyTicketRequestBody, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[TicketReply]:
        """
        You can reply to a ticket with a message from an admin or on behalf of a contact, or with a note for admins.

        Parameters
        ----------
        id : str

        request : ReplyTicketRequestBody

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

        Returns
        -------
        HttpResponse[TicketReply]
            Admin Reply to send Quick Reply Options
        """
        _response = self._client_wrapper.httpx_client.request(
            f"tickets/{jsonable_encoder(id)}/reply",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=ReplyTicketRequestBody, direction="write"
            ),
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TicketReply,
                    construct_type(
                        type_=TicketReply,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # 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 enqueue_create_ticket(
        self,
        *,
        ticket_type_id: str,
        contacts: typing.Sequence[CreateTicketRequestContactsItem],
        skip_notifications: typing.Optional[bool] = OMIT,
        conversation_to_link_id: typing.Optional[str] = OMIT,
        company_id: typing.Optional[str] = OMIT,
        created_at: typing.Optional[int] = OMIT,
        assignment: typing.Optional[CreateTicketRequestAssignment] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[Jobs]:
        """
        Enqueues ticket creation for asynchronous processing, returning if the job was enqueued successfully to be processed. We attempt to perform a best-effort validation on inputs before tasks are enqueued. If the given parameters are incorrect, we won't enqueue the job.

        Parameters
        ----------
        ticket_type_id : str
            The ID of the type of ticket you want to create

        contacts : typing.Sequence[CreateTicketRequestContactsItem]
            The list of contacts (users or leads) affected by this ticket. Currently only one is allowed

        skip_notifications : typing.Optional[bool]
            Option to disable notifications when a Ticket is created.

        conversation_to_link_id : typing.Optional[str]
            The ID of the conversation you want to link to the ticket. Here are the valid ways of linking two tickets:
             - conversation | back-office ticket
             - customer tickets | non-shared back-office ticket
             - conversation | tracker ticket
             - customer ticket | tracker ticket

        company_id : typing.Optional[str]
            The ID of the company that the ticket is associated with. The unique identifier for the company which is given by Intercom

        created_at : typing.Optional[int]
            The time the ticket was created. If not provided, the current time will be used.

        assignment : typing.Optional[CreateTicketRequestAssignment]

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

        Returns
        -------
        HttpResponse[Jobs]
            Successful response
        """
        _response = self._client_wrapper.httpx_client.request(
            "tickets/enqueue",
            method="POST",
            json={
                "skip_notifications": skip_notifications,
                "ticket_type_id": ticket_type_id,
                "contacts": convert_and_respect_annotation_metadata(
                    object_=contacts, annotation=typing.Sequence[CreateTicketRequestContactsItem], direction="write"
                ),
                "conversation_to_link_id": conversation_to_link_id,
                "company_id": company_id,
                "created_at": created_at,
                "assignment": convert_and_respect_annotation_metadata(
                    object_=assignment, annotation=CreateTicketRequestAssignment, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Jobs,
                    construct_type(
                        type_=Jobs,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # 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 get_ticket(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[typing.Optional[Ticket]]:
        """
        You can fetch the details of a single ticket.

        Parameters
        ----------
        id : str
            The unique identifier for the ticket which is given by Intercom.

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

        Returns
        -------
        HttpResponse[typing.Optional[Ticket]]
            Ticket found
        """
        _response = self._client_wrapper.httpx_client.request(
            f"tickets/{jsonable_encoder(id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if _response is None or not _response.text.strip():
                return HttpResponse(response=_response, data=None)
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.Optional[Ticket],
                    construct_type(
                        type_=typing.Optional[Ticket],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # 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 update_ticket(
        self,
        id: str,
        *,
        ticket_attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
        ticket_state_id: typing.Optional[str] = OMIT,
        company_id: typing.Optional[str] = OMIT,
        open: typing.Optional[bool] = OMIT,
        is_shared: typing.Optional[bool] = OMIT,
        snoozed_until: typing.Optional[int] = OMIT,
        admin_id: typing.Optional[int] = OMIT,
        assignee_id: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[typing.Optional[Ticket]]:
        """
        You can update a ticket.

        Parameters
        ----------
        id : str
            The unique identifier for the ticket which is given by Intercom

        ticket_attributes : typing.Optional[typing.Dict[str, typing.Any]]
            The attributes set on the ticket.

        ticket_state_id : typing.Optional[str]
            The ID of the ticket state associated with the ticket type.

        company_id : typing.Optional[str]
            The ID of the company that the ticket is associated with. The unique identifier for the company which is given by Intercom. Set to nil to remove company.

        open : typing.Optional[bool]
            Specify if a ticket is open. Set to false to close a ticket. Closing a ticket will also unsnooze it.

        is_shared : typing.Optional[bool]
            Specify whether the ticket is visible to users.

        snoozed_until : typing.Optional[int]
            The time you want the ticket to reopen.

        admin_id : typing.Optional[int]
            The ID of the admin performing ticket update. Needed for workflows execution and attributing actions to specific admins.

        assignee_id : typing.Optional[str]
            The ID of the admin or team to which the ticket is assigned. Set this 0 to unassign it.

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

        Returns
        -------
        HttpResponse[typing.Optional[Ticket]]
            Successful response
        """
        _response = self._client_wrapper.httpx_client.request(
            f"tickets/{jsonable_encoder(id)}",
            method="PUT",
            json={
                "ticket_attributes": ticket_attributes,
                "ticket_state_id": ticket_state_id,
                "company_id": company_id,
                "open": open,
                "is_shared": is_shared,
                "snoozed_until": snoozed_until,
                "admin_id": admin_id,
                "assignee_id": assignee_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if _response is None or not _response.text.strip():
                return HttpResponse(response=_response, data=None)
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.Optional[Ticket],
                    construct_type(
                        type_=typing.Optional[Ticket],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # 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 delete_ticket(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> HttpResponse[DeleteTicketResponse]:
        """
        You can delete a ticket using the Intercom provided ID.

        Parameters
        ----------
        id : str
            The unique identifier for the ticket which is given by Intercom.

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

        Returns
        -------
        HttpResponse[DeleteTicketResponse]
            successful
        """
        _response = self._client_wrapper.httpx_client.request(
            f"tickets/{jsonable_encoder(id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DeleteTicketResponse,
                    construct_type(
                        type_=DeleteTicketResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return HttpResponse(response=_response, data=_data)
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # 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 search_tickets(
        self,
        *,
        query: SearchRequestQuery,
        pagination: typing.Optional[StartingAfterPaging] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> HttpResponse[TicketList]:
        """
        You can search for multiple tickets by the value of their attributes in order to fetch exactly which ones you want.

        To search for tickets, you send a `POST` request to `https://api.intercom.io/tickets/search`.

        This will accept a query object in the body which will define your filters.
        {% admonition type="warning" name="Optimizing search queries" %}
          Search queries can be complex, so optimizing them can help the performance of your search.
          Use the `AND` and `OR` operators to combine multiple filters to get the exact results you need and utilize
          pagination to limit the number of results returned. The default is `20` results per page.
          See the [pagination section](https://developers.intercom.com/docs/build-an-integration/learn-more/rest-apis/pagination/#example-search-conversations-request) for more details on how to use the `starting_after` param.
        {% /admonition %}

        ### Nesting & Limitations

        You can nest these filters in order to get even more granular insights that pinpoint exactly what you need. Example: (1 OR 2) AND (3 OR 4).
        There are some limitations to the amount of multiples there can be:
        - There's a limit of max 2 nested filters
        - There's a limit of max 15 filters for each AND or OR group

        ### Accepted Fields

        Most keys listed as part of the Ticket model are searchable, whether writeable or not. The value you search for has to match the accepted type, otherwise the query will fail (ie. as `created_at` accepts a date, the `value` cannot be a string such as `"foobar"`).
        The `source.body` field is unique as the search will not be performed against the entire value, but instead against every element of the value separately. For example, when searching for a conversation with a `"I need support"` body - the query should contain a `=` operator with the value `"support"` for such conversation to be returned. A query with a `=` operator and a `"need support"` value will not yield a result.

        | Field                                     | Type                                                                                     |
        | :---------------------------------------- | :--------------------------------------------------------------------------------------- |
        | id                                        | String                                                                                   |
        | created_at                                | Date (UNIX timestamp)                                                                    |
        | updated_at                                | Date (UNIX timestamp)                                                                    |
        | title                           | String                                                                                   |
        | description                     | String                                                                                   |
        | category                                  | String                                                                                   |
        | ticket_type_id                            | String                                                                                   |
        | contact_ids                               | String                                                                                   |
        | teammate_ids                              | String                                                                                   |
        | admin_assignee_id                         | String                                                                                   |
        | team_assignee_id                          | String                                                                                   |
        | open                                      | Boolean                                                                                  |
        | state                                     | String                                                                                   |
        | snoozed_until                             | Date (UNIX timestamp)                                                                    |
        | ticket_attribute.{id}                     | String or Boolean or Date (UNIX timestamp) or Float or Integer                           |

        {% admonition type="info" name="Searching by Category" %}
        When searching for tickets by the **`category`** field, specific terms must be used instead of the category names:
        * For **Customer** category tickets, use the term `request`.
        * For **Back-office** category tickets, use the term `task`.
        * For **Tracker** category tickets, use the term `tracker`.
        {% /admonition %}

        ### Accepted Operators

        {% admonition type="info" name="Searching based on `created_at`" %}
          You may use the `<=` or `>=` operators to search by `created_at`.
        {% /admonition %}

        The table below shows the operators you can use to define how you want to search for the value.  The operator should be put in as a string (`"="`). The operator has to be compatible with the field's type  (eg. you cannot search with `>` for a given string value as it's only compatible for integer's and dates).

        | Operator | Valid Types                    | Description                                                  |
        | :------- | :----------------------------- | :----------------------------------------------------------- |
        | =        | All                            | Equals                                                       |
        | !=       | All                            | Doesn't Equal                                                |
        | IN       | All                            | In  Shortcut for `OR` queries  Values most be in Array       |
        | NIN      | All                            | Not In  Shortcut for `OR !` queries  Values must be in Array |
        | >        | Integer  Date (UNIX Timestamp) | Greater (or equal) than                                      |
        | <       | Integer  Date (UNIX Timestamp) | Lower (or equal) than                                        |
        | ~        | String                         | Contains                                                     |
        | !~       | String                         | Doesn't Contain                                              |
        | ^        | String                         | Starts With                                                  |
        | $        | String                         | Ends With                                                    |

        Parameters
        ----------
        query : SearchRequestQuery

        pagination : typing.Optional[StartingAfterPaging]

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

        Returns
        -------
        HttpResponse[TicketList]
            successful
        """
        _response = self._client_wrapper.httpx_client.request(
            "tickets/search",
            method="POST",
            json={
                "query": convert_and_respect_annotation_metadata(
                    object_=query, annotation=SearchRequestQuery, direction="write"
                ),
                "pagination": convert_and_respect_annotation_metadata(
                    object_=pagination, annotation=StartingAfterPaging, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TicketList,
                    construct_type(
                        type_=TicketList,  # 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 AsyncRawTicketsClient:
    def __init__(self, *, client_wrapper: AsyncClientWrapper):
        self._client_wrapper = client_wrapper

    async def reply_ticket(
        self, id: str, *, request: ReplyTicketRequestBody, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[TicketReply]:
        """
        You can reply to a ticket with a message from an admin or on behalf of a contact, or with a note for admins.

        Parameters
        ----------
        id : str

        request : ReplyTicketRequestBody

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

        Returns
        -------
        AsyncHttpResponse[TicketReply]
            Admin Reply to send Quick Reply Options
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"tickets/{jsonable_encoder(id)}/reply",
            method="POST",
            json=convert_and_respect_annotation_metadata(
                object_=request, annotation=ReplyTicketRequestBody, direction="write"
            ),
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TicketReply,
                    construct_type(
                        type_=TicketReply,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # 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 enqueue_create_ticket(
        self,
        *,
        ticket_type_id: str,
        contacts: typing.Sequence[CreateTicketRequestContactsItem],
        skip_notifications: typing.Optional[bool] = OMIT,
        conversation_to_link_id: typing.Optional[str] = OMIT,
        company_id: typing.Optional[str] = OMIT,
        created_at: typing.Optional[int] = OMIT,
        assignment: typing.Optional[CreateTicketRequestAssignment] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[Jobs]:
        """
        Enqueues ticket creation for asynchronous processing, returning if the job was enqueued successfully to be processed. We attempt to perform a best-effort validation on inputs before tasks are enqueued. If the given parameters are incorrect, we won't enqueue the job.

        Parameters
        ----------
        ticket_type_id : str
            The ID of the type of ticket you want to create

        contacts : typing.Sequence[CreateTicketRequestContactsItem]
            The list of contacts (users or leads) affected by this ticket. Currently only one is allowed

        skip_notifications : typing.Optional[bool]
            Option to disable notifications when a Ticket is created.

        conversation_to_link_id : typing.Optional[str]
            The ID of the conversation you want to link to the ticket. Here are the valid ways of linking two tickets:
             - conversation | back-office ticket
             - customer tickets | non-shared back-office ticket
             - conversation | tracker ticket
             - customer ticket | tracker ticket

        company_id : typing.Optional[str]
            The ID of the company that the ticket is associated with. The unique identifier for the company which is given by Intercom

        created_at : typing.Optional[int]
            The time the ticket was created. If not provided, the current time will be used.

        assignment : typing.Optional[CreateTicketRequestAssignment]

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

        Returns
        -------
        AsyncHttpResponse[Jobs]
            Successful response
        """
        _response = await self._client_wrapper.httpx_client.request(
            "tickets/enqueue",
            method="POST",
            json={
                "skip_notifications": skip_notifications,
                "ticket_type_id": ticket_type_id,
                "contacts": convert_and_respect_annotation_metadata(
                    object_=contacts, annotation=typing.Sequence[CreateTicketRequestContactsItem], direction="write"
                ),
                "conversation_to_link_id": conversation_to_link_id,
                "company_id": company_id,
                "created_at": created_at,
                "assignment": convert_and_respect_annotation_metadata(
                    object_=assignment, annotation=CreateTicketRequestAssignment, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    Jobs,
                    construct_type(
                        type_=Jobs,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # 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 get_ticket(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[typing.Optional[Ticket]]:
        """
        You can fetch the details of a single ticket.

        Parameters
        ----------
        id : str
            The unique identifier for the ticket which is given by Intercom.

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

        Returns
        -------
        AsyncHttpResponse[typing.Optional[Ticket]]
            Ticket found
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"tickets/{jsonable_encoder(id)}",
            method="GET",
            request_options=request_options,
        )
        try:
            if _response is None or not _response.text.strip():
                return AsyncHttpResponse(response=_response, data=None)
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.Optional[Ticket],
                    construct_type(
                        type_=typing.Optional[Ticket],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # 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 update_ticket(
        self,
        id: str,
        *,
        ticket_attributes: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
        ticket_state_id: typing.Optional[str] = OMIT,
        company_id: typing.Optional[str] = OMIT,
        open: typing.Optional[bool] = OMIT,
        is_shared: typing.Optional[bool] = OMIT,
        snoozed_until: typing.Optional[int] = OMIT,
        admin_id: typing.Optional[int] = OMIT,
        assignee_id: typing.Optional[str] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[typing.Optional[Ticket]]:
        """
        You can update a ticket.

        Parameters
        ----------
        id : str
            The unique identifier for the ticket which is given by Intercom

        ticket_attributes : typing.Optional[typing.Dict[str, typing.Any]]
            The attributes set on the ticket.

        ticket_state_id : typing.Optional[str]
            The ID of the ticket state associated with the ticket type.

        company_id : typing.Optional[str]
            The ID of the company that the ticket is associated with. The unique identifier for the company which is given by Intercom. Set to nil to remove company.

        open : typing.Optional[bool]
            Specify if a ticket is open. Set to false to close a ticket. Closing a ticket will also unsnooze it.

        is_shared : typing.Optional[bool]
            Specify whether the ticket is visible to users.

        snoozed_until : typing.Optional[int]
            The time you want the ticket to reopen.

        admin_id : typing.Optional[int]
            The ID of the admin performing ticket update. Needed for workflows execution and attributing actions to specific admins.

        assignee_id : typing.Optional[str]
            The ID of the admin or team to which the ticket is assigned. Set this 0 to unassign it.

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

        Returns
        -------
        AsyncHttpResponse[typing.Optional[Ticket]]
            Successful response
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"tickets/{jsonable_encoder(id)}",
            method="PUT",
            json={
                "ticket_attributes": ticket_attributes,
                "ticket_state_id": ticket_state_id,
                "company_id": company_id,
                "open": open,
                "is_shared": is_shared,
                "snoozed_until": snoozed_until,
                "admin_id": admin_id,
                "assignee_id": assignee_id,
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if _response is None or not _response.text.strip():
                return AsyncHttpResponse(response=_response, data=None)
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    typing.Optional[Ticket],
                    construct_type(
                        type_=typing.Optional[Ticket],  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 400:
                raise BadRequestError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # 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 delete_ticket(
        self, id: str, *, request_options: typing.Optional[RequestOptions] = None
    ) -> AsyncHttpResponse[DeleteTicketResponse]:
        """
        You can delete a ticket using the Intercom provided ID.

        Parameters
        ----------
        id : str
            The unique identifier for the ticket which is given by Intercom.

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

        Returns
        -------
        AsyncHttpResponse[DeleteTicketResponse]
            successful
        """
        _response = await self._client_wrapper.httpx_client.request(
            f"tickets/{jsonable_encoder(id)}",
            method="DELETE",
            request_options=request_options,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    DeleteTicketResponse,
                    construct_type(
                        type_=DeleteTicketResponse,  # type: ignore
                        object_=_response.json(),
                    ),
                )
                return AsyncHttpResponse(response=_response, data=_data)
            if _response.status_code == 401:
                raise UnauthorizedError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        Error,
                        construct_type(
                            type_=Error,  # type: ignore
                            object_=_response.json(),
                        ),
                    ),
                )
            if _response.status_code == 404:
                raise NotFoundError(
                    headers=dict(_response.headers),
                    body=typing.cast(
                        typing.Any,
                        construct_type(
                            type_=typing.Any,  # 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 search_tickets(
        self,
        *,
        query: SearchRequestQuery,
        pagination: typing.Optional[StartingAfterPaging] = OMIT,
        request_options: typing.Optional[RequestOptions] = None,
    ) -> AsyncHttpResponse[TicketList]:
        """
        You can search for multiple tickets by the value of their attributes in order to fetch exactly which ones you want.

        To search for tickets, you send a `POST` request to `https://api.intercom.io/tickets/search`.

        This will accept a query object in the body which will define your filters.
        {% admonition type="warning" name="Optimizing search queries" %}
          Search queries can be complex, so optimizing them can help the performance of your search.
          Use the `AND` and `OR` operators to combine multiple filters to get the exact results you need and utilize
          pagination to limit the number of results returned. The default is `20` results per page.
          See the [pagination section](https://developers.intercom.com/docs/build-an-integration/learn-more/rest-apis/pagination/#example-search-conversations-request) for more details on how to use the `starting_after` param.
        {% /admonition %}

        ### Nesting & Limitations

        You can nest these filters in order to get even more granular insights that pinpoint exactly what you need. Example: (1 OR 2) AND (3 OR 4).
        There are some limitations to the amount of multiples there can be:
        - There's a limit of max 2 nested filters
        - There's a limit of max 15 filters for each AND or OR group

        ### Accepted Fields

        Most keys listed as part of the Ticket model are searchable, whether writeable or not. The value you search for has to match the accepted type, otherwise the query will fail (ie. as `created_at` accepts a date, the `value` cannot be a string such as `"foobar"`).
        The `source.body` field is unique as the search will not be performed against the entire value, but instead against every element of the value separately. For example, when searching for a conversation with a `"I need support"` body - the query should contain a `=` operator with the value `"support"` for such conversation to be returned. A query with a `=` operator and a `"need support"` value will not yield a result.

        | Field                                     | Type                                                                                     |
        | :---------------------------------------- | :--------------------------------------------------------------------------------------- |
        | id                                        | String                                                                                   |
        | created_at                                | Date (UNIX timestamp)                                                                    |
        | updated_at                                | Date (UNIX timestamp)                                                                    |
        | title                           | String                                                                                   |
        | description                     | String                                                                                   |
        | category                                  | String                                                                                   |
        | ticket_type_id                            | String                                                                                   |
        | contact_ids                               | String                                                                                   |
        | teammate_ids                              | String                                                                                   |
        | admin_assignee_id                         | String                                                                                   |
        | team_assignee_id                          | String                                                                                   |
        | open                                      | Boolean                                                                                  |
        | state                                     | String                                                                                   |
        | snoozed_until                             | Date (UNIX timestamp)                                                                    |
        | ticket_attribute.{id}                     | String or Boolean or Date (UNIX timestamp) or Float or Integer                           |

        {% admonition type="info" name="Searching by Category" %}
        When searching for tickets by the **`category`** field, specific terms must be used instead of the category names:
        * For **Customer** category tickets, use the term `request`.
        * For **Back-office** category tickets, use the term `task`.
        * For **Tracker** category tickets, use the term `tracker`.
        {% /admonition %}

        ### Accepted Operators

        {% admonition type="info" name="Searching based on `created_at`" %}
          You may use the `<=` or `>=` operators to search by `created_at`.
        {% /admonition %}

        The table below shows the operators you can use to define how you want to search for the value.  The operator should be put in as a string (`"="`). The operator has to be compatible with the field's type  (eg. you cannot search with `>` for a given string value as it's only compatible for integer's and dates).

        | Operator | Valid Types                    | Description                                                  |
        | :------- | :----------------------------- | :----------------------------------------------------------- |
        | =        | All                            | Equals                                                       |
        | !=       | All                            | Doesn't Equal                                                |
        | IN       | All                            | In  Shortcut for `OR` queries  Values most be in Array       |
        | NIN      | All                            | Not In  Shortcut for `OR !` queries  Values must be in Array |
        | >        | Integer  Date (UNIX Timestamp) | Greater (or equal) than                                      |
        | <       | Integer  Date (UNIX Timestamp) | Lower (or equal) than                                        |
        | ~        | String                         | Contains                                                     |
        | !~       | String                         | Doesn't Contain                                              |
        | ^        | String                         | Starts With                                                  |
        | $        | String                         | Ends With                                                    |

        Parameters
        ----------
        query : SearchRequestQuery

        pagination : typing.Optional[StartingAfterPaging]

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

        Returns
        -------
        AsyncHttpResponse[TicketList]
            successful
        """
        _response = await self._client_wrapper.httpx_client.request(
            "tickets/search",
            method="POST",
            json={
                "query": convert_and_respect_annotation_metadata(
                    object_=query, annotation=SearchRequestQuery, direction="write"
                ),
                "pagination": convert_and_respect_annotation_metadata(
                    object_=pagination, annotation=StartingAfterPaging, direction="write"
                ),
            },
            headers={
                "content-type": "application/json",
            },
            request_options=request_options,
            omit=OMIT,
        )
        try:
            if 200 <= _response.status_code < 300:
                _data = typing.cast(
                    TicketList,
                    construct_type(
                        type_=TicketList,  # 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)
