from data.database import BUILD_PHASE
from data import model
from redis import RedisError

import datetime
import logging

logger = logging.getLogger(__name__)

class StatusHandler(object):
  """ Context wrapper for writing status to build logs. """

  def __init__(self, build_logs, repository_build_uuid):
    self._current_phase = None
    self._current_command = None
    self._uuid = repository_build_uuid
    self._build_logs = build_logs

    self._status = {
        'total_commands': 0,
        'current_command': None,
        'push_completion': 0.0,
        'pull_completion': 0.0,
    }

    # Write the initial status.
    self.__exit__(None, None, None)

  def _append_log_message(self, log_message, log_type=None, log_data=None):
    log_data = log_data or {}
    log_data['datetime'] = str(datetime.datetime.now())

    try:
      self._build_logs.append_log_message(self._uuid, log_message, log_type, log_data)
    except RedisError:
      logger.exception('Could not save build log for build %s: %s', self._uuid, log_message)

  def append_log(self, log_message, extra_data=None):
    if log_message is None:
      return

    self._append_log_message(log_message, log_data=extra_data)

  def set_command(self, command, extra_data=None):
    if self._current_command == command:
      return

    self._current_command = command
    self._append_log_message(command, self._build_logs.COMMAND, extra_data)

  def set_error(self, error_message, extra_data=None, internal_error=False, requeued=False):
    self.set_phase(BUILD_PHASE.INTERNAL_ERROR if internal_error and requeued else BUILD_PHASE.ERROR)

    extra_data = extra_data or {}
    extra_data['internal_error'] = internal_error
    self._append_log_message(error_message, self._build_logs.ERROR, extra_data)

  def set_phase(self, phase, extra_data=None):
    if phase == self._current_phase:
      return False

    self._current_phase = phase
    self._append_log_message(phase, self._build_logs.PHASE, extra_data)

    # Update the repository build with the new phase
    repo_build = model.build.get_repository_build(self._uuid)
    repo_build.phase = phase
    repo_build.save()

    return True

  def __enter__(self):
    return self._status

  def __exit__(self, exc_type, value, traceback):
    try:
      self._build_logs.set_status(self._uuid, self._status)
    except RedisError:
      logger.exception('Could not set status of build %s to %s', self._uuid, self._status)