import logging
import json

from jsonschema import validate
from buildtrigger.triggerutil import (RepositoryReadException, TriggerActivationException,
                                      TriggerStartException, ValidationRequestException,
                                      InvalidPayloadException,
                                      SkipRequestException, raise_if_skipped_build,
                                      find_matching_branches)

from buildtrigger.basehandler import BuildTriggerHandler

from util.security.ssh import generate_ssh_keypair


logger = logging.getLogger(__name__)

class CustomBuildTrigger(BuildTriggerHandler):
  payload_schema = {
    'type': 'object',
    'properties': {
      'commit': {
        'type': 'string',
        'description': 'first 7 characters of the SHA-1 identifier for a git commit',
        'pattern': '^([A-Fa-f0-9]{7,})$',
      },
      'ref': {
        'type': 'string',
        'description': 'git reference for a git commit',
        'pattern': '^refs\/(heads|tags|remotes)\/(.+)$',
      },
      'default_branch': {
        'type': 'string',
        'description': 'default branch of the git repository',
      },
      'commit_info': {
        'type': 'object',
        'description': 'metadata about a git commit',
        'properties': {
          'url': {
            'type': 'string',
            'description': 'URL to view a git commit',
          },
          'message': {
            'type': 'string',
            'description': 'git commit message',
          },
          'date': {
            'type': 'string',
            'description': 'timestamp for a git commit'
          },
          'author': {
            'type': 'object',
            'description': 'metadata about the author of a git commit',
            'properties': {
              'username': {
                'type': 'string',
                'description': 'username of the author',
              },
              'url': {
                'type': 'string',
                'description': 'URL to view the profile of the author',
              },
              'avatar_url': {
                'type': 'string',
                'description': 'URL to view the avatar of the author',
              },
            },
            'required': ['username', 'url', 'avatar_url'],
          },
          'committer': {
            'type': 'object',
            'description': 'metadata about the committer of a git commit',
            'properties': {
              'username': {
                'type': 'string',
                'description': 'username of the committer',
              },
              'url': {
                'type': 'string',
                'description': 'URL to view the profile of the committer',
              },
              'avatar_url': {
                'type': 'string',
                'description': 'URL to view the avatar of the committer',
              },
            },
            'required': ['username', 'url', 'avatar_url'],
          },
        },
        'required': ['url', 'message', 'date'],
      },
    },
    'required': ['commit', 'ref', 'default_branch'],
  }

  @classmethod
  def service_name(cls):
    return 'custom-git'

  def is_active(self):
    return self.config.has_key('credentials')

  def _metadata_from_payload(self, payload):
    try:
      metadata = json.loads(payload)
      validate(metadata, self.payload_schema)
    except Exception as e:
      raise InvalidPayloadException(e.message)
    return metadata

  def handle_trigger_request(self, request):
    payload = request.data
    if not payload:
      raise InvalidPayloadException()

    logger.debug('Payload %s', payload)

    metadata = self._metadata_from_payload(payload)
    metadata['git_url'] = self.config['build_source']

    prepared = self.prepare_build(metadata)

    # Check if we should skip this build.
    raise_if_skipped_build(prepared, self.config)

    return prepared

  def manual_start(self, run_parameters=None):
    # commit_sha is the only required parameter
    commit_sha = run_parameters.get('commit_sha')
    if commit_sha is None:
      raise TriggerStartException('missing required parameter')

    config = self.config
    metadata = {
      'commit': commit_sha,
      'git_url': config['build_source'],
    }

    return self.prepare_build(metadata, is_manual=True)

  def activate(self, standard_webhook_url):
    config = self.config
    public_key, private_key = generate_ssh_keypair()
    config['credentials'] = [
      {
        'name': 'SSH Public Key',
        'value': public_key,
      },
      {
        'name': 'Webhook Endpoint URL',
        'value': standard_webhook_url,
      },
    ]
    self.config = config
    return config, {'private_key': private_key}

  def deactivate(self):
    config = self.config
    config.pop('credentials', None)
    self.config = config
    return config

  def get_repository_url(self):
    return None