# 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) Python Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------
from collections.abc import MutableMapping
import datetime
from typing import Any, Callable, Optional, TypeVar, Union
import urllib.parse

from azure.core import PipelineClient
from azure.core.exceptions import (
    ClientAuthenticationError,
    HttpResponseError,
    ResourceExistsError,
    ResourceNotFoundError,
    ResourceNotModifiedError,
    StreamClosedError,
    StreamConsumedError,
    map_error,
)
from azure.core.paging import ItemPaged
from azure.core.pipeline import PipelineResponse
from azure.core.rest import HttpRequest, HttpResponse
from azure.core.tracing.decorator import distributed_trace
from azure.core.utils import case_insensitive_dict
from azure.mgmt.core.exceptions import ARMErrorFormat

from .. import models as _models
from .._configuration import UsageManagementClientConfiguration
from .._utils.model_base import _deserialize, _failsafe_deserialize
from .._utils.serialization import Deserializer, Serializer

T = TypeVar("T")
ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, dict[str, Any]], Any]]
List = list

_SERIALIZER = Serializer()
_SERIALIZER.client_side_validation = False


def build_usage_aggregates_list_request(
    subscription_id: str,
    *,
    reported_start_time: datetime.datetime,
    reported_end_time: datetime.datetime,
    show_details: Optional[bool] = None,
    aggregation_granularity: Union[str, _models.AggregationGranularity] = "Daily",
    continuation_token_parameter: Optional[str] = None,
    **kwargs: Any
) -> HttpRequest:
    _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {})
    _params = case_insensitive_dict(kwargs.pop("params", {}) or {})

    api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2015-06-01-preview"))
    accept = _headers.pop("Accept", "application/json")

    # Construct URL
    _url = "/subscriptions/{subscriptionId}/providers/Microsoft.Commerce/usageAggregates"
    path_format_arguments = {
        "subscriptionId": _SERIALIZER.url("subscription_id", subscription_id, "str"),
    }

    _url: str = _url.format(**path_format_arguments)  # type: ignore

    # Construct parameters
    _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str")
    _params["reportedStartTime"] = _SERIALIZER.query("reported_start_time", reported_start_time, "iso-8601")
    _params["reportedEndTime"] = _SERIALIZER.query("reported_end_time", reported_end_time, "iso-8601")
    if show_details is not None:
        _params["showDetails"] = _SERIALIZER.query("show_details", show_details, "bool")
    if aggregation_granularity is not None:
        _params["aggregationGranularity"] = _SERIALIZER.query("aggregation_granularity", aggregation_granularity, "str")
    if continuation_token_parameter is not None:
        _params["continuationToken"] = _SERIALIZER.query(
            "continuation_token_parameter", continuation_token_parameter, "str"
        )

    # Construct headers
    _headers["Accept"] = _SERIALIZER.header("accept", accept, "str")

    return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs)


