from abc import ABCMeta, abstractmethod
from collections import namedtuple
from six import add_metaclass

from config_app.config_endpoints.api import format_date


def user_view(user):
  return {
    'name': user.username,
    'kind': 'user',
    'is_robot': user.robot,
  }


class RepositoryBuild(namedtuple('RepositoryBuild',
                                 ['uuid', 'logs_archived', 'repository_namespace_user_username',
                                  'repository_name',
                                  'can_write', 'can_read', 'pull_robot', 'resource_key', 'trigger',
                                  'display_name',
                                  'started', 'job_config', 'phase', 'status', 'error',
                                  'archive_url'])):
  """
  RepositoryBuild represents a build associated with a repostiory
  :type uuid: string
  :type logs_archived: boolean
  :type repository_namespace_user_username: string
  :type repository_name: string
  :type can_write: boolean
  :type can_write: boolean
  :type pull_robot: User
  :type resource_key: string
  :type trigger: Trigger
  :type display_name: string
  :type started: boolean
  :type job_config: {Any -> Any}
  :type phase: string
  :type status: string
  :type error: string
  :type archive_url: string
  """

  def to_dict(self):

    resp = {
      'id': self.uuid,
      'phase': self.phase,
      'started': format_date(self.started),
      'display_name': self.display_name,
      'status': self.status or {},
      'subdirectory': self.job_config.get('build_subdir', ''),
      'dockerfile_path': self.job_config.get('build_subdir', ''),
      'context': self.job_config.get('context', ''),
      'tags': self.job_config.get('docker_tags', []),
      'manual_user': self.job_config.get('manual_user', None),
      'is_writer': self.can_write,
      'trigger': self.trigger.to_dict(),
      'trigger_metadata': self.job_config.get('trigger_metadata', None) if self.can_read else None,
      'resource_key': self.resource_key,
      'pull_robot': user_view(self.pull_robot) if self.pull_robot else None,
      'repository': {
        'namespace': self.repository_namespace_user_username,
        'name': self.repository_name
      },
      'error': self.error,
    }

    if self.can_write:
      if self.resource_key is not None:
        resp['archive_url'] = self.archive_url
      elif self.job_config.get('archive_url', None):
        resp['archive_url'] = self.job_config['archive_url']

    return resp


class Approval(namedtuple('Approval', ['approver', 'approval_type', 'approved_date', 'notes'])):
  """
  Approval represents whether a key has been approved or not
  :type approver: User
  :type approval_type: string
  :type approved_date: Date
  :type notes: string
  """

  def to_dict(self):
    return {
      'approver': self.approver.to_dict() if self.approver else None,
      'approval_type': self.approval_type,
      'approved_date': self.approved_date,
      'notes': self.notes,
    }


class ServiceKey(
  namedtuple('ServiceKey', ['name', 'kid', 'service', 'jwk', 'metadata', 'created_date',
                            'expiration_date', 'rotation_duration', 'approval'])):
  """
  ServiceKey is an apostille signing key
  :type name: string
  :type kid: int
  :type service: string
  :type jwk: string
  :type metadata: string
  :type created_date: Date
  :type expiration_date: Date
  :type rotation_duration: Date
  :type approval: Approval

  """

  def to_dict(self):
    return {
      'name': self.name,
      'kid': self.kid,
      'service': self.service,
      'jwk': self.jwk,
      'metadata': self.metadata,
      'created_date': self.created_date,
      'expiration_date': self.expiration_date,
      'rotation_duration': self.rotation_duration,
      'approval': self.approval.to_dict() if self.approval is not None else None,
    }


class User(namedtuple('User', ['username', 'email', 'verified', 'enabled', 'robot'])):
  """
  User represents a single user.
  :type username: string
  :type email: string
  :type verified: boolean
  :type enabled: boolean
  :type robot: User
  """

  def to_dict(self):
    user_data = {
      'kind': 'user',
      'name': self.username,
      'username': self.username,
      'email': self.email,
      'verified': self.verified,
      'enabled': self.enabled,
    }

    return user_data


class Organization(namedtuple('Organization', ['username', 'email'])):
  """
  Organization represents a single org.
  :type username: string
  :type email: string
  """

  def to_dict(self):
    return {
      'name': self.username,
      'email': self.email,
    }


@add_metaclass(ABCMeta)
class SuperuserDataInterface(object):
  """
  Interface that represents all data store interactions required by a superuser api.
  """

  @abstractmethod
  def list_all_service_keys(self):
    """
    Returns a list of service keys
    """