# flake8: noqa : I005, I900, I001
"""This module contains the exception classes that are used to represent errors that occur during the invocation of a User Data Function.
These can be imported from the `fabric.functions` module."""

from fabric.internal.decorators.constants import (
    UDFExceptionCodes,
)


class UserDataFunctionError(Exception):
    """The exception/error base class for any errors raised during the invocation of a User Data Function.

    :param error_code: A string representing the error code associated with the exception.
    :type error_code: str
    :param message: An optional message describing the exception. Defaults to "Known User Data Function Exception Thrown".
    :type message: str
    :param properties: An optional dictionary containing additional properties related to the exception.
    :type properties: dict
    """

    def __init__(
        self,
        error_code: str,
        message: str = "Known User Data Function Exception Thrown",
        properties: dict = None,
    ):
        self.error_code = error_code
        self.message = message
        if properties is None:
            self.properties = {}
        else:
            self.properties = properties
        super().__init__(self.message)


class UserDataFunctionInternalError(UserDataFunctionError):
    """Represents an internal error that occurs during the execution of a user-defined function. This error is typically thrown when an unexpected error occurs during the execution of a function that is not related to an input or the user's code."""

    def __init__(
        self,
        message: str = "An internal execution error occured during function execution",
        properties: dict = None,
    ):
        """
        :param message: An optional message describing the exception. Defaults to "An internal execution error occured during function execution".
        :type message: str
        :param properties: An optional dictionary containing additional properties related to the exception.
        :type properties: dict
        """
        super().__init__(UDFExceptionCodes.INTERNAL_ERROR, message, properties)


class UserDataFunctionInvalidInputError(UserDataFunctionError):
    """Represents an error that occurs when the input provided to a function is invalid. This error is typically thrown when the input provided to a function does not match the expected input type or format."""

    def __init__(
        self,
        message: str = "Something went wrong when parsing an input to this function. This could be because the provided data couldn't be constructed as the data type provided, or the provided data isn't valid JSON.",
        properties: dict = None,
    ):
        """
        :param message: An optional message describing the exception. Defaults to "Something went wrong when parsing an input to this function. This could be because the provided data couldn't be constructed as the data type provided, or the provided data isn't valid JSON.".
        :type message: str
        :param properties: An optional dictionary containing additional properties related to the exception.
        :type properties: dict
        """
        super().__init__(UDFExceptionCodes.INVALID_INPUT, message, properties)


class UserDataFunctionMissingInputError(UserDataFunctionError):
    """Represents an error that occurs when a required parameter is missing from the input data provided to a function. This error is typically thrown when a parameter is expected to be present in the input data but is not found."""

    def __init__(
        self,
        message: str = "Parameter does not exist in binding data",
        properties: dict = None,
    ):
        """
        :param message: An optional message describing the exception. Defaults to "Parameter does not exist in binding data".
        :type message: str
        :param properties: An optional dictionary containing additional properties related to the exception.
        :type properties: dict
        """
        super().__init__(UDFExceptionCodes.MISSING_INPUT, message, properties)


class UserDataFunctionResponseTooLargeError(UserDataFunctionError):
    """Represents an error that occurs when the response generated by a function is too large. This limit is currently set to 30 megabytes."""

    def __init__(self, limit_in_megabytes: int, properties: dict = None):
        """
        :param limit_in_megabytes: The limit in megabytes that the response exceeded.
        :type limit_in_megabytes: int
        :param properties: An optional dictionary containing additional properties related to the exception.
        :type properties: dict
        """
        super().__init__(
            UDFExceptionCodes.RESPONSE_TOO_LARGE,
            f"Function's response size is larger than the {limit_in_megabytes} megabyte limit.",
            properties,
        )


class UserDataFunctionTimeoutError(UserDataFunctionError):
    """Represents an error that occurs when a function exceeds the timeout limit set for the function. This limit is currently set to 200 seconds."""

    def __init__(self, timeout: int, properties: dict = None):
        """
        :param timeout: The timeout limit in seconds that the function exceeded.
        :type timeout: int
        :param properties: An optional dictionary containing additional properties related to the exception.
        :type properties: dict
        """
        super().__init__(
            UDFExceptionCodes.TIMEOUT,
            f"Function hit a timeout limit after {timeout} seconds but may still be running. Please check the logs for more information.",
            properties,
        )


class UserThrownError(UserDataFunctionError):
    """Represents an error that is thrown by the user's code during the execution of a function. This error is typically thrown when the user's code encounters an error that is not related to the input data and can be the base class for custom errors."""

    def __init__(self, message: str = "User Exception Thrown", properties: dict = None):
        """
        :param message: An optional message describing the exception. Defaults to "User Exception Thrown".
        :type message: str
        :param properties: An optional dictionary containing additional properties related to the exception.
        :type properties: dict
        """
        super().__init__(UDFExceptionCodes.USER_THROWN, message, properties)
