from typing import Dict

from fastapi import status

from learninghouse import versions
from learninghouse.api.errors import LearningHouseException
from learninghouse.models import LearningHouseErrorMessage, LearningHouseVersions

MIMETYPE_JSON = 'application/json'


class BrainNotTrained(LearningHouseException):
    STATUS_CODE = status.HTTP_404_NOT_FOUND
    NOT_TRAINED = 'NOT_TRAINED'
    DESCRIPTION = 'No trained brain with {name} found.'

    def __init__(self, name: str):
        super().__init__(self.STATUS_CODE,
                         self.NOT_TRAINED,
                         self.DESCRIPTION.format(name=name))

    @classmethod
    def api_description(cls) -> Dict:
        return {
            'model': LearningHouseErrorMessage,
            'description': 'No trained brain with this name found.',
            'content': {
                MIMETYPE_JSON: {
                    'example': {
                        'error': cls.NOT_TRAINED,
                        'description': cls.DESCRIPTION
                    }
                }
            }
        }


class BrainNotActual(LearningHouseException):
    STATUS_CODE = status.HTTP_428_PRECONDITION_REQUIRED
    NOT_ACTUAL = 'NOT_ACTUAL'
    DESCRIPTION = 'The versions of trained brain {name} are ' + \
        'not the same as service. ' + \
        'Versions service: {versions}. ' + \
        'Versions brain: {brain_versions}. ' + \
        'Please train the brain again.'

    def __init__(self, name: str, brain_versions: LearningHouseVersions):
        super().__init__(self.STATUS_CODE,
                         self.NOT_ACTUAL,
                         self.DESCRIPTION.format(name=name,
                                                 versions=versions,
                                                 brain_versions=brain_versions))

    @classmethod
    def api_description(cls) -> Dict:
        return {
            'model': LearningHouseErrorMessage,
            'description': 'If brain was not trained with actual versions ' +
            'of service and libraries.',
            'content': {
                MIMETYPE_JSON: {
                    'example': {
                        'error': cls.NOT_ACTUAL,
                        'description': cls.DESCRIPTION
                    }
                }
            }
        }


class BrainNotEnoughData(LearningHouseException):
    STATUS_CODE = status.HTTP_202_ACCEPTED
    NOT_ENOUGH_TRAINING_DATA = 'NOT_ENOUGH_TRAINING_DATA'
    DESCRIPTION = 'Brain was not trained because at least 10 data points are needed. ' + \
        'But your new data point was saved.'

    def __init__(self):
        super().__init__(self.STATUS_CODE,
                         self.NOT_ENOUGH_TRAINING_DATA,
                         self.DESCRIPTION)

    @classmethod
    def api_description(cls) -> Dict:
        return {
            'model': LearningHouseErrorMessage,
            'description': 'Response if there are not enough data points.',
            'content': {
                MIMETYPE_JSON: {
                    'example': {
                        'error': cls.NOT_ENOUGH_TRAINING_DATA,
                        'description': cls.DESCRIPTION
                    }
                }
            }
        }


class BrainNoConfiguration(LearningHouseException):
    STATUS_CODE = status.HTTP_404_NOT_FOUND
    NO_CONFIGURATION = 'NO_CONFIGURATION'
    DESCRIPTION = 'No configuration for brain {name} found.'

    def __init__(self, name: str):
        super().__init__(self.STATUS_CODE,
                         self.NO_CONFIGURATION,
                         self.DESCRIPTION.format(name=name))

    @classmethod
    def api_description(cls) -> Dict:
        return {
            'model': LearningHouseErrorMessage,
            'description': 'No brain configuration found.',
            'content': {
                MIMETYPE_JSON: {
                    'example': {
                        'error': cls.NO_CONFIGURATION,
                        'description': cls.DESCRIPTION
                    }
                }
            }
        }


class BrainBadRequest(LearningHouseException):
    STATUS_CODE = status.HTTP_400_BAD_REQUEST
    BAD_REQUEST = 'BAD_REQUEST'

    def __init__(self, description: str):
        super().__init__(self.STATUS_CODE, self.BAD_REQUEST, description)

    @classmethod
    def api_description(cls) -> Dict:
        return {
            'model': LearningHouseErrorMessage,
            'description': 'Brain received a bad request.',
            'content': {
                MIMETYPE_JSON: {
                    'example': {
                        'error': cls.BAD_REQUEST,
                        'description': ''
                    }
                }
            }
        }


class BrainExists(LearningHouseException):
    STATUS_CODE = status.HTTP_400_BAD_REQUEST
    EXISTS = 'EXISTS'
    DESCRIPTION = 'The existing brain {name} can not be recreated. Use PUT to update.'

    def __init__(self, name: str):
        super().__init__(self.STATUS_CODE,
                         self.EXISTS,
                         self.DESCRIPTION.format(name=name))

    @classmethod
    def api_description(cls) -> Dict:
        return {
            'model': LearningHouseErrorMessage,
            'description': 'An existing brain can not be recreated. Use PUT to update.',
            'content': {
                MIMETYPE_JSON: {
                    'example': {
                        'error': cls.EXISTS,
                        'description': cls.DESCRIPTION
                    }
                }
            }
        }
