import logging

from cubicweb import AuthenticationError, Forbidden, Unauthorized, QueryError
from pyramid.config import Configurator
from pyramid.request import Request
from rql import RQLException
from yams import ValidationError, UnknownType

from cubicweb_api.httperrors import get_http_error, get_http_500_error

log = logging.getLogger(__name__)


class ApiAuthenticationError(AuthenticationError):
    pass


class ApiForbidden(Forbidden):
    pass


class ApiException(Exception):
    pass


class ApiUnauthorized(Unauthorized):
    pass


class ApiRqlValidationError(ValidationError):
    pass


class ApiRqlException(RQLException):
    pass


class ApiRqlQueryError(QueryError):
    pass


class ApiRqlUnknownType(UnknownType):
    pass


def http_401_view(exc: Exception, request: Request):
    # User was not authenticated, return 401 HTTP error
    log.info(exc.__class__.__name__, exc_info=True)
    return get_http_error(401, exc.__class__.__name__, str(exc))


def http_403_view(exc: Exception, request: Request):
    # User was authenticated but had insufficient privileges, return 403 HTTP error
    log.info(exc.__class__.__name__, exc_info=True)
    return get_http_error(403, exc.__class__.__name__, str(exc))


def http_500_view(exc: Exception, request: Request):
    # An exception was raised but not caught, this is a server error (HTTP 5OO)
    log.info("ServerError", exc_info=True)
    return get_http_500_error()


def rql_validation_error_exception(exc: ValidationError, request: Request):
    exc.translate(request.cw_cnx._)
    log.info(exc.__class__.__name__, exc_info=True)
    return get_http_error(400, exc.__class__.__name__, str(exc))


def rql_error_exception(exc: Exception, request: Request):
    log.info(exc.__class__.__name__, exc_info=True)
    return get_http_error(400, exc.__class__.__name__, str(exc))


def includeme(config: Configurator):
    config.add_exception_view(
        rql_validation_error_exception, context=ApiRqlValidationError
    )
    config.add_exception_view(rql_error_exception, context=ApiRqlException)
    config.add_exception_view(rql_error_exception, context=ApiRqlQueryError)
    config.add_exception_view(rql_error_exception, context=ApiRqlUnknownType)
    config.add_exception_view(http_401_view, context=ApiAuthenticationError)
    config.add_exception_view(http_401_view, context=ApiUnauthorized)
    config.add_exception_view(http_403_view, context=ApiForbidden)
    config.add_exception_view(http_500_view, context=ApiException)