"""
Functions for exception manipulation + custom exceptions used by SnowFinch
to identify common deviations from the expected behavior.
"""
import functools
import logging
import sys
import traceback
from typing import Optional, cast

if sys.version_info[:2] >= (3, 8):
    # TODO: Import directly (no need for conditional) when `python_requires = >= 3.8`
    from importlib.metadata import EntryPoint  # pragma: no cover
else:
    from importlib_metadata import EntryPoint  # pragma: no cover

from snowfinch import __version__ as VERSION


def exceptions2exit(exception_list):
    """Decorator to convert given exceptions to exit messages
    This avoids displaying nasty stack traces to end-users
    Args:
        exception_list [Exception]: list of exceptions to convert
    """

    def exceptions2exit_decorator(func):
        @functools.wraps(func)
        def func_wrapper(*args, **kwargs):
            try:
                func(*args, **kwargs)
            except tuple(exception_list) as ex:
                from snowfinch.cli import get_log_level  # defer circular imports to avoid errors

                if get_log_level() <= logging.DEBUG:
                    # user surely wants to see the stacktrace
                    traceback.print_exc()
                print(f"ERROR: {ex}")
                sys.exit(1)

        return func_wrapper

    return exceptions2exit_decorator


class DirectoryAlreadyExists(RuntimeError):
    """The project directory already exists, but no ``update`` or ``force``
    option was used.
    """


class DirectoryDoesNotExist(RuntimeError):
    """No directory was found to be updated."""


class GitNotInstalled(RuntimeError):
    """PyScaffold requires git to run."""

    DEFAULT_MESSAGE = "Make sure git is installed and working."

    def __init__(self, message=DEFAULT_MESSAGE, *args, **kwargs):
        super().__init__(message, *args, **kwargs)


class GitNotConfigured(RuntimeError):
    """PyScaffold tries to read user.name and user.email from git config."""

    DEFAULT_MESSAGE = (
        "Make sure git is configured. Run:\n"
        '  git config --global user.email "you@example.com"\n'
        '  git config --global user.name "Your Name"\n'
        "to set your account's default identity."
    )

    def __init__(self, message=DEFAULT_MESSAGE, *args, **kwargs):
        super().__init__(message, *args, **kwargs)


class GitDirtyWorkspace(RuntimeError):
    """Workspace of git is empty."""

    DEFAULT_MESSAGE = (
        "Your working tree is dirty. Commit your changes first" " or use '--force'."
    )

    def __init__(self, message=DEFAULT_MESSAGE, *args, **kwargs):
        super().__init__(message, *args, **kwargs)


class InvalidIdentifier(RuntimeError):
    """Python requires a specific format for its identifiers.

    https://docs.python.org/3.6/reference/lexical_analysis.html#identifiers
    """


class ShellCommandException(RuntimeError):
    """Outputs proper logging when a ShellCommand fails"""


class ImpossibleToFindConfigDir(RuntimeError):
    """An expected error occurred when trying to find the config dir.

    This might be related to not being able to read the $HOME env var in Unix
    systems, or %USERPROFILE% in Windows, or even the username.
    """

    def __init__(self, message=None, *args, **kwargs):
        message = message or self.__class__.__doc__
        super().__init__(message, *args, **kwargs)
