# coding: utf-8

"""
    Optimeering

    No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)

    The version of the OpenAPI document: 0.1.0
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""  # noqa: E501

from typing import Any, Dict, List, Optional, Tuple, Union

from optimeering_beta.api_client import OptimeeringClient, RequestSerialized
from optimeering_beta.models.predictions_data_get_response import PredictionsDataGetResponse
from optimeering_beta.models.predictions_series_get_response import PredictionsSeriesGetResponse
from pydantic import Field, StrictFloat, StrictInt, StrictStr, validate_call
from typing_extensions import Annotated


class PredictionsApi:
    """
    Collection of methods to interact with PredictionsApi
    """

    def __init__(self, api_client=None) -> None:
        if api_client is None:
            api_client = OptimeeringClient.get_default()
        self.api_client = api_client

    @validate_call
    def get_latest_predictions(
        self,
        max_event_time: Annotated[
            Optional[Any],
            Field(
                description="If specified, will only return the latest prediction available at the specified time. If not specified, no filters are applied. Should be specified in ISO 8601 datetime or duration format (eg - '2024-05-15T06:00:00+00:00', 'P1H', '-P1W1D', etc.)"
            ),
        ] = None,
        series_id: Annotated[
            Optional[List[StrictInt]],
            Field(description="Series ID to filter. If not specified, will return all series."),
        ] = None,
        _request_timeout: Union[
            None,
            Annotated[StrictFloat, Field(gt=0)],
            Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]],
        ] = None,
    ) -> PredictionsDataGetResponse:
        """Get Latest Predictions

        Returns latest predictions

        :param max_event_time: If specified, will only return the latest prediction available at the specified time. If not specified, no filters are applied. Should be specified in ISO 8601 datetime or duration format (eg - '2024-05-15T06:00:00+00:00', 'P1H', '-P1W1D', etc.)
        :type max_event_time: MaxEventTime
        :param series_id: Series ID to filter. If not specified, will return all series.
        :type series_id: List[StrictInt]
        :param _request_timeout: timeout setting for this request. If one
                                 number provided, it will be total request
                                 timeout. It can also be a pair (tuple) of
                                 (connection, read) timeouts.
        :type _request_timeout: int, tuple(int, int), optional
        :return: Returns the result object.
        :rtype: PredictionsDataGetResponse

        :Example:

        >>> from optimeering_beta import Configuration, OptimeeringClient
        >>> configuration = Configuration(host="https://beta.optimeering.com")
        >>> client = OptimeeringClient(configuration=configuration)
        >>> # Get filtered data point - replace ... with appropriate filters documented above
        >>> response = client.predictions_api.get_latest_predictions(...)

        """  # noqa: E501

        _param = self._get_latest_predictions_serialize(
            max_event_time=max_event_time,
            series_id=series_id,
            limit=None,
            offset=None,
        )

        _response_types_map: Dict[str, Optional[str]] = {
            "200": "PredictionsDataGetResponse",
            "422": "HTTPValidationError",
        }
        response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout)
        response_data.read()
        paginated_response = self.api_client.response_deserialize(
            response_data=response_data,
            response_types_map=_response_types_map,
        ).data
        if type(paginated_response) != dict:
            paginated_response._client = self.api_client
        next_page = paginated_response.next_page

        if next_page is None:
            return paginated_response

        # resolve extendable attribute
        attribute_to_extend_selected: Optional[str] = None
        if "series_id" in set(paginated_response.items[0].model_fields):
            extendable_attribute = {"datapoints", "events"}
            attribute_to_extend = extendable_attribute.intersection(set(paginated_response.items[0].model_fields))
            if len(attribute_to_extend) == 1:
                attribute_to_extend_selected = list(attribute_to_extend)[0]
            else:
                raise AttributeError("Failed to resolve extendable attribute.")

        api_key_configured = self.api_client.configuration.api_key is not None
        if api_key_configured:
            auth_header = {"apikey": self.api_client.configuration.api_key}
        while next_page is not None:
            if not api_key_configured:
                auth_header = {"Authorization": f"Bearer {self.api_client.token}"}

            next_pagination = self.api_client.call_api(
                method=_param[0],
                url=next_page,
                header_params={**_param[2], **auth_header},
                body=_param[3],
                post_params=_param[4],
                _request_timeout=_request_timeout,
            )
            next_pagination.read()
            next_pagination = self.api_client.response_deserialize(
                response_data=next_pagination,
                response_types_map=_response_types_map,
            ).data
            next_page = next_pagination.next_page

            if attribute_to_extend_selected:
                if next_pagination.items[0].series_id == paginated_response.items[-1].series_id:
                    # if series id is same, extract the first item and extend to last item
                    continued_data: List = getattr(next_pagination.items.pop(0), attribute_to_extend_selected)
                    previous_data: List = getattr(paginated_response.items[-1], attribute_to_extend_selected)
                    previous_data.extend(continued_data)
            paginated_response.items.extend(next_pagination.items)
        return paginated_response

    def _get_latest_predictions_serialize(
        self,
        max_event_time,
        series_id,
        limit,
        offset,
    ) -> RequestSerialized:
        _collection_formats: Dict[str, str] = {}

        _path_params: Dict[str, str] = {}
        _query_params: List[Tuple[str, str]] = []
        _header_params: Dict[str, Optional[str]] = {}
        _form_params: List[Tuple[str, str]] = []
        _files: Dict[str, Union[str, bytes]] = {}
        _body_params: Optional[bytes] = None

        # process the path parameters
        # process the query parameters
        if max_event_time is not None:
            _query_params.append(("max_event_time", max_event_time))

        if series_id is not None:
            series_id = ",".join(str(i) for i in series_id)
            _query_params.append(("series_id", series_id))

        if limit is not None:
            _query_params.append(("limit", limit))

        if offset is not None:
            _query_params.append(("offset", offset))

        # process the header parameters
        # process the form parameters
        # process the body parameter

        if self.api_client.configuration.api_key is None:
            # inject azure token
            _header_params["Authorization"] = f"Bearer {self.api_client.token}"
        else:
            _header_params["apikey"] = self.api_client.configuration.api_key

        return self.api_client.param_serialize(
            method="GET",
            resource_path="/api/predictions/latest",
            path_params=_path_params,
            query_params=_query_params,
            header_params=_header_params,
            body=_body_params,
            post_params=_form_params,
            files=_files,
            collection_formats=_collection_formats,
        )

    @validate_call
    def get_prediction_series(
        self,
        id: Annotated[
            Optional[List[StrictInt]],
            Field(description="ID of the series to retrieve. If not specified, will return all series."),
        ] = None,
        product: Annotated[
            Optional[List[StrictStr]],
            Field(
                description="The product for which series should be retrieved. If not specified, will return series for all products."
            ),
        ] = None,
        unit_type: Annotated[
            Optional[List[StrictStr]],
            Field(
                description="Unit type (eq. 'volumes', 'price', or 'price_spread'). If not specified, will return series for all unit types."
            ),
        ] = None,
        statistic: Annotated[
            Optional[List[StrictStr]],
            Field(
                description="Statistic type (eg. 'size', 'direction', or 'quantile'). If not specified, will return series for all statistic types."
            ),
        ] = None,
        area: Annotated[
            Optional[List[StrictStr]],
            Field(description="The name of the area (eg - NO3, SE4, or FI). If not specified, will return all areas."),
        ] = None,
        _request_timeout: Union[
            None,
            Annotated[StrictFloat, Field(gt=0)],
            Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]],
        ] = None,
    ) -> PredictionsSeriesGetResponse:
        """Get Series

        Returns the prediction series

        :param id: ID of the series to retrieve. If not specified, will return all series.
        :type id: List[StrictInt]
        :param product: The product for which series should be retrieved. If not specified, will return series for all products.
        :type product: List[StrictStr]
        :param unit_type: Unit type (eq. 'volumes', 'price', or 'price_spread'). If not specified, will return series for all unit types.
        :type unit_type: List[StrictStr]
        :param statistic: Statistic type (eg. 'size', 'direction', or 'quantile'). If not specified, will return series for all statistic types.
        :type statistic: List[StrictStr]
        :param area: The name of the area (eg - NO3, SE4, or FI). If not specified, will return all areas.
        :type area: List[StrictStr]
        :param _request_timeout: timeout setting for this request. If one
                                 number provided, it will be total request
                                 timeout. It can also be a pair (tuple) of
                                 (connection, read) timeouts.
        :type _request_timeout: int, tuple(int, int), optional
        :return: Returns the result object.
        :rtype: PredictionsSeriesGetResponse

        :Example:

        >>> from optimeering_beta import Configuration, OptimeeringClient
        >>> configuration = Configuration(host="https://beta.optimeering.com")
        >>> client = OptimeeringClient(configuration=configuration)
        >>> # Get filtered data point - replace ... with appropriate filters documented above
        >>> response = client.predictions_api.get_prediction_series(...)

        """  # noqa: E501

        _param = self._get_prediction_series_serialize(
            id=id,
            product=product,
            unit_type=unit_type,
            statistic=statistic,
            area=area,
            limit=None,
            offset=None,
        )

        _response_types_map: Dict[str, Optional[str]] = {
            "200": "PredictionsSeriesGetResponse",
            "422": "HTTPValidationError",
        }
        response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout)
        response_data.read()
        paginated_response = self.api_client.response_deserialize(
            response_data=response_data,
            response_types_map=_response_types_map,
        ).data
        if type(paginated_response) != dict:
            paginated_response._client = self.api_client
        next_page = paginated_response.next_page

        if next_page is None:
            return paginated_response

        # resolve extendable attribute
        attribute_to_extend_selected: Optional[str] = None
        if "series_id" in set(paginated_response.items[0].model_fields):
            extendable_attribute = {"datapoints", "events"}
            attribute_to_extend = extendable_attribute.intersection(set(paginated_response.items[0].model_fields))
            if len(attribute_to_extend) == 1:
                attribute_to_extend_selected = list(attribute_to_extend)[0]
            else:
                raise AttributeError("Failed to resolve extendable attribute.")

        api_key_configured = self.api_client.configuration.api_key is not None
        if api_key_configured:
            auth_header = {"apikey": self.api_client.configuration.api_key}
        while next_page is not None:
            if not api_key_configured:
                auth_header = {"Authorization": f"Bearer {self.api_client.token}"}

            next_pagination = self.api_client.call_api(
                method=_param[0],
                url=next_page,
                header_params={**_param[2], **auth_header},
                body=_param[3],
                post_params=_param[4],
                _request_timeout=_request_timeout,
            )
            next_pagination.read()
            next_pagination = self.api_client.response_deserialize(
                response_data=next_pagination,
                response_types_map=_response_types_map,
            ).data
            next_page = next_pagination.next_page

            if attribute_to_extend_selected:
                if next_pagination.items[0].series_id == paginated_response.items[-1].series_id:
                    # if series id is same, extract the first item and extend to last item
                    continued_data: List = getattr(next_pagination.items.pop(0), attribute_to_extend_selected)
                    previous_data: List = getattr(paginated_response.items[-1], attribute_to_extend_selected)
                    previous_data.extend(continued_data)
            paginated_response.items.extend(next_pagination.items)
        return paginated_response

    def _get_prediction_series_serialize(
        self,
        id,
        product,
        unit_type,
        statistic,
        area,
        limit,
        offset,
    ) -> RequestSerialized:
        _collection_formats: Dict[str, str] = {}

        _path_params: Dict[str, str] = {}
        _query_params: List[Tuple[str, str]] = []
        _header_params: Dict[str, Optional[str]] = {}
        _form_params: List[Tuple[str, str]] = []
        _files: Dict[str, Union[str, bytes]] = {}
        _body_params: Optional[bytes] = None

        # process the path parameters
        # process the query parameters
        if id is not None:
            id = ",".join(str(i) for i in id)
            _query_params.append(("id", id))

        if product is not None:
            product = ",".join(str(i) for i in product)
            _query_params.append(("product", product))

        if unit_type is not None:
            unit_type = ",".join(str(i) for i in unit_type)
            _query_params.append(("unit_type", unit_type))

        if statistic is not None:
            statistic = ",".join(str(i) for i in statistic)
            _query_params.append(("statistic", statistic))

        if area is not None:
            area = ",".join(str(i) for i in area)
            _query_params.append(("area", area))

        if limit is not None:
            _query_params.append(("limit", limit))

        if offset is not None:
            _query_params.append(("offset", offset))

        # process the header parameters
        # process the form parameters
        # process the body parameter

        if self.api_client.configuration.api_key is None:
            # inject azure token
            _header_params["Authorization"] = f"Bearer {self.api_client.token}"
        else:
            _header_params["apikey"] = self.api_client.configuration.api_key

        return self.api_client.param_serialize(
            method="GET",
            resource_path="/api/predictions/series/",
            path_params=_path_params,
            query_params=_query_params,
            header_params=_header_params,
            body=_body_params,
            post_params=_form_params,
            files=_files,
            collection_formats=_collection_formats,
        )

    @validate_call
    def get_predictions(
        self,
        series_id: Annotated[
            Optional[List[StrictInt]],
            Field(description="Series ID to filter. If not specified, will return all series."),
        ] = None,
        start: Annotated[
            Optional[Any],
            Field(
                description="The first datetime to fetch (inclusive). Defaults to `1970-01-01 00:00:00+0000`. Should be specified in ISO 8601 datetime or duration format (eg - '2024-05-15T06:00:00+00:00', 'P1H', '-P1W1D', etc.)"
            ),
        ] = None,
        end: Annotated[
            Optional[Any],
            Field(
                description="The last datetime to fetch (exclusive). Defaults to '2999-12-30 00:00:00+0000'. Should be specified in ISO 8601 datetime or duration format (eg - '2024-05-15T06:00:00+00:00', 'P1H', '-P1W1D', etc.)"
            ),
        ] = None,
        _request_timeout: Union[
            None,
            Annotated[StrictFloat, Field(gt=0)],
            Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]],
        ] = None,
    ) -> PredictionsDataGetResponse:
        """Get Predictions

        Returns predictions

        :param series_id: Series ID to filter. If not specified, will return all series.
        :type series_id: List[StrictInt]
        :param start: The first datetime to fetch (inclusive). Defaults to `1970-01-01 00:00:00+0000`. Should be specified in ISO 8601 datetime or duration format (eg - '2024-05-15T06:00:00+00:00', 'P1H', '-P1W1D', etc.)
        :type start: Start
        :param end: The last datetime to fetch (exclusive). Defaults to '2999-12-30 00:00:00+0000'. Should be specified in ISO 8601 datetime or duration format (eg - '2024-05-15T06:00:00+00:00', 'P1H', '-P1W1D', etc.)
        :type end: End
        :param _request_timeout: timeout setting for this request. If one
                                 number provided, it will be total request
                                 timeout. It can also be a pair (tuple) of
                                 (connection, read) timeouts.
        :type _request_timeout: int, tuple(int, int), optional
        :return: Returns the result object.
        :rtype: PredictionsDataGetResponse

        :Example:

        >>> from optimeering_beta import Configuration, OptimeeringClient
        >>> configuration = Configuration(host="https://beta.optimeering.com")
        >>> client = OptimeeringClient(configuration=configuration)
        >>> # Get filtered data point - replace ... with appropriate filters documented above
        >>> response = client.predictions_api.get_predictions(...)

        """  # noqa: E501

        _param = self._get_predictions_serialize(
            series_id=series_id,
            start=start,
            end=end,
            limit=None,
            offset=None,
        )

        _response_types_map: Dict[str, Optional[str]] = {
            "200": "PredictionsDataGetResponse",
            "422": "HTTPValidationError",
        }
        response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout)
        response_data.read()
        paginated_response = self.api_client.response_deserialize(
            response_data=response_data,
            response_types_map=_response_types_map,
        ).data
        if type(paginated_response) != dict:
            paginated_response._client = self.api_client
        next_page = paginated_response.next_page

        if next_page is None:
            return paginated_response

        # resolve extendable attribute
        attribute_to_extend_selected: Optional[str] = None
        if "series_id" in set(paginated_response.items[0].model_fields):
            extendable_attribute = {"datapoints", "events"}
            attribute_to_extend = extendable_attribute.intersection(set(paginated_response.items[0].model_fields))
            if len(attribute_to_extend) == 1:
                attribute_to_extend_selected = list(attribute_to_extend)[0]
            else:
                raise AttributeError("Failed to resolve extendable attribute.")

        api_key_configured = self.api_client.configuration.api_key is not None
        if api_key_configured:
            auth_header = {"apikey": self.api_client.configuration.api_key}
        while next_page is not None:
            if not api_key_configured:
                auth_header = {"Authorization": f"Bearer {self.api_client.token}"}

            next_pagination = self.api_client.call_api(
                method=_param[0],
                url=next_page,
                header_params={**_param[2], **auth_header},
                body=_param[3],
                post_params=_param[4],
                _request_timeout=_request_timeout,
            )
            next_pagination.read()
            next_pagination = self.api_client.response_deserialize(
                response_data=next_pagination,
                response_types_map=_response_types_map,
            ).data
            next_page = next_pagination.next_page

            if attribute_to_extend_selected:
                if next_pagination.items[0].series_id == paginated_response.items[-1].series_id:
                    # if series id is same, extract the first item and extend to last item
                    continued_data: List = getattr(next_pagination.items.pop(0), attribute_to_extend_selected)
                    previous_data: List = getattr(paginated_response.items[-1], attribute_to_extend_selected)
                    previous_data.extend(continued_data)
            paginated_response.items.extend(next_pagination.items)
        return paginated_response

    def _get_predictions_serialize(
        self,
        series_id,
        start,
        end,
        limit,
        offset,
    ) -> RequestSerialized:
        _collection_formats: Dict[str, str] = {}

        _path_params: Dict[str, str] = {}
        _query_params: List[Tuple[str, str]] = []
        _header_params: Dict[str, Optional[str]] = {}
        _form_params: List[Tuple[str, str]] = []
        _files: Dict[str, Union[str, bytes]] = {}
        _body_params: Optional[bytes] = None

        # process the path parameters
        # process the query parameters
        if series_id is not None:
            series_id = ",".join(str(i) for i in series_id)
            _query_params.append(("series_id", series_id))

        if start is not None:
            _query_params.append(("start", start))

        if end is not None:
            _query_params.append(("end", end))

        if limit is not None:
            _query_params.append(("limit", limit))

        if offset is not None:
            _query_params.append(("offset", offset))

        # process the header parameters
        # process the form parameters
        # process the body parameter

        if self.api_client.configuration.api_key is None:
            # inject azure token
            _header_params["Authorization"] = f"Bearer {self.api_client.token}"
        else:
            _header_params["apikey"] = self.api_client.configuration.api_key

        return self.api_client.param_serialize(
            method="GET",
            resource_path="/api/predictions/",
            path_params=_path_params,
            query_params=_query_params,
            header_params=_header_params,
            body=_body_params,
            post_params=_form_params,
            files=_files,
            collection_formats=_collection_formats,
        )
