# 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 datetime
from io import IOBase
import sys
from typing import Any, Callable, Dict, IO, List, Optional, TypeVar, Union, cast, overload

from azure.core.exceptions import (
    ClientAuthenticationError,
    HttpResponseError,
    ResourceExistsError,
    ResourceNotFoundError,
    ResourceNotModifiedError,
    map_error,
)
from azure.core.pipeline import PipelineResponse
from azure.core.rest import AsyncHttpResponse, HttpRequest
from azure.core.tracing.decorator_async import distributed_trace_async
from azure.core.utils import case_insensitive_dict

from ...operations._operations import build_metrics_batch_batch_request

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


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

        Instead, you should access the following operations through
        :class:`~monitor_batch_metrics_client.aio.MonitorBatchMetricsClient`'s
        :attr:`metrics_batch` 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")

    @overload
    async def batch(
        self,
        subscription_id: str,
        batch_request: JSON,
        *,
        metricnamespace: str,
        metricnames: List[str],
        starttime: Optional[str] = None,
        endtime: Optional[str] = None,
        interval: Optional[datetime.timedelta] = None,
        aggregation: Optional[str] = None,
        top: Optional[int] = None,
        orderby: Optional[str] = None,
        filter: Optional[str] = None,
        rollupby: Optional[str] = None,
        content_type: str = "application/json",
        **kwargs: Any
    ) -> JSON:
        """Lists the metric values for multiple resources.

        :param subscription_id: The subscription identifier for the resources in this batch. Required.
        :type subscription_id: str
        :param batch_request: Metrics batch body including the list of resource ids. Required.
        :type batch_request: JSON
        :keyword metricnamespace: Metric namespace that contains the requested metric names. Required.
        :paramtype metricnamespace: str
        :keyword metricnames: The names of the metrics (comma separated) to retrieve. Required.
        :paramtype metricnames: list[str]
        :keyword starttime: The start time of the query. It is a string in the format
         'yyyy-MM-ddTHH:mm:ss.fffZ'. If you have specified the endtime parameter, then this parameter is
         required.
         If only starttime is specified, then endtime defaults to the current time.
         If no time interval is specified, the default is 1 hour. Default value is None.
        :paramtype starttime: str
        :keyword endtime: The end time of the query. It is a string in the format
         'yyyy-MM-ddTHH:mm:ss.fffZ'. Default value is None.
        :paramtype endtime: str
        :keyword interval: The interval (i.e. timegrain) of the query in ISO 8601 duration format.
         Defaults to PT1M. Special case for 'FULL' value that returns single datapoint for entire time
         span requested.
         *Examples: PT15M, PT1H, P1D, FULL*. Default value is None.
        :paramtype interval: ~datetime.timedelta
        :keyword aggregation: The list of aggregation types (comma separated) to retrieve.
         *Examples: average, minimum, maximum*. Default value is None.
        :paramtype aggregation: str
        :keyword top: The maximum number of records to retrieve per resource ID in the request.
         Valid only if filter is specified.
         Defaults to 10. Default value is None.
        :paramtype top: int
        :keyword orderby: The aggregation to use for sorting results and the direction of the sort.
         Only one order can be specified.
         *Examples: sum asc*. Default value is None.
        :paramtype orderby: str
        :keyword filter: The filter is used to reduce the set of metric data
         returned.:code:`<br>`Example::code:`<br>`Metric contains metadata A, B and C.:code:`<br>`-
         Return all time series of C where A = a1 and B = b1 or b2:code:`<br>`\\ **filter=A eq ‘a1’ and
         B eq ‘b1’ or B eq ‘b2’ and C eq ‘*’**\\ :code:`<br>`- Invalid variant::code:`<br>`\\ **filter=A
         eq ‘a1’ and B eq ‘b1’ and C eq ‘*’ or B = ‘b2’**\\ :code:`<br>`This is invalid because the
         logical or operator cannot separate two different metadata names.:code:`<br>`- Return all time
         series where A = a1, B = b1 and C = c1::code:`<br>`\\ **filter=A eq ‘a1’ and B eq ‘b1’ and C eq
         ‘c1’**\\ :code:`<br>`- Return all time series where A = a1:code:`<br>`\\ **filter=A eq ‘a1’ and
         B eq ‘\\ *’ and C eq ‘*\\ ’**. Default value is None.
        :paramtype filter: str
        :keyword rollupby: Dimension name(s) to rollup results by. For example if you only want to see
         metric values with a filter like 'City eq Seattle or City eq Tacoma' but don't want to see
         separate values for each city, you can specify 'RollUpBy=City' to see the results for Seattle
         and Tacoma rolled up into one timeseries. Default value is None.
        :paramtype rollupby: str
        :keyword content_type: Body Parameter content-type. Content type parameter for JSON body.
         Default value is "application/json".
        :paramtype content_type: str
        :return: JSON object
        :rtype: JSON
        :raises ~azure.core.exceptions.HttpResponseError:

        Example:
            .. code-block:: python

                # JSON input template you can fill out and use as your body input.
                batch_request = {
                    "resourceids": [
                        "str"
                    ]
                }

                # response body for status code(s): 200
                response == {
                    "values": [
                        {
                            "endtime": "str",
                            "starttime": "str",
                            "value": [
                                {
                                    "id": "str",
                                    "name": {
                                        "value": "str",
                                        "localizedValue": "str"
                                    },
                                    "timeseries": [
                                        {
                                            "data": [
                                                {
                                                    "timeStamp":
                                                      "2020-02-20 00:00:00",
                                                    "average":
                                                      0.0,
                                                    "count": 0.0,
                                                    "maximum":
                                                      0.0,
                                                    "minimum":
                                                      0.0,
                                                    "total": 0.0
                                                }
                                            ],
                                            "metadatavalues": [
                                                {
                                                    "name": {
                "value": "str",
                "localizedValue": "str"
                                                    },
                                                    "value":
                                                      "str"
                                                }
                                            ]
                                        }
                                    ],
                                    "type": "str",
                                    "unit": "str",
                                    "displayDescription": "str",
                                    "errorCode": "str",
                                    "errorMessage": "str"
                                }
                            ],
                            "interval": "str",
                            "namespace": "str",
                            "resourceid": "str",
                            "resourceregion": "str"
                        }
                    ]
                }
        """

    @overload
    async def batch(
        self,
        subscription_id: str,
        batch_request: IO[bytes],
        *,
        metricnamespace: str,
        metricnames: List[str],
        starttime: Optional[str] = None,
        endtime: Optional[str] = None,
        interval: Optional[datetime.timedelta] = None,
        aggregation: Optional[str] = None,
        top: Optional[int] = None,
        orderby: Optional[str] = None,
        filter: Optional[str] = None,
        rollupby: Optional[str] = None,
        content_type: str = "application/json",
        **kwargs: Any
    ) -> JSON:
        """Lists the metric values for multiple resources.

        :param subscription_id: The subscription identifier for the resources in this batch. Required.
        :type subscription_id: str
        :param batch_request: Metrics batch body including the list of resource ids. Required.
        :type batch_request: IO[bytes]
        :keyword metricnamespace: Metric namespace that contains the requested metric names. Required.
        :paramtype metricnamespace: str
        :keyword metricnames: The names of the metrics (comma separated) to retrieve. Required.
        :paramtype metricnames: list[str]
        :keyword starttime: The start time of the query. It is a string in the format
         'yyyy-MM-ddTHH:mm:ss.fffZ'. If you have specified the endtime parameter, then this parameter is
         required.
         If only starttime is specified, then endtime defaults to the current time.
         If no time interval is specified, the default is 1 hour. Default value is None.
        :paramtype starttime: str
        :keyword endtime: The end time of the query. It is a string in the format
         'yyyy-MM-ddTHH:mm:ss.fffZ'. Default value is None.
        :paramtype endtime: str
        :keyword interval: The interval (i.e. timegrain) of the query in ISO 8601 duration format.
         Defaults to PT1M. Special case for 'FULL' value that returns single datapoint for entire time
         span requested.
         *Examples: PT15M, PT1H, P1D, FULL*. Default value is None.
        :paramtype interval: ~datetime.timedelta
        :keyword aggregation: The list of aggregation types (comma separated) to retrieve.
         *Examples: average, minimum, maximum*. Default value is None.
        :paramtype aggregation: str
        :keyword top: The maximum number of records to retrieve per resource ID in the request.
         Valid only if filter is specified.
         Defaults to 10. Default value is None.
        :paramtype top: int
        :keyword orderby: The aggregation to use for sorting results and the direction of the sort.
         Only one order can be specified.
         *Examples: sum asc*. Default value is None.
        :paramtype orderby: str
        :keyword filter: The filter is used to reduce the set of metric data
         returned.:code:`<br>`Example::code:`<br>`Metric contains metadata A, B and C.:code:`<br>`-
         Return all time series of C where A = a1 and B = b1 or b2:code:`<br>`\\ **filter=A eq ‘a1’ and
         B eq ‘b1’ or B eq ‘b2’ and C eq ‘*’**\\ :code:`<br>`- Invalid variant::code:`<br>`\\ **filter=A
         eq ‘a1’ and B eq ‘b1’ and C eq ‘*’ or B = ‘b2’**\\ :code:`<br>`This is invalid because the
         logical or operator cannot separate two different metadata names.:code:`<br>`- Return all time
         series where A = a1, B = b1 and C = c1::code:`<br>`\\ **filter=A eq ‘a1’ and B eq ‘b1’ and C eq
         ‘c1’**\\ :code:`<br>`- Return all time series where A = a1:code:`<br>`\\ **filter=A eq ‘a1’ and
         B eq ‘\\ *’ and C eq ‘*\\ ’**. Default value is None.
        :paramtype filter: str
        :keyword rollupby: Dimension name(s) to rollup results by. For example if you only want to see
         metric values with a filter like 'City eq Seattle or City eq Tacoma' but don't want to see
         separate values for each city, you can specify 'RollUpBy=City' to see the results for Seattle
         and Tacoma rolled up into one timeseries. Default value is None.
        :paramtype rollupby: str
        :keyword content_type: Body Parameter content-type. Content type parameter for binary body.
         Default value is "application/json".
        :paramtype content_type: str
        :return: JSON object
        :rtype: JSON
        :raises ~azure.core.exceptions.HttpResponseError:

        Example:
            .. code-block:: python

                # response body for status code(s): 200
                response == {
                    "values": [
                        {
                            "endtime": "str",
                            "starttime": "str",
                            "value": [
                                {
                                    "id": "str",
                                    "name": {
                                        "value": "str",
                                        "localizedValue": "str"
                                    },
                                    "timeseries": [
                                        {
                                            "data": [
                                                {
                                                    "timeStamp":
                                                      "2020-02-20 00:00:00",
                                                    "average":
                                                      0.0,
                                                    "count": 0.0,
                                                    "maximum":
                                                      0.0,
                                                    "minimum":
                                                      0.0,
                                                    "total": 0.0
                                                }
                                            ],
                                            "metadatavalues": [
                                                {
                                                    "name": {
                "value": "str",
                "localizedValue": "str"
                                                    },
                                                    "value":
                                                      "str"
                                                }
                                            ]
                                        }
                                    ],
                                    "type": "str",
                                    "unit": "str",
                                    "displayDescription": "str",
                                    "errorCode": "str",
                                    "errorMessage": "str"
                                }
                            ],
                            "interval": "str",
                            "namespace": "str",
                            "resourceid": "str",
                            "resourceregion": "str"
                        }
                    ]
                }
        """

    @distributed_trace_async
    async def batch(
        self,
        subscription_id: str,
        batch_request: Union[JSON, IO[bytes]],
        *,
        metricnamespace: str,
        metricnames: List[str],
        starttime: Optional[str] = None,
        endtime: Optional[str] = None,
        interval: Optional[datetime.timedelta] = None,
        aggregation: Optional[str] = None,
        top: Optional[int] = None,
        orderby: Optional[str] = None,
        filter: Optional[str] = None,
        rollupby: Optional[str] = None,
        **kwargs: Any
    ) -> JSON:
        """Lists the metric values for multiple resources.

        :param subscription_id: The subscription identifier for the resources in this batch. Required.
        :type subscription_id: str
        :param batch_request: Metrics batch body including the list of resource ids. Is either a JSON
         type or a IO[bytes] type. Required.
        :type batch_request: JSON or IO[bytes]
        :keyword metricnamespace: Metric namespace that contains the requested metric names. Required.
        :paramtype metricnamespace: str
        :keyword metricnames: The names of the metrics (comma separated) to retrieve. Required.
        :paramtype metricnames: list[str]
        :keyword starttime: The start time of the query. It is a string in the format
         'yyyy-MM-ddTHH:mm:ss.fffZ'. If you have specified the endtime parameter, then this parameter is
         required.
         If only starttime is specified, then endtime defaults to the current time.
         If no time interval is specified, the default is 1 hour. Default value is None.
        :paramtype starttime: str
        :keyword endtime: The end time of the query. It is a string in the format
         'yyyy-MM-ddTHH:mm:ss.fffZ'. Default value is None.
        :paramtype endtime: str
        :keyword interval: The interval (i.e. timegrain) of the query in ISO 8601 duration format.
         Defaults to PT1M. Special case for 'FULL' value that returns single datapoint for entire time
         span requested.
         *Examples: PT15M, PT1H, P1D, FULL*. Default value is None.
        :paramtype interval: ~datetime.timedelta
        :keyword aggregation: The list of aggregation types (comma separated) to retrieve.
         *Examples: average, minimum, maximum*. Default value is None.
        :paramtype aggregation: str
        :keyword top: The maximum number of records to retrieve per resource ID in the request.
         Valid only if filter is specified.
         Defaults to 10. Default value is None.
        :paramtype top: int
        :keyword orderby: The aggregation to use for sorting results and the direction of the sort.
         Only one order can be specified.
         *Examples: sum asc*. Default value is None.
        :paramtype orderby: str
        :keyword filter: The filter is used to reduce the set of metric data
         returned.:code:`<br>`Example::code:`<br>`Metric contains metadata A, B and C.:code:`<br>`-
         Return all time series of C where A = a1 and B = b1 or b2:code:`<br>`\\ **filter=A eq ‘a1’ and
         B eq ‘b1’ or B eq ‘b2’ and C eq ‘*’**\\ :code:`<br>`- Invalid variant::code:`<br>`\\ **filter=A
         eq ‘a1’ and B eq ‘b1’ and C eq ‘*’ or B = ‘b2’**\\ :code:`<br>`This is invalid because the
         logical or operator cannot separate two different metadata names.:code:`<br>`- Return all time
         series where A = a1, B = b1 and C = c1::code:`<br>`\\ **filter=A eq ‘a1’ and B eq ‘b1’ and C eq
         ‘c1’**\\ :code:`<br>`- Return all time series where A = a1:code:`<br>`\\ **filter=A eq ‘a1’ and
         B eq ‘\\ *’ and C eq ‘*\\ ’**. Default value is None.
        :paramtype filter: str
        :keyword rollupby: Dimension name(s) to rollup results by. For example if you only want to see
         metric values with a filter like 'City eq Seattle or City eq Tacoma' but don't want to see
         separate values for each city, you can specify 'RollUpBy=City' to see the results for Seattle
         and Tacoma rolled up into one timeseries. Default value is None.
        :paramtype rollupby: str
        :return: JSON object
        :rtype: JSON
        :raises ~azure.core.exceptions.HttpResponseError:

        Example:
            .. code-block:: python

                # JSON input template you can fill out and use as your body input.
                batch_request = {
                    "resourceids": [
                        "str"
                    ]
                }

                # response body for status code(s): 200
                response == {
                    "values": [
                        {
                            "endtime": "str",
                            "starttime": "str",
                            "value": [
                                {
                                    "id": "str",
                                    "name": {
                                        "value": "str",
                                        "localizedValue": "str"
                                    },
                                    "timeseries": [
                                        {
                                            "data": [
                                                {
                                                    "timeStamp":
                                                      "2020-02-20 00:00:00",
                                                    "average":
                                                      0.0,
                                                    "count": 0.0,
                                                    "maximum":
                                                      0.0,
                                                    "minimum":
                                                      0.0,
                                                    "total": 0.0
                                                }
                                            ],
                                            "metadatavalues": [
                                                {
                                                    "name": {
                "value": "str",
                "localizedValue": "str"
                                                    },
                                                    "value":
                                                      "str"
                                                }
                                            ]
                                        }
                                    ],
                                    "type": "str",
                                    "unit": "str",
                                    "displayDescription": "str",
                                    "errorCode": "str",
                                    "errorMessage": "str"
                                }
                            ],
                            "interval": "str",
                            "namespace": "str",
                            "resourceid": "str",
                            "resourceregion": "str"
                        }
                    ]
                }
        """
        error_map: MutableMapping = {
            401: ClientAuthenticationError,
            404: ResourceNotFoundError,
            409: ResourceExistsError,
            304: ResourceNotModifiedError,
        }
        error_map.update(kwargs.pop("error_map", {}) or {})

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

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

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

        _request = build_metrics_batch_batch_request(
            subscription_id=subscription_id,
            metricnamespace=metricnamespace,
            metricnames=metricnames,
            starttime=starttime,
            endtime=endtime,
            interval=interval,
            aggregation=aggregation,
            top=top,
            orderby=orderby,
            filter=filter,
            rollupby=rollupby,
            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)

        _stream = False
        pipeline_response: PipelineResponse = await self._client._pipeline.run(  # pylint: disable=protected-access
            _request, stream=_stream, **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)

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

        if cls:
            return cls(pipeline_response, cast(JSON, deserialized), {})  # type: ignore

        return cast(JSON, deserialized)  # type: ignore
