"""
Copyright (C) 2021 Clariteia SL

This file is part of minos framework.

Minos framework can not be copied and/or distributed without the express permission of Clariteia SL.
"""
from __future__ import (
    annotations,
)

from typing import (
    TYPE_CHECKING,
    Any,
    Type,
)

if TYPE_CHECKING:
    from .model import (
        Aggregate,
        AggregateDiff,
    )


class MinosException(Exception):
    """Exception class for import packages or modules"""

    __slots__ = "_message"

    def __init__(self, error_message: str):
        self._message = error_message

    def __repr__(self):
        return f"{type(self).__name__}(message={repr(self._message)})"

    def __str__(self) -> str:
        """represent in a string format the error message passed during the instantiation"""
        return self._message


class MinosImportException(MinosException):
    pass


class MinosProtocolException(MinosException):
    pass


class MinosMessageException(MinosException):
    pass


class MinosConfigException(MinosException):
    """Base config exception."""


class MinosConfigDefaultAlreadySetException(MinosConfigException):
    """Exception to be raised when some config is already set as default."""


class MinosBrokerException(MinosException):
    """Base broker exception"""


class MinosBrokerNotProvidedException(MinosBrokerException):
    """Exception to be raised when a broker is needed but none is set."""


class MinosRepositoryException(MinosException):
    """Base repository exception."""


class MinosRepositoryAggregateNotFoundException(MinosRepositoryException):
    """Exception to be raised when some aggregate is not found on the repository."""


class MinosRepositoryDeletedAggregateException(MinosRepositoryException):
    """Exception to be raised when some aggregate is already deleted from the repository."""


class MinosRepositoryManuallySetAggregateIdException(MinosRepositoryException):
    """Exception to be raised when some aggregate is trying to be created with a manually set id."""


class MinosRepositoryManuallySetAggregateVersionException(MinosRepositoryException):
    """Exception to be raised when some aggregate is trying to be created with a manually set version."""


class MinosRepositoryUnknownActionException(MinosRepositoryException):
    """Exception to be raised when some entry tries to perform an unknown action."""


class MinosRepositoryNotProvidedException(MinosRepositoryException):
    """Exception to be raised when a repository is needed but none is set."""


class MinosSnapshotException(MinosException):
    """Base snapshot exception."""


class MinosSnapshotNotProvidedException(MinosSnapshotException):
    """Exception to be raised when a snapshot is needed but none is set."""


class MinosPreviousVersionSnapshotException(MinosSnapshotException):
    """Exception to be raised when current version is newer than the one to be processed."""

    def __init__(self, previous: Aggregate, diff: AggregateDiff):
        self.previous = previous
        self.diff = diff
        super().__init__(
            f"Version for {repr(previous.classname)} aggregate must be "
            f"greater than {previous.version}. Obtained: {diff.version}"
        )


class MinosModelException(MinosException):
    """Exception to be raised when some mandatory condition is not satisfied by a model."""

    pass


class EmptyMinosModelSequenceException(MinosModelException):
    """Exception to be raised when a sequence must be not empty, but it is empty."""

    pass


class MultiTypeMinosModelSequenceException(MinosModelException):
    """Exception to be raised when a sequence doesn't satisfy the condition to have the same type for each item."""

    pass


class MinosModelAttributeException(MinosException):
    """Base model attributes exception."""

    pass


class MinosReqAttributeException(MinosModelAttributeException):
    """Exception to be raised when some required attributes are not provided."""

    pass


class MinosTypeAttributeException(MinosModelAttributeException):
    """Exception to be raised when there are any mismatching between the expected and observed attribute type."""

    def __init__(self, name: str, target_type: Type, value: Any):
        self.name = name
        self.target_type = target_type
        self.value = value
        super().__init__(
            f"The {repr(target_type)} expected type for {repr(name)} does not match with "
            f"the given data type: {type(value)}"
        )


class MinosMalformedAttributeException(MinosModelAttributeException):
    """Exception to be raised when there are any kind of problems with the type definition."""

    pass


class MinosParseAttributeException(MinosModelAttributeException):
    """Exception to be raised when there are any kind of problems with the parsing logic."""

    def __init__(self, name: str, value: Any, exception: Exception):
        self.name = name
        self.value = value
        self.exception = exception
        super().__init__(f"{repr(exception)} was raised while parsing {repr(name)} field with {repr(value)} value.")


class MinosAttributeValidationException(MinosModelAttributeException):
    """Exception to be raised when some fields are not valid."""

    def __init__(self, name: str, value: Any):
        self.name = name
        self.value = value
        super().__init__(f"{repr(value)} value does not pass the {repr(name)} field validation.")
