# WARNING: Do not edit by hand, this file was generated by Crank:
#
#   https://github.com/gocardless/crank
#

import json


class GoCardlessProError(Exception):
    """Base exception class for gocardless_pro errors."""


class ApiError(GoCardlessProError):
    """Base exception class for GoCardless API errors. API errors will result
    in one of this class' subclasses being raised.
    """

    def __init__(self, error):
        self.error = error

    def __str__(self):
        messages = [error['message'] for error in (self.errors or [])
                    if error['message'] != self.message]
        if messages:
            return '{} ({})'.format(self.message, ', '.join(messages))
        else:
            return self.message

    @property
    def type(self):
        return self.error.get('type')

    @property
    def code(self):
        return self.error.get('code')

    @property
    def errors(self):
        return self.error.get('errors')

    @property
    def documentation_url(self):
        return self.error.get('documentation_url')

    @property
    def message(self):
        return self.error.get('message')

    @property
    def request_id(self):
        return self.error.get('request_id')

    @classmethod
    def _exception_for_status(cls, status):
        if status == 401:
            return AuthenticationError
        elif status == 403:
            return PermissionsError
        elif status == 429:
            return RateLimitError
        else:
            return None

    @classmethod
    def _exception_for_error_type(cls, error_type, errors=[]):
        if error_type == 'validation_failed':
            return ValidationFailedError
        elif error_type == 'invalid_api_usage':
            return InvalidApiUsageError
        elif error_type == 'invalid_state':
            for error in errors:
                if error['reason'] == 'idempotent_creation_conflict':
                    return IdempotentCreationConflictError
            return InvalidStateError
        elif error_type == 'gocardless':
            return GoCardlessInternalError
        else:
            return None


    @classmethod
    def exception_for(cls, status, error_type, errors=[]):
        exception = cls._exception_for_status(status) or cls._exception_for_error_type(error_type, errors)
        if exception is not None:
            return exception
        raise GoCardlessProError('Invalid error type "{}"'.format(error_type))


class ValidationFailedError(ApiError):

    def __str__(self):
        if self.errors and 'field' in self.errors[0]:
            errors = ['{field} {message}'.format(**error) for error in self.errors]
            return '{} ({})'.format(self.message, ', '.join(errors))
        return super(ValidationFailedError, self).__str__()


class IdempotentCreationConflictError(ApiError):

    @property
    def conflicting_resource_id(self):
        for error in self.error['errors']:
            if 'conflicting_resource_id' in error.get('links', {}) and \
                    bool(error['links']['conflicting_resource_id']):  # Neither None nor ""
                return error['links']['conflicting_resource_id']
        else:
            raise ApiError("Idempotent Creation Conflict Error missing conflicting_resource_id")


class InvalidApiUsageError(ApiError):
    pass


class InvalidStateError(ApiError):
    pass


class GoCardlessInternalError(ApiError):
    pass


class AuthenticationError(ApiError):
    pass


class PermissionsError(ApiError):
    pass


class RateLimitError(ApiError):
    pass


class MalformedResponseError(GoCardlessProError):

    def __init__(self, message, response):
        super(MalformedResponseError, self).__init__(message)
        self.response = response


class InvalidSignatureError(GoCardlessProError):
    pass