def build_rate_card_get_request(subscription_id: str, *, filter: str, **kwargs: Any) -> HttpRequest:
    _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {})
    _params = case_insensitive_dict(kwargs.pop("params", {}) or {})

    api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2015-06-01-preview"))
    accept = _headers.pop("Accept", "application/json")

    # Construct URL
    _url = "/subscriptions/{subscriptionId}/providers/Microsoft.Commerce/rateCard"
    path_format_arguments = {
        "subscriptionId": _SERIALIZER.url("subscription_id", subscription_id, "str"),
    }

    _url: str = _url.format(**path_format_arguments)  # type: ignore

    # Construct parameters
    _params["api-version"] = _SERIALIZER.query("api_version", api_version, "str")
    _params["$filter"] = _SERIALIZER.query("filter", filter, "str")

    # Construct headers
    _headers["Accept"] = _SERIALIZER.header("accept", accept, "str")

    return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs)


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

        Instead, you should access the following operations through
        :class:`~azure.mgmt.commerce.UsageManagementClient`'s
        :attr:`usage_aggregates` attribute.
    """

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

    @distributed_trace
    def list(
        self,
        *,
        reported_start_time: datetime.datetime,
        reported_end_time: datetime.datetime,
        show_details: Optional[bool] = None,
        aggregation_granularity: Union[str, _models.AggregationGranularity] = "Daily",
        continuation_token_parameter: Optional[str] = None,
        **kwargs: Any
    ) -> ItemPaged["_models.UsageAggregation"]:
        """Query aggregated Azure subscription consumption data for a date range.

        :keyword reported_start_time: The start of the time range to retrieve data for. Required.
        :paramtype reported_start_time: ~datetime.datetime
        :keyword reported_end_time: The end of the time range to retrieve data for. Required.
        :paramtype reported_end_time: ~datetime.datetime
        :keyword show_details: ``True`` returns usage data in instance-level detail, ``false`` causes
         server-side aggregation with fewer details. For example, if you have 3 website instances, by
         default you will get 3 line items for website consumption. If you specify showDetails = false,
         the data will be aggregated as a single line item for website consumption within the time
         period (for the given subscriptionId, meterId, usageStartTime and usageEndTime). Default value
         is None.
        :paramtype show_details: bool
        :keyword aggregation_granularity: ``Daily`` (default) returns the data in daily granularity,
         ``Hourly`` returns the data in hourly granularity. Known values are: "Daily" and "Hourly".
         Default value is "Daily".
        :paramtype aggregation_granularity: str or ~azure.mgmt.commerce.models.AggregationGranularity
        :keyword continuation_token_parameter: Used when a continuation token string is provided in the
         response body of the previous call, enabling paging through a large result set. If not present,
         the data is retrieved from the beginning of the day/hour (based on the granularity) passed in.
         Default value is None.
        :paramtype continuation_token_parameter: str
        :return: An iterator like instance of UsageAggregation
        :rtype: ~azure.core.paging.ItemPaged[~azure.mgmt.commerce.models.UsageAggregation]
        :raises ~azure.core.exceptions.HttpResponseError:
        """
        _headers = kwargs.pop("headers", {}) or {}
        _params = kwargs.pop("params", {}) or {}

        cls: ClsType[List[_models.UsageAggregation]] = kwargs.pop("cls", None)

        error_map: MutableMapping = {
            401: ClientAuthenticationError,
            404: ResourceNotFoundError,
            409: ResourceExistsError,
            304: ResourceNotModifiedError,
        }
        error_map.update(kwargs.pop("error_map", {}) or {})

        def prepare_request(next_link=None):
            if not next_link:

                _request = build_usage_aggregates_list_request(
                    subscription_id=self._config.subscription_id,
                    reported_start_time=reported_start_time,
                    reported_end_time=reported_end_time,
                    show_details=show_details,
                    aggregation_granularity=aggregation_granularity,
                    continuation_token_parameter=continuation_token_parameter,
                    api_version=self._config.api_version,
                    headers=_headers,
                    params=_params,
                )
                path_format_arguments = {
                    "endpoint": self._serialize.url(
                        "self._config.base_url", self._config.base_url, "str", skip_quote=True
                    ),
                }
                _request.url = self._client.format_url(_request.url, **path_format_arguments)

            else:
                # make call to next link with the client's api-version
                _parsed_next_link = urllib.parse.urlparse(next_link)
                _next_request_params = case_insensitive_dict(
                    {
                        key: [urllib.parse.quote(v) for v in value]
                        for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items()
                    }
                )
                _next_request_params["api-version"] = self._config.api_version
                _request = HttpRequest(
                    "GET", urllib.parse.urljoin(next_link, _parsed_next_link.path), params=_next_request_params
                )
                path_format_arguments = {
                    "endpoint": self._serialize.url(
                        "self._config.base_url", self._config.base_url, "str", skip_quote=True
                    ),
                }
                _request.url = self._client.format_url(_request.url, **path_format_arguments)

            return _request

        def extract_data(pipeline_response):
            deserialized = pipeline_response.http_response.json()
            list_of_elem = _deserialize(
                List[_models.UsageAggregation],
                deserialized.get("value", []),
            )
            if cls:
                list_of_elem = cls(list_of_elem)  # type: ignore
            return deserialized.get("nextLink") or None, iter(list_of_elem)

        def get_next(next_link=None):
            _request = prepare_request(next_link)

            _stream = False
            pipeline_response: PipelineResponse = 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)
                error = None
                if response.status_code == 202:
                    error = _failsafe_deserialize(_models.ErrorObjectResponse, response)
                else:
                    error = _failsafe_deserialize(
                        _models.ErrorObjectResponse,
                        response,
                    )
                raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat)

            return pipeline_response

        return ItemPaged(get_next, extract_data)


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

        Instead, you should access the following operations through
        :class:`~azure.mgmt.commerce.UsageManagementClient`'s
        :attr:`rate_card` attribute.
    """

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

    @distributed_trace
    def get(self, *, filter: str, **kwargs: Any) -> _models.ResourceRateCardInfo:
        """Enables you to query for the resource/meter metadata and related prices used in a given
        subscription by Offer ID, Currency, Locale and Region. The metadata associated with the billing
        meters, including but not limited to service names, types, resources, units of measure, and
        regions, is subject to change at any time and without notice. If you intend to use this billing
        data in an automated fashion, please use the billing meter GUID to uniquely identify each
        billable item. If the billing meter GUID is scheduled to change due to a new billing model, you
        will be notified in advance of the change.

        :keyword filter: The filter to apply on the operation. It ONLY supports the 'eq' and 'and'
         logical operators at this time. All the 4 query parameters 'OfferDurableId',  'Currency',
         'Locale', 'Region' are required to be a part of the $filter. Required.
        :paramtype filter: str
        :return: ResourceRateCardInfo. The ResourceRateCardInfo is compatible with MutableMapping
        :rtype: ~azure.mgmt.commerce.models.ResourceRateCardInfo
        :raises ~azure.core.exceptions.HttpResponseError:
        """
        error_map: MutableMapping = {
            401: ClientAuthenticationError,
            404: ResourceNotFoundError,
            409: ResourceExistsError,
            304: ResourceNotModifiedError,
        }
        error_map.update(kwargs.pop("error_map", {}) or {})

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

        cls: ClsType[_models.ResourceRateCardInfo] = kwargs.pop("cls", None)

        _request = build_rate_card_get_request(
            subscription_id=self._config.subscription_id,
            filter=filter,
            api_version=self._config.api_version,
            headers=_headers,
            params=_params,
        )
        path_format_arguments = {
            "endpoint": self._serialize.url("self._config.base_url", self._config.base_url, "str", skip_quote=True),
        }
        _request.url = self._client.format_url(_request.url, **path_format_arguments)

        _decompress = kwargs.pop("decompress", True)
        _stream = kwargs.pop("stream", False)
        pipeline_response: PipelineResponse = self._client._pipeline.run(  # pylint: disable=protected-access
            _request, stream=_stream, **kwargs
        )

        response = pipeline_response.http_response

        if response.status_code not in [200]:
            if _stream:
                try:
                    response.read()  # Load the body in memory and close the socket
                except (StreamConsumedError, StreamClosedError):
                    pass
            map_error(status_code=response.status_code, response=response, error_map=error_map)
            error = _failsafe_deserialize(
                _models.ErrorResponse,
                response,
            )
            raise HttpResponseError(response=response, model=error, error_format=ARMErrorFormat)

        if _stream:
            deserialized = response.iter_bytes() if _decompress else response.iter_raw()
        else:
            deserialized = _deserialize(_models.ResourceRateCardInfo, response.json())

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

        return deserialized  # type: ignore
