# pylint: disable=too-many-lines
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------
import sys
from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload

from azure.core.exceptions import (
    ClientAuthenticationError,
    HttpResponseError,
    ResourceExistsError,
    ResourceNotFoundError,
    map_error,
)
from azure.core.pipeline import PipelineResponse
from azure.core.pipeline.transport import AsyncHttpResponse
from azure.core.polling import AsyncLROPoller, AsyncNoPolling, AsyncPollingMethod
from azure.core.polling.async_base_polling import AsyncLROBasePolling
from azure.core.rest import HttpRequest
from azure.core.tracing.decorator_async import distributed_trace_async
from azure.core.utils import case_insensitive_dict

from ...operations._operations import build_email_get_send_result_request, build_email_send_request

if sys.version_info >= (3, 9):
    from collections.abc import MutableMapping
else:
    from typing import MutableMapping  # type: ignore  # pylint: disable=ungrouped-imports
JSON = MutableMapping[str, Any]  # pylint: disable=unsubscriptable-object
T = TypeVar("T")
ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]]


class EmailOperations:
    """
    .. warning::
        **DO NOT** instantiate this class directly.

        Instead, you should access the following operations through
        :class:`~azure.communication.email.aio.AzureCommunicationEmailService`'s
        :attr:`email` attribute.
    """

    def __init__(self, *args, **kwargs) -> None:
        input_args = list(args)
        self._client = input_args.pop(0) if input_args else kwargs.pop("client")
        self._config = input_args.pop(0) if input_args else kwargs.pop("config")
        self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer")
        self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer")

    @distributed_trace_async
    async def get_send_result(self, operation_id: str, **kwargs: Any) -> JSON:
        """Gets the status of the email send operation.

        Gets the status of the email send operation.

        :param operation_id: ID of the long running operation (GUID) returned from a previous call to
         send email. Required.
        :type operation_id: str
        :return: JSON object
        :rtype: JSON
        :raises ~azure.core.exceptions.HttpResponseError:

        Example:
            .. code-block:: python

                # response body for status code(s): 200
                response == {
                    "id": "str",  # The unique id of the operation. Use a UUID. Required.
                    "status": "str",  # Status of operation. Required. Known values are:
                      "NotStarted", "Running", "Succeeded", "Failed", and "Canceled".
                    "error": {
                        "additionalInfo": [
                            {
                                "info": {},  # Optional. The additional info.
                                "type": "str"  # Optional. The additional info type.
                            }
                        ],
                        "code": "str",  # Optional. The error code.
                        "details": [
                            ...
                        ],
                        "message": "str",  # Optional. The error message.
                        "target": "str"  # Optional. The error target.
                    }
                }
        """
        error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError}
        error_map.update(kwargs.pop("error_map", {}) or {})

        _headers = kwargs.pop("headers", {}) or {}
        _params = kwargs.pop("params", {}) or {}

        cls = kwargs.pop("cls", None)  # type: ClsType[JSON]

        request = build_email_get_send_result_request(
            operation_id=operation_id,
            api_version=self._config.api_version,
            headers=_headers,
            params=_params,
        )
        path_format_arguments = {
            "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True),
        }
        request.url = self._client.format_url(request.url, **path_format_arguments)  # type: ignore

        pipeline_response = await self._client._pipeline.run(  # type: ignore # pylint: disable=protected-access
            request, stream=False, **kwargs
        )

        response = pipeline_response.http_response

        if response.status_code not in [200]:
            map_error(status_code=response.status_code, response=response, error_map=error_map)
            raise HttpResponseError(response=response)

        response_headers = {}
        response_headers["retry-after"] = self._deserialize("int", response.headers.get("retry-after"))

        if response.content:
            deserialized = response.json()
        else:
            deserialized = None

        if cls:
            return cls(pipeline_response, cast(JSON, deserialized), response_headers)

        return cast(JSON, deserialized)

    async def _send_initial(
        self,
        message: Union[JSON, IO],
        *,
        operation_id: Optional[str] = None,
        client_request_id: Optional[str] = None,
        **kwargs: Any
    ) -> JSON:
        error_map = {401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError}
        error_map.update(kwargs.pop("error_map", {}) or {})

        _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {})
        _params = kwargs.pop("params", {}) or {}

        content_type = kwargs.pop("content_type", _headers.pop("Content-Type", None))  # type: Optional[str]
        cls = kwargs.pop("cls", None)  # type: ClsType[JSON]

        content_type = content_type or "application/json"
        _json = None
        _content = None
        if isinstance(message, (IO, bytes)):
            _content = message
        else:
            _json = message

        request = build_email_send_request(
            operation_id=operation_id,
            client_request_id=client_request_id,
            content_type=content_type,
            api_version=self._config.api_version,
            json=_json,
            content=_content,
            headers=_headers,
            params=_params,
        )
        path_format_arguments = {
            "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True),
        }
        request.url = self._client.format_url(request.url, **path_format_arguments)  # type: ignore

        pipeline_response = await self._client._pipeline.run(  # type: ignore # pylint: disable=protected-access
            request, stream=False, **kwargs
        )

        response = pipeline_response.http_response

        if response.status_code not in [202]:
            map_error(status_code=response.status_code, response=response, error_map=error_map)
            raise HttpResponseError(response=response)

        response_headers = {}
        response_headers["Operation-Location"] = self._deserialize("str", response.headers.get("Operation-Location"))
        response_headers["retry-after"] = self._deserialize("int", response.headers.get("retry-after"))

        if response.content:
            deserialized = response.json()
        else:
            deserialized = None

        if cls:
            return cls(pipeline_response, cast(JSON, deserialized), response_headers)

        return cast(JSON, deserialized)

    @overload
    async def begin_send(
        self,
        message: JSON,
        *,
        operation_id: Optional[str] = None,
        client_request_id: Optional[str] = None,
        content_type: str = "application/json",
        **kwargs: Any
    ) -> AsyncLROPoller[JSON]:
        """Queues an email message to be sent to one or more recipients.

        Queues an email message to be sent to one or more recipients.

        :param message: Message payload for sending an email. Required.
        :type message: JSON
        :keyword operation_id: This is the ID provided by the customer to identify the long running
         operation. If an ID is not provided by the customer, the service will generate one. Default
         value is None.
        :paramtype operation_id: str
        :keyword client_request_id: Tracking ID sent with the request to help with debugging. Default
         value is None.
        :paramtype client_request_id: str
        :keyword content_type: Body Parameter content-type. Content type parameter for JSON body.
         Default value is "application/json".
        :paramtype content_type: str
        :keyword str continuation_token: A continuation token to restart a poller from a saved state.
        :keyword polling: By default, your polling method will be AsyncLROBasePolling. Pass in False
         for this operation to not poll, or pass in your own initialized polling object for a personal
         polling strategy.
        :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod
        :keyword int polling_interval: Default waiting time between two polls for LRO operations if no
         Retry-After header is present.
        :return: An instance of AsyncLROPoller that returns JSON object
        :rtype: ~azure.core.polling.AsyncLROPoller[JSON]
        :raises ~azure.core.exceptions.HttpResponseError:

        Example:
            .. code-block:: python

                # JSON input template you can fill out and use as your body input.
                message = {
                    "content": {
                        "subject": "str",  # Subject of the email message. Required.
                        "html": "str",  # Optional. Html version of the email message.
                        "plainText": "str"  # Optional. Plain text version of the email
                          message.
                    },
                    "recipients": {
                        "to": [
                            {
                                "address": "str",  # Email address. Required.
                                "displayName": "str"  # Optional. Email display name.
                            }
                        ],
                        "bcc": [
                            {
                                "address": "str",  # Email address. Required.
                                "displayName": "str"  # Optional. Email display name.
                            }
                        ],
                        "cc": [
                            {
                                "address": "str",  # Email address. Required.
                                "displayName": "str"  # Optional. Email display name.
                            }
                        ]
                    },
                    "senderAddress": "str",  # Sender email address from a verified domain.
                      Required.
                    "attachments": [
                        {
                            "contentInBase64": "str",  # Base64 encoded contents of the
                              attachment. Required.
                            "contentType": "str",  # MIME type of the content being
                              attached. Required.
                            "name": "str",  # Name of the attachment. Required.
                            "contentId": "str"  # Optional. Unique identifier (CID) to
                              reference an inline attachment.
                        }
                    ],
                    "headers": {
                        "str": "str"  # Optional. Custom email headers to be passed.
                    },
                    "replyTo": [
                        {
                            "address": "str",  # Email address. Required.
                            "displayName": "str"  # Optional. Email display name.
                        }
                    ],
                    "userEngagementTrackingDisabled": bool  # Optional. Indicates whether user
                      engagement tracking should be disabled for this request if the resource-level
                      user engagement tracking setting was already enabled in the control plane.
                }

                # response body for status code(s): 202
                response == {
                    "id": "str",  # The unique id of the operation. Use a UUID. Required.
                    "status": "str",  # Status of operation. Required. Known values are:
                      "NotStarted", "Running", "Succeeded", "Failed", and "Canceled".
                    "error": {
                        "additionalInfo": [
                            {
                                "info": {},  # Optional. The additional info.
                                "type": "str"  # Optional. The additional info type.
                            }
                        ],
                        "code": "str",  # Optional. The error code.
                        "details": [
                            ...
                        ],
                        "message": "str",  # Optional. The error message.
                        "target": "str"  # Optional. The error target.
                    }
                }
        """

    @overload
    async def begin_send(
        self,
        message: IO,
        *,
        operation_id: Optional[str] = None,
        client_request_id: Optional[str] = None,
        content_type: str = "application/json",
        **kwargs: Any
    ) -> AsyncLROPoller[JSON]:
        """Queues an email message to be sent to one or more recipients.

        Queues an email message to be sent to one or more recipients.

        :param message: Message payload for sending an email. Required.
        :type message: IO
        :keyword operation_id: This is the ID provided by the customer to identify the long running
         operation. If an ID is not provided by the customer, the service will generate one. Default
         value is None.
        :paramtype operation_id: str
        :keyword client_request_id: Tracking ID sent with the request to help with debugging. Default
         value is None.
        :paramtype client_request_id: str
        :keyword content_type: Body Parameter content-type. Content type parameter for binary body.
         Default value is "application/json".
        :paramtype content_type: str
        :keyword str continuation_token: A continuation token to restart a poller from a saved state.
        :keyword polling: By default, your polling method will be AsyncLROBasePolling. Pass in False
         for this operation to not poll, or pass in your own initialized polling object for a personal
         polling strategy.
        :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod
        :keyword int polling_interval: Default waiting time between two polls for LRO operations if no
         Retry-After header is present.
        :return: An instance of AsyncLROPoller that returns JSON object
        :rtype: ~azure.core.polling.AsyncLROPoller[JSON]
        :raises ~azure.core.exceptions.HttpResponseError:

        Example:
            .. code-block:: python

                # response body for status code(s): 202
                response == {
                    "id": "str",  # The unique id of the operation. Use a UUID. Required.
                    "status": "str",  # Status of operation. Required. Known values are:
                      "NotStarted", "Running", "Succeeded", "Failed", and "Canceled".
                    "error": {
                        "additionalInfo": [
                            {
                                "info": {},  # Optional. The additional info.
                                "type": "str"  # Optional. The additional info type.
                            }
                        ],
                        "code": "str",  # Optional. The error code.
                        "details": [
                            ...
                        ],
                        "message": "str",  # Optional. The error message.
                        "target": "str"  # Optional. The error target.
                    }
                }
        """

    @distributed_trace_async
    async def begin_send(
        self,
        message: Union[JSON, IO],
        *,
        operation_id: Optional[str] = None,
        client_request_id: Optional[str] = None,
        **kwargs: Any
    ) -> AsyncLROPoller[JSON]:
        """Queues an email message to be sent to one or more recipients.

        Queues an email message to be sent to one or more recipients.

        :param message: Message payload for sending an email. Is either a model type or a IO type.
         Required.
        :type message: JSON or IO
        :keyword operation_id: This is the ID provided by the customer to identify the long running
         operation. If an ID is not provided by the customer, the service will generate one. Default
         value is None.
        :paramtype operation_id: str
        :keyword client_request_id: Tracking ID sent with the request to help with debugging. Default
         value is None.
        :paramtype client_request_id: str
        :keyword content_type: Body Parameter content-type. Known values are: 'application/json'.
         Default value is None.
        :paramtype content_type: str
        :keyword str continuation_token: A continuation token to restart a poller from a saved state.
        :keyword polling: By default, your polling method will be AsyncLROBasePolling. Pass in False
         for this operation to not poll, or pass in your own initialized polling object for a personal
         polling strategy.
        :paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod
        :keyword int polling_interval: Default waiting time between two polls for LRO operations if no
         Retry-After header is present.
        :return: An instance of AsyncLROPoller that returns JSON object
        :rtype: ~azure.core.polling.AsyncLROPoller[JSON]
        :raises ~azure.core.exceptions.HttpResponseError:

        Example:
            .. code-block:: python

                # response body for status code(s): 202
                response == {
                    "id": "str",  # The unique id of the operation. Use a UUID. Required.
                    "status": "str",  # Status of operation. Required. Known values are:
                      "NotStarted", "Running", "Succeeded", "Failed", and "Canceled".
                    "error": {
                        "additionalInfo": [
                            {
                                "info": {},  # Optional. The additional info.
                                "type": "str"  # Optional. The additional info type.
                            }
                        ],
                        "code": "str",  # Optional. The error code.
                        "details": [
                            ...
                        ],
                        "message": "str",  # Optional. The error message.
                        "target": "str"  # Optional. The error target.
                    }
                }
        """
        _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {})
        _params = kwargs.pop("params", {}) or {}

        content_type = kwargs.pop("content_type", _headers.pop("Content-Type", None))  # type: Optional[str]
        cls = kwargs.pop("cls", None)  # type: ClsType[JSON]
        polling = kwargs.pop("polling", True)  # type: Union[bool, AsyncPollingMethod]
        lro_delay = kwargs.pop("polling_interval", self._config.polling_interval)
        cont_token = kwargs.pop("continuation_token", None)  # type: Optional[str]
        if cont_token is None:
            raw_result = await self._send_initial(  # type: ignore
                message=message,
                operation_id=operation_id,
                client_request_id=client_request_id,
                content_type=content_type,
                cls=lambda x, y, z: x,
                headers=_headers,
                params=_params,
                **kwargs
            )
        kwargs.pop("error_map", None)

        def get_long_running_output(pipeline_response):
            response_headers = {}
            response = pipeline_response.http_response
            response_headers["Operation-Location"] = self._deserialize(
                "str", response.headers.get("Operation-Location")
            )
            response_headers["retry-after"] = self._deserialize("int", response.headers.get("retry-after"))

            if response.content:
                deserialized = response.json()
            else:
                deserialized = None
            if cls:
                return cls(pipeline_response, deserialized, response_headers)
            return deserialized

        path_format_arguments = {
            "endpoint": self._serialize.url("self._config.endpoint", self._config.endpoint, "str", skip_quote=True),
        }

        if polling is True:
            polling_method = cast(
                AsyncPollingMethod,
                AsyncLROBasePolling(
                    lro_delay,
                    lro_options={"final-state-via": "azure-async-operation"},
                    path_format_arguments=path_format_arguments,
                    **kwargs
                ),
            )  # type: AsyncPollingMethod
        elif polling is False:
            polling_method = cast(AsyncPollingMethod, AsyncNoPolling())
        else:
            polling_method = polling
        if cont_token:
            return AsyncLROPoller.from_continuation_token(
                polling_method=polling_method,
                continuation_token=cont_token,
                client=self._client,
                deserialization_callback=get_long_running_output,
            )
        return AsyncLROPoller(self._client, raw_result, get_long_running_output, polling_method)
