import sys
from typing import List
from unittest import mock

import pytest
from packaging import version

from great_expectations.core.usage_statistics.execution_environment import (
    GXExecutionEnvironment,
    InstallEnvironment,
    PackageInfo,
)

if sys.version_info < (3, 8):
    # Note: importlib_metadata is included in the python standard library as importlib
    # starting with v3.8. At the time we remove support for python v3.7
    # this conditional can be removed.
    METADATA_VERSION_PATCH: str = "importlib_metadata.version"
else:
    METADATA_VERSION_PATCH: str = "importlib.metadata.version"


@pytest.mark.parametrize(
    "input_version", ["8.8.8", "0.14.12+14.g8f54aa902.dirty", "0.1.0.post0"]
)
@mock.patch(
    "great_expectations.core.usage_statistics.execution_environment.GXExecutionEnvironment._get_all_installed_packages",
    return_value=True,
)
@mock.patch(METADATA_VERSION_PATCH, return_value=True)
@mock.patch(
    "great_expectations.core.usage_statistics.package_dependencies.GXDependencies.get_dev_dependency_names",
    return_value=True,
)
@mock.patch(
    "great_expectations.core.usage_statistics.package_dependencies.GXDependencies.get_required_dependency_names",
    return_value=True,
)
def test_get_installed_packages(
    get_required_dependency_names,
    get_dev_dependency_names,
    mock_version,
    get_all_installed_packages,
    input_version,
):
    """Test that we are able to retrieve installed and not installed packages in the GX execution environment."""

    get_required_dependency_names.return_value = [
        "req-package-1",
        "req-package-2",
        "not-installed-req-package-1",
        "not-installed-req-package-2",
    ]
    get_dev_dependency_names.return_value = [
        "dev-package-1",
        "dev-package-2",
        "not-installed-dev-package-1",
        "not-installed-dev-package-2",
    ]
    mock_version.return_value = input_version
    get_all_installed_packages.return_value = [
        "req-package-1",
        "req-package-2",
        "dev-package-1",
        "dev-package-2",
    ]

    ge_execution_environment = GXExecutionEnvironment()
    expected_dependencies: List[PackageInfo] = [
        PackageInfo(
            package_name="req-package-1",
            installed=True,
            install_environment=InstallEnvironment.REQUIRED,
            version=version.Version(input_version),
        ),
        PackageInfo(
            package_name="req-package-2",
            installed=True,
            install_environment=InstallEnvironment.REQUIRED,
            version=version.Version(input_version),
        ),
        PackageInfo(
            package_name="not-installed-req-package-1",
            installed=False,
            install_environment=InstallEnvironment.REQUIRED,
            version=None,
        ),
        PackageInfo(
            package_name="not-installed-req-package-2",
            installed=False,
            install_environment=InstallEnvironment.REQUIRED,
            version=None,
        ),
        PackageInfo(
            package_name="dev-package-1",
            installed=True,
            install_environment=InstallEnvironment.DEV,
            version=version.Version(input_version),
        ),
        PackageInfo(
            package_name="dev-package-2",
            installed=True,
            install_environment=InstallEnvironment.DEV,
            version=version.Version(input_version),
        ),
        PackageInfo(
            package_name="not-installed-dev-package-1",
            installed=False,
            install_environment=InstallEnvironment.DEV,
            version=None,
        ),
        PackageInfo(
            package_name="not-installed-dev-package-2",
            installed=False,
            install_environment=InstallEnvironment.DEV,
            version=None,
        ),
    ]
    assert ge_execution_environment.dependencies == expected_dependencies
