import logging
import sys
import traceback
from functools import wraps


class CustomExceptionMessage(Exception):
    """
    This class provides custom exception message.

    Parameters
    ----------
    error: Exception
        Provide the error that will be generated by the Exception class.

    Returns
    -------
    error_message: str
        A string containing the script file name, error line number and the
        exception message.
    """

    def __init__(self, exception_msg: Exception):
        super().__init__(exception_msg)
        self.exception_msg = exception_msg
        self.error_message = self.error_message_detail()

    def __str__(self) -> str:
        return self.error_message

    def error_message_detail(self) -> str:
        _, _, exc_traceback = sys.exc_info()
        file_name = exc_traceback.tb_frame.f_code.co_filename
        line_number = exc_traceback.tb_lineno

        traceback.print_exc()
        error_message = (
            "\n[Exception] A exception occurred in python module: "
            f"[{file_name}] at line number: [{line_number}] with error "
            f"message:\n {type(self.exception_msg).__name__} - {self.exception_msg}"
        )

        return error_message


def log_exception(logger: logging.Logger):
    """
    A decorator for catching exception and logging them in the log file.
    """

    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except:
                issue = "exception in " + func.__name__ + "\n"
                issue = issue + "==========================\n"
                logger.exception(issue)
                raise

        return wrapper

    return decorator