text: """
      Aqualink API documentation
  
      The Aqualink public API documentation  # noqa: E501
  
      The version of the OpenAPI document: 1.0.0
      Generated by: https://openapi-generator.tech
  """
  from pprint import pprint
  import pandas as pd
  
  from aqualink_sdk.api_client import ApiClient
  from aqualink_sdk.api import time_series_api
  
  default_mapping = {
      "min_temperature": "min",
      "precipitation": "sum",
      "alert_level": "max",
      "bottom_temperature": "mean",
  }
  
  
  def aggregate_data(
      timeseries_data, aggregate_frequency, aggregate_mapping=default_mapping
  ):
      data = timeseries_data._data_store
      # Data is in the form:
      # {'bottom_temperature': {
      #     'spotter': {
      #         'data': [
      #             {'timestamp': '2022-01-08T00:04:00.000Z', 'value': 25.32},
      #             {'timestamp': '2022-01-08T00:14:00.000Z', 'value': 25.259999999999998},
      #             {'timestamp': '2022-01-08T00:24:00.000Z', 'value': 25.28}]}}
      # }
  
      new_data = {}
      for metric_name, metric_data in data.items():
          for sonde_type_name, sonde_data in metric_data.items():
              dataframe = pd.DataFrame(sonde_data["data"])
              dataframe["timestamp_index"] = pd.to_datetime(
                  dataframe["timestamp"]
              )  # convert column to datetime object
              dataframe.set_index("timestamp_index", inplace=True)
  
              temp_aggregate_mapping = {"value": aggregate_mapping[metric_name]}
  
              aggregate_data = dataframe.groupby(
                  pd.Grouper(freq=aggregate_frequency)
              ).agg(temp_aggregate_mapping)
  
              # Convert timestamp back to string
              aggregate_data["timestamp"] = aggregate_data.index.map(
                  lambda ts: ts.isoformat(timespec="milliseconds").replace("+00:00", "Z")
              )
  
              aggregate_data.dropna(inplace=True)
  
              new_metric_data = {
                  sonde_type_name: {"data": aggregate_data.to_dict("records")}
              }
              new_data[metric_name] = new_metric_data
  
      return new_data
  
  
  def aggregate_data_for_csv(
      timeseries_data, aggregate_frequency, aggregate_mapping=default_mapping
  ):
      data = timeseries_data._data_store
      # Data is in the form:
      # {'bottom_temperature': {
      #     'spotter': {
      #         'data': [
      #             {'timestamp': '2022-01-08T00:04:00.000Z', 'value': 25.32},
      #             {'timestamp': '2022-01-08T00:14:00.000Z', 'value': 25.259999999999998},
      #             {'timestamp': '2022-01-08T00:24:00.000Z', 'value': 25.28}]}}
      # }
  
      new_data_drame = None
  
      for metric_name, metric_data in data.items():
          for sonde_type_name, sonde_data in metric_data.items():
              dataframe = pd.DataFrame(sonde_data["data"])
              dataframe["timestamp_index"] = pd.to_datetime(
                  dataframe["timestamp"]
              )  # convert column to datetime object
              dataframe.set_index("timestamp_index", inplace=True)
  
              temp_aggregate_mapping = {"value": aggregate_mapping[metric_name]}
  
              aggregate_data = dataframe.groupby(
                  pd.Grouper(freq=aggregate_frequency)
              ).agg(temp_aggregate_mapping)
  
              aggregate_data.dropna(inplace=True)
              aggregate_data.rename(
                  columns={"value": f"{metric_name}_{sonde_type_name}"}, inplace=True
              )
  
              new_data_drame = (
                  new_data_drame.join(aggregate_data, how="outer")
                  if new_data_drame is not None
                  else aggregate_data
              )
  
      # Convert timestamp back to string
      new_data_drame["timestamp"] = new_data_drame.index.map(
          lambda ts: ts.isoformat(timespec="milliseconds").replace("+00:00", "Z")
      )
  
      # Replace timestamp in first position
      new_data_drame.insert(0, "timestamp", new_data_drame.pop("timestamp"))
  
      return new_data_drame
  
  
  class AggregateApi(object):
      """AggregateApi Class, built on top of the TimeSeriesApi"""
  
      def __init__(self, api_client=None):
          if api_client is None:
              api_client = ApiClient()
          self.ts_api = time_series_api.TimeSeriesApi(api_client)
  
      def get_aggregate_site_data(
          self,
          site_id,
          metrics,
          start,
          end,
          aggregate_frequency,
          aggregate_mapping,
          csv_output,
          **kwargs,
      ):
          """Returns specified aggregated time series data for a specified site  # noqa: E501
  
          Args:
              site_id (float):
              metrics ([str]):
              start (str):
              end (str):
              aggregate_frequency (str):
              aggregate_mapping({str: str})
  
          Returns:
              InlineResponse200
          """
          kwargs["hourly"] = False
          api_response = self.ts_api.time_series_controller_find_site_data(
              site_id, metrics, start, end, async_req=False, **kwargs
          )
  
          # TODO - verify that all the metrics requested in "metrics" have a mapping
          # TODO - strongly type the frequency
          # TODO - Hourly and aggregate are incompatible
  
          if not (aggregate_frequency and aggregate_mapping):
              raise Exception('Missing parameter aggregate_frequency or aggregate_mapping')
  
          if csv_output:
              dataframe = aggregate_data_for_csv(
                  api_response, aggregate_frequency, aggregate_mapping
              )
              dataframe.to_csv(csv_output, encoding="utf-8", index=False)
  
          data = aggregate_data(api_response, aggregate_frequency, aggregate_mapping)
          api_response._data_store = data
  
          return api_response
  