"""Metrics reporting module for Blueberry using protobuf.

Internal reference
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import base64
import logging
import time

# Internal import


class BluetoothMetricLogger(object):
    """A class used for gathering metrics from tests and devices.

  This class provides methods to allow test writers to easily export metrics
  from their tests as protobuf messages.

  Attributes:
    _metrics: The Bluetooth test proto message to add metrics to.
  """

    def __init__(self, bluetooth_test_proto_message):
        self._metrics = bluetooth_test_proto_message
        self._start_time = int(time.time())

    def add_primary_device_metrics(self, device):
        """Adds primary device metrics to the test proto message.

    Args:
      device: The Bluetooth device object to gather device metrics from.
    """
        device_message = self._metrics.configuration_data.primary_device
        message_fields = device_message.DESCRIPTOR.fields_by_name.keys()
        try:
            device_metrics_dict = device.get_device_info()
        except AttributeError:
            logging.info(
                'Must implement get_device_info method for this controller in order to upload device metrics.'
            )
            return

        for metric in device_metrics_dict:
            if metric in message_fields:
                setattr(device_message, metric, device_metrics_dict[metric])
            else:
                logging.info('%s is not a valid metric field.', metric)

    def add_connected_device_metrics(self, device):
        """Adds connected device metrics to the test proto message.

    Args:
      device: The Bluetooth device object to gather device metrics from.
    """
        device_message = self._metrics.configuration_data.connected_device
        message_fields = device_message.DESCRIPTOR.fields_by_name.keys()
        try:
            device_metrics_dict = device.get_device_info()
        except AttributeError:
            logging.info(
                'Must implement get_device_info method for this controller in order to upload device metrics.'
            )
            return

        for metric in device_metrics_dict:
            if metric in message_fields:
                setattr(device_message, metric, device_metrics_dict[metric])
            else:
                logging.warning('%s is not a valid metric field.', metric)

    def add_test_metrics(self, test_metrics_dict):
        """Adds test metrics to the test proto message.

    Args:
      test_metrics_dict: A dictionary of metrics to add to the test proto
      message. Metric will only be added if the key exists as a field in the
      test proto message.
    """
        if hasattr(self._metrics, 'configuration_data'):
            self._metrics.configuration_data.test_date_time = self._start_time
        message_fields = self._metrics.DESCRIPTOR.fields_by_name.keys()
        for metric in test_metrics_dict:
            if metric in message_fields:
                metric_value = test_metrics_dict[metric]
                if isinstance(metric_value, (list, tuple)):
                    getattr(self._metrics, metric).extend(metric_value)
                else:
                    setattr(self._metrics, metric, metric_value)
            else:
                logging.warning('%s is not a valid metric field.', metric)

    def proto_message_to_base64(self):
        """Converts a proto message to a base64 string.

    Returns:
    string, Message formatted as a base64 string.
    """
        return base64.b64encode(self._metrics.SerializeToString()).decode('utf-8')

    def proto_message_to_ascii(self):
        """Converts a proto message to an ASCII string.

    Returns:
      string, Message formatted as an ASCII string. Useful for debugging.
    """
        return text_format.MessageToString(self._metrics)
