import json
import logging

from typing import Dict

from requests import Response

from typing import Union


class NotFound(Exception):
    pass


class BackupAlertsDatabaseNoSourceException(Exception):
    pass


class RestoreAlertsDatabaseNoSourceException(Exception):
    pass


class NoResponseError(Exception):

    def __init__(
        self,
        logger,     # logging.Logger
        response,   # Response
    ):
        # type: (...) -> None

        self.logger = logger
        self.response = response

        error_status_code = response.status_code
        content = _get_response_content(response)

        if self.logger.isEnabledFor(logging.ERROR):
            response_str = json_serialize(response)
            self.logger.error(
                "No response. StatusCode: %r; Content: %r; FullResponse: %r",
                error_status_code,
                content,
                response_str,
            )

        super(NoResponseError, self).__init__(content)


class ForbiddenError(Exception):

    def __init__(
        self,
        logger,    # logging.Logger
        response,  # Response
    ):
        # type: (...) -> None

        self.logger = logger
        self.response = response

        error_status_code = response.status_code
        content = _get_response_content(response)

        if self.logger.isEnabledFor(logging.ERROR):
            response_str = json_serialize(response)
            self.logger.error(
                "Forbidden error. StatusCode: %r; Content: %r; FullResponse: %r",
                error_status_code,
                content,
                response_str,
            )

        super(ForbiddenError, self).__init__(content)


class NotFoundError(Exception):

    def __init__(
        self,
        logger,    # logging.Logger
        response,  # Response
    ):
        # type: (...) -> None

        self.logger = logger
        self.response = response

        error_status_code = response.status_code
        content = _get_response_content(response)

        if self.logger.isEnabledFor(logging.ERROR):
            response_str = json_serialize(response)
            self.logger.error(
                "Not found. StatusCode: %r; Content: %r; FullResponse: %r",
                error_status_code,
                content,
                response_str,
            )

        super(NotFoundError, self).__init__(content)


class NotAvailableError(Exception):

    def __init__(
        self,
        logger,    # logging.Logger
        response,  # Response
    ):
        # type: (...) -> None

        self.logger = logger
        self.response = response

        error_status_code = response.status_code
        content = _get_response_content(response)

        if self.logger.isEnabledFor(logging.ERROR):
            response_str = json_serialize(response)
            self.logger.error(
                "Code not available. StatusCode: %r; Content: %r; FullResponse: %r",
                error_status_code,
                content,
                response_str,
            )

        super(NotAvailableError, self).__init__(content)


class InUseError(Exception):

    def __init__(
        self,
        logger,    # logging.Logger
        response,  # Response
    ):
        # type: (...) -> None

        self.logger = logger
        self.response = response

        error_status_code = response.status_code
        content = _get_response_content(response)

        if self.logger.isEnabledFor(logging.ERROR):
            response_str = json_serialize(response)
            self.logger.error(
                "Code in use on another terminal. StatusCode: %r; Content: %r; FullResponse: %r",
                error_status_code,
                content,
                response_str,
            )

        super(InUseError, self).__init__(content)


class ProcessorError(Exception):

    def __init__(
        self,
        logger,    # logging.Logger
        response,  # Response
    ):
        # type: (...) -> None

        self.logger = logger
        self.response = response

        error_status_code = response.status_code
        content = _get_response_content(response)

        if self.logger.isEnabledFor(logging.ERROR):
            response_str = json_serialize(response)
            self.logger.error(
                "Processing error. StatusCode: %r; Content: %r; FullResponse: %r",
                error_status_code,
                content,
                response_str,
            )

        super(ProcessorError, self).__init__(content)


def _get_response_content(
    response,  # type: Response
):
    # type: (...) -> str

    try:
        content = json.loads(response.content).get("detail").encode("utf8")
        return content
    except (AttributeError, ValueError):
        return ""


def json_serialize(
    obj,  # type: Union[str, Dict]
):
    # type: (...) -> str

    try:
        return json.dumps(obj, default=lambda o: getattr(o, '__dict__', str(o)))
    except ValueError:  # noqa
        return obj
