# The following comment should be removed at some point in the future.
# mypy: strict-optional=False

from __future__ import absolute_import

import logging
import os
import shutil
import sys
import zipfile

from pipenv.patched.notpip._vendor import pkg_resources, six
from pipenv.patched.notpip._vendor.packaging.requirements import Requirement
from pipenv.patched.notpip._vendor.packaging.utils import canonicalize_name
from pipenv.patched.notpip._vendor.packaging.version import Version
from pipenv.patched.notpip._vendor.packaging.version import parse as parse_version
from pipenv.patched.notpip._vendor.pep517.wrappers import Pep517HookCaller

from pipenv.patched.notpip._internal import pep425tags
from pipenv.patched.notpip._internal.build_env import NoOpBuildEnvironment
from pipenv.patched.notpip._internal.exceptions import InstallationError
from pipenv.patched.notpip._internal.locations import get_scheme
from pipenv.patched.notpip._internal.models.link import Link
from pipenv.patched.notpip._internal.operations.build.metadata import generate_metadata
from pipenv.patched.notpip._internal.operations.build.metadata_legacy import \
    generate_metadata as generate_metadata_legacy
from pipenv.patched.notpip._internal.operations.install.editable_legacy import \
    install_editable as install_editable_legacy
from pipenv.patched.notpip._internal.operations.install.legacy import install as install_legacy
from pipenv.patched.notpip._internal.operations.install.wheel import install_wheel
from pipenv.patched.notpip._internal.pyproject import load_pyproject_toml, make_pyproject_path
from pipenv.patched.notpip._internal.req.req_uninstall import UninstallPathSet
from pipenv.patched.notpip._internal.utils.deprecation import deprecated
from pipenv.patched.notpip._internal.utils.hashes import Hashes
from pipenv.patched.notpip._internal.utils.logging import indent_log
from pipenv.patched.notpip._internal.utils.marker_files import (
    PIP_DELETE_MARKER_FILENAME,
    has_delete_marker_file,
    write_delete_marker_file,
)
from pipenv.patched.notpip._internal.utils.misc import (
    ask_path_exists,
    backup_dir,
    display_path,
    dist_in_site_packages,
    dist_in_usersite,
    get_installed_version,
    hide_url,
    redact_auth_from_url,
    rmtree,
)
from pipenv.patched.notpip._internal.utils.packaging import get_metadata
from pipenv.patched.notpip._internal.utils.temp_dir import TempDirectory
from pipenv.patched.notpip._internal.utils.typing import MYPY_CHECK_RUNNING
from pipenv.patched.notpip._internal.utils.virtualenv import running_under_virtualenv
from pipenv.patched.notpip._internal.vcs import vcs

if MYPY_CHECK_RUNNING:
    from typing import (
        Any, Dict, Iterable, List, Optional, Sequence, Union,
    )
    from pipenv.patched.notpip._internal.build_env import BuildEnvironment
    from pipenv.patched.notpip._internal.cache import WheelCache
    from pipenv.patched.notpip._internal.index.package_finder import PackageFinder
    from pipenv.patched.notpip._vendor.pkg_resources import Distribution
    from pipenv.patched.notpip._vendor.packaging.specifiers import SpecifierSet
    from pipenv.patched.notpip._vendor.packaging.markers import Marker


logger = logging.getLogger(__name__)


def _get_dist(metadata_directory):
    # type: (str) -> Distribution
    """Return a pkg_resources.Distribution for the provided
    metadata directory.
    """
    dist_dir = metadata_directory.rstrip(os.sep)

    # Determine the correct Distribution object type.
    if dist_dir.endswith(".egg-info"):
        dist_cls = pkg_resources.Distribution
    else:
        assert dist_dir.endswith(".dist-info")
        dist_cls = pkg_resources.DistInfoDistribution

    # Build a PathMetadata object, from path to metadata. :wink:
    base_dir, dist_dir_name = os.path.split(dist_dir)
    dist_name = os.path.splitext(dist_dir_name)[0]
    metadata = pkg_resources.PathMetadata(base_dir, dist_dir)

    return dist_cls(
        base_dir,
        project_name=dist_name,
        metadata=metadata,
    )


class InstallRequirement(object):
    """
    Represents something that may be installed later on, may have information
    about where to fetch the relevant requirement and also contains logic for
    installing the said requirement.
    """

    def __init__(
        self,
        req,  # type: Optional[Requirement]
        comes_from,  # type: Optional[Union[str, InstallRequirement]]
        source_dir=None,  # type: Optional[str]
        editable=False,  # type: bool
        link=None,  # type: Optional[Link]
        markers=None,  # type: Optional[Marker]
        use_pep517=None,  # type: Optional[bool]
        isolated=False,  # type: bool