"""
    This module contains all error that may occur during the management of
    virtual environments handled by Python3's built-in solutions (venv and pip).
"""

import re

from wox.subprocess_error_detection.utils import detect_error_from_stderr
from wox.utils import get_python_version_from_command
from wox.wox_exceptions import (
    DependencyConflictError,
    DiskFullError,
    PackageNotFoundError,
    PermissionDeniedError,
    PipTimeoutError,
    PythonInterpreterUnstableError
)


def detect_pip_errors(stderr_output, command, python_interpreter):
    """
        Detects pip-related errors upon dependencies installation.

        Parameters
        ----------
        stderr_output : str
            Output captured from the subprocess stderr stream.
        command : str
            Command executed by subprocess.
        python_interpreter : PythonInterpreter
            Python interpreter with its version and path.

        Raises
        ------
        DependencyConflictError
            Dependency conflict occurs during package installation.
        DiskFullError
            Disk is full and command cannot write data.
        PipTimeoutError
            Pip cannot reach package server.
        PackageNotFoundError
            Package is missing or wrongly spelled.
        PermissionDeniedError
            Permissions prevent writing data.
        PythonInterpreterUnstableError
            The Python interpreter crashes at the C-level.
    """

    check_dependency_conflict_error(stderr_output, command)
    check_disk_full_error(stderr_output, command)
    check_pip_timeout_error(stderr_output, command)
    check_package_not_found_error(stderr_output, command, python_interpreter.path)
    check_permission_denied_error(stderr_output, command)
    check_python_interpreter_unstable_error(stderr_output,
        command,
        python_interpreter.version
    )

def check_dependency_conflict_error(stderr_output, command):
    if (
        'install' in command and \
        detect_error_from_stderr(stderr_output,
            ['resolutionimpossible', 'conflicting dependencies']
        )
    ):
        raise DependencyConflictError

def check_disk_full_error(stderr_output, command):
    if 'install' in command and detect_error_from_stderr(stderr_output, ['errno 28']):
        raise DiskFullError

def check_pip_timeout_error(stderr_output, command):
    if ('install' in command and \
        detect_error_from_stderr(stderr_output,
            ['connection broken', 'failed to establish new connection']
        )
    ):
        raise PipTimeoutError

def check_package_not_found_error(stderr_output, command, python_interpreter_path = None):
    if ('install' in command and \
        detect_error_from_stderr(stderr_output,
            ['could not find a version', 'no matching distribution']
        )
    ):
        environment = python_interpreter_path.parent.parent.name
        match = re.search(r'No matching distribution found for (\S+)', stderr_output)
        if match:
            missing_package = match.group(1)
        raise PackageNotFoundError(missing_package, environment)

def check_permission_denied_error(stderr_output, command):
    if ('install' in command and \
        detect_error_from_stderr(stderr_output, ['permissionerror'])
    ):
        raise PermissionDeniedError

def check_python_interpreter_unstable_error(stderr_output, command, version):
    if (
        (
            ('venv' in command or 'install' in command) and \
            detect_error_from_stderr(stderr_output,
                [
                    'died with', 'sigsegv',
                    'segmentation fault', 'core dumped',
                    'problem confirming the ssl certificate',
                    'ssl module is not available',
                    'ssl module in python is not available'
                ]
            )
        ) or (
            'cannot open shared object file' in stderr_output.lower() and \
            'libpython' in stderr_output.lower()
        )
    ):
        if not version:
            version = get_python_version_from_command(command)
        raise PythonInterpreterUnstableError(version)
