import os
import platform
import shutil
import subprocess
import sys
from pathlib import Path
from packaging.version import Version

import pytest
import re

# Need to import everything to get fixtures
from .helpers import *  # noqa: F403
from . import helpers


class TestInstall:
    current_root_prefix = os.environ["MAMBA_ROOT_PREFIX"]
    current_prefix = os.environ["CONDA_PREFIX"]

    env_name = helpers.random_string()
    root_prefix = os.path.expanduser(os.path.join("~", "tmproot" + helpers.random_string()))
    prefix = os.path.join(root_prefix, "envs", env_name)

    @classmethod
    def setup_class(cls):
        os.environ["MAMBA_ROOT_PREFIX"] = TestInstall.root_prefix
        os.environ["CONDA_PREFIX"] = TestInstall.prefix

    @classmethod
    def setup_method(cls):
        helpers.create("-n", TestInstall.env_name, "--offline", no_dry_run=True)

    @classmethod
    def teardown_class(cls):
        os.environ["MAMBA_ROOT_PREFIX"] = TestInstall.current_root_prefix
        os.environ["CONDA_PREFIX"] = TestInstall.current_prefix
        shutil.rmtree(TestInstall.root_prefix)

    @classmethod
    def teardown_method(cls):
        os.environ["MAMBA_ROOT_PREFIX"] = TestInstall.root_prefix
        os.environ["CONDA_PREFIX"] = TestInstall.prefix
        for v in ("CONDA_CHANNELS", "MAMBA_TARGET_PREFIX"):
            if v in os.environ:
                os.environ.pop(v)

        if Path(TestInstall.prefix).exists():
            helpers.rmtree(TestInstall.prefix)

    @classmethod
    def config_tests(cls, res, root_prefix=root_prefix, target_prefix=prefix):
        assert res["root_prefix"] == root_prefix
        assert res["target_prefix"] == target_prefix
        assert res["use_target_prefix_fallback"]
        assert res["use_default_prefix_fallback"]
        assert res["use_root_prefix_fallback"]
        checks = (
            helpers.MAMBA_ALLOW_EXISTING_PREFIX
            | helpers.MAMBA_NOT_ALLOW_MISSING_PREFIX
            | helpers.MAMBA_NOT_ALLOW_NOT_ENV_PREFIX
            | helpers.MAMBA_EXPECT_EXISTING_PREFIX
        )
        assert res["target_prefix_checks"] == checks

    @pytest.mark.parametrize(
        "source,file_type",
        [
            ("cli_only", None),
            ("spec_file_only", "classic"),
            ("spec_file_only", "explicit"),
            ("spec_file_only", "yaml"),
            ("both", "classic"),
            ("both", "explicit"),
            ("both", "yaml"),
        ],
    )
    def test_specs(self, source, file_type, existing_cache):
        cmd = []
        specs = []

        if source in ("cli_only", "both"):
            specs = ["xtensor-python", "xtl"]
            cmd = list(specs)

        if source in ("spec_file_only", "both"):
            f_name = helpers.random_string()
            spec_file = os.path.join(TestInstall.root_prefix, f_name)

            if file_type == "classic":
                file_content = ["xtensor >0.20", "xsimd"]
                specs += file_content
            elif file_type == "explicit":
                channel = "https://conda.anaconda.org/conda-forge/linux-64/"
                explicit_specs = [
                    channel + "xtensor-0.21.5-hc9558a2_0.tar.bz2#d330e02e5ed58330638a24601b7e4887",
                    channel + "xsimd-7.4.8-hc9558a2_0.tar.bz2#32d5b7ad7d6511f1faacf87e53a63e5f",
                ]
                file_content = ["@EXPLICIT"] + explicit_specs
                specs = explicit_specs
            else:  # yaml
                spec_file += ".yaml"
                file_content = ["dependencies:", "  - xtensor >0.20", "  - xsimd"]
                specs += ["xtensor >0.20", "xsimd"]

            with open(spec_file, "w") as f:
                f.write("\n".join(file_content))

            cmd += ["-f", spec_file]

        res = helpers.install(*cmd, "--print-config-only")

        TestInstall.config_tests(res)
        assert res["env_name"] == ""
        assert res["specs"] == specs

    @pytest.mark.parametrize("root_prefix", (None, "env_var", "cli"))
    @pytest.mark.parametrize("target_is_root", (False, True))
    @pytest.mark.parametrize("cli_prefix", (False, True))
    @pytest.mark.parametrize("cli_env_name", (False, True))
    @pytest.mark.parametrize("yaml_name", (False, True, "prefix"))
    @pytest.mark.parametrize("env_var", (False, True))
    @pytest.mark.parametrize("current_target_prefix_fallback", (False, True))
    def test_target_prefix(
        self,
        root_prefix,
        target_is_root,
        cli_prefix,
        cli_env_name,
        yaml_name,
        env_var,
        current_target_prefix_fallback,
        existing_cache,
    ):
        cmd = []

        if root_prefix in (None, "cli"):
            os.environ["MAMBA_DEFAULT_ROOT_PREFIX"] = os.environ.pop("MAMBA_ROOT_PREFIX")

        if root_prefix == "cli":
            cmd += ["-r", TestInstall.root_prefix]

        r = TestInstall.root_prefix

        if target_is_root:
            p = r
            n = "base"
        else:
            p = TestInstall.prefix
            n = TestInstall.env_name

        expected_p = p

        if cli_prefix:
            cmd += ["-p", p]

        if cli_env_name:
            cmd += ["-n", n]

        if yaml_name:
            f_name = helpers.random_string() + ".yaml"
            spec_file = os.path.join(TestInstall.prefix, f_name)

            if yaml_name == "prefix":
                yaml_n = p
            else:
                yaml_n = n
                if not (cli_prefix or cli_env_name or target_is_root):
                    expected_p = os.path.join(TestInstall.root_prefix, "envs", yaml_n)

            file_content = [
                f"name: {yaml_n}",
                "dependencies: [xtensor]",
            ]
            with open(spec_file, "w") as f:
                f.write("\n".join(file_content))

            cmd += ["-f", spec_file]

        if env_var:
            os.environ["MAMBA_TARGET_PREFIX"] = p

        if not current_target_prefix_fallback:
            os.environ.pop("CONDA_PREFIX")
            os.environ.pop("CONDA_DEFAULT_ENV")
        else:
            os.environ["CONDA_PREFIX"] = p

        if (cli_prefix and cli_env_name) or (yaml_name == "prefix"):
            with pytest.raises(subprocess.CalledProcessError):
                helpers.install(*cmd, "--print-config-only")
        elif not (
            cli_prefix or cli_env_name or yaml_name or env_var or current_target_prefix_fallback
        ):
            # Fallback on root prefix
            res = helpers.install(*cmd, "--print-config-only")
            TestInstall.config_tests(res, root_prefix=r, target_prefix=r)
        else:
            res = helpers.install(*cmd, "--print-config-only")
            TestInstall.config_tests(res, root_prefix=r, target_prefix=expected_p)

    def test_target_prefix_with_no_settings(
        self,
        existing_cache,
    ):
        # Specify no arg
        cmd = []

        # Get the actual set MAMBA_ROOT_PREFIX when setting up `TestInstall` class
        os.environ["MAMBA_DEFAULT_ROOT_PREFIX"] = os.environ.pop("MAMBA_ROOT_PREFIX")
        os.environ.pop("CONDA_PREFIX")
        os.environ.pop("CONDA_DEFAULT_ENV")

        # Fallback on root prefix
        res = helpers.install(*cmd, "--print-config-only")

        TestInstall.config_tests(
            res,
            root_prefix=TestInstall.root_prefix,
            target_prefix=TestInstall.root_prefix,
        )

    @pytest.mark.skipif(
        sys.platform == "win32",
        reason="MAMBA_ROOT_PREFIX is set in windows GH workflow",
    )
    def test_target_prefix_with_no_settings_and_no_env_var(
        self,
        existing_cache,
    ):
        # Specify no arg
        cmd = []

        os.environ.pop("MAMBA_ROOT_PREFIX")
        os.environ.pop("CONDA_PREFIX")
        os.environ.pop("CONDA_DEFAULT_ENV")

        # Fallback on root prefix
        res = helpers.install(*cmd, "--print-config-only")

        TestInstall.config_tests(
            res,
            root_prefix=TestInstall.current_root_prefix,
            target_prefix=TestInstall.current_root_prefix,
        )

    @pytest.mark.parametrize("cli", (False, True))
    @pytest.mark.parametrize("yaml", (False, True))
    @pytest.mark.parametrize("env_var", (False, True))
    @pytest.mark.parametrize("rc_file", (False, True))
    def test_channels(self, cli, yaml, env_var, rc_file, existing_cache):
        cmd = []
        expected_channels = []

        if cli:
            cmd += ["-c", "cli"]
            expected_channels += ["cli"]

        if yaml:
            f_name = helpers.random_string() + ".yaml"
            spec_file = os.path.join(TestInstall.prefix, f_name)

            file_content = [
                "channels: [yaml]",
                "dependencies: [xtensor]",
            ]
            with open(spec_file, "w") as f:
                f.write("\n".join(file_content))

            cmd += ["-f", spec_file]
            expected_channels += ["yaml"]

        if env_var:
            os.environ["CONDA_CHANNELS"] = "env_var"
            expected_channels += ["env_var"]

        if rc_file:
            f_name = helpers.random_string() + ".yaml"
            rc_file = os.path.join(TestInstall.prefix, f_name)

            file_content = ["channels: [rc]"]
            with open(rc_file, "w") as f:
                f.write("\n".join(file_content))

            cmd += ["--rc-file", rc_file]
            expected_channels += ["rc"]

        res = helpers.install(*cmd, "--print-config-only", no_rc=not rc_file, default_channel=False)
        TestInstall.config_tests(res)
        if expected_channels:
            assert res["channels"] == expected_channels
        else:
            assert res["channels"] == ["conda-forge"]

    @pytest.mark.parametrize("type", ("yaml", "classic", "explicit"))
    def test_multiple_spec_files(self, type, existing_cache):
        cmd = []
        specs = ["xtensor", "xsimd"]
        channel = "https://conda.anaconda.org/conda-forge/linux-64/"
        explicit_specs = [
            channel + "xtensor-0.21.5-hc9558a2_0.tar.bz2#d330e02e5ed58330638a24601b7e4887",
            channel + "linux-64/xsimd-7.4.8-hc9558a2_0.tar.bz2#32d5b7ad7d6511f1faacf87e53a63e5f",
        ]

        for i in range(2):
            f_name = helpers.random_string()
            file = os.path.join(TestInstall.prefix, f_name)

            if type == "yaml":
                file += ".yaml"
                file_content = [f"dependencies: [{specs[i]}]"]
            elif type == "classic":
                file_content = [specs[i]]
            else:  # explicit
                file_content = ["@EXPLICIT", explicit_specs[i]]

            with open(file, "w") as f:
                f.write("\n".join(file_content))

            cmd += ["-f", file]

        res = helpers.install(*cmd, "--print-config-only")
        if type == "yaml" or type == "classic":
            assert res["specs"] == specs
        else:  # explicit
            assert res["specs"] == [explicit_specs[0]]

    @pytest.mark.parametrize("priority", (None, "disabled", "flexible", "strict"))
    @pytest.mark.parametrize("no_priority", (None, True))
    @pytest.mark.parametrize("strict_priority", (None, True))
    def test_channel_priority(self, priority, no_priority, strict_priority, existing_cache):
        cmd = ["-p", TestInstall.prefix, "xtensor"]
        expected_priority = "flexible"

        if priority:
            cmd += ["--channel-priority", priority]
            expected_priority = priority
        if no_priority:
            cmd += ["--no-channel-priority"]
            expected_priority = "disabled"
        if strict_priority:
            cmd += ["--strict-channel-priority"]
            expected_priority = "strict"

        if (
            (priority is not None)
            and (
                (no_priority and priority != "disabled")
                or (strict_priority and priority != "strict")
            )
            or (no_priority and strict_priority)
        ):
            with pytest.raises(subprocess.CalledProcessError):
                helpers.install(*cmd, "--print-config-only")
        else:
            res = helpers.install(*cmd, "--print-config-only")
            assert res["channel_priority"] == expected_priority

    def test_quotes(self, existing_cache):
        cmd = ["-p", f"{TestInstall.prefix}", "xtensor", "--print-config-only"]
        res = helpers.install(*cmd)
        assert res["target_prefix"] == TestInstall.prefix

    @pytest.mark.parametrize("prefix", ("target", "root"))
    def test_expand_user(self, prefix, existing_cache):
        if prefix == "target":
            r = TestInstall.root_prefix
            p = TestInstall.prefix.replace(os.path.expanduser("~"), "~")
        else:
            r = TestInstall.root_prefix.replace(os.path.expanduser("~"), "~")
            p = TestInstall.prefix

        cmd = [
            "-r",
            r,
            "-p",
            p,
            "xtensor",
            "--print-config-only",
        ]
        res = helpers.install(*cmd)
        assert res["target_prefix"] == TestInstall.prefix
        assert res["root_prefix"] == TestInstall.root_prefix

    def test_empty_specs(self, existing_cache):
        assert "Nothing to do." in helpers.install().strip()

    @pytest.mark.skipif(
        helpers.dry_run_tests is helpers.DryRun.ULTRA_DRY,
        reason="Running only ultra-dry tests",
    )
    @pytest.mark.parametrize("already_installed", [False, True])
    def test_non_explicit_spec(self, already_installed, existing_cache):
        cmd = ["-p", TestInstall.prefix, "xtensor", "--json"]

        if already_installed:
            helpers.install(*cmd, no_dry_run=True)

        res = helpers.install(*cmd)

        assert res["success"]
        assert res["dry_run"] == (helpers.dry_run_tests == helpers.DryRun.DRY)
        if already_installed:
            keys = {"dry_run", "success", "prefix", "message"}
            assert keys.issubset(set(res.keys()))
        else:
            keys = {"success", "prefix", "actions", "dry_run"}
            assert keys.issubset(set(res.keys()))

            action_keys = {"LINK", "PREFIX"}
            assert action_keys.issubset(set(res["actions"].keys()))

            packages = {pkg["name"] for pkg in res["actions"]["LINK"]}
            expected_packages = {"xtensor", "xtl"}
            assert expected_packages.issubset(packages)

            if not helpers.dry_run_tests:
                pkg_name = helpers.get_concrete_pkg(res, "xtensor")
                checker = helpers.PackageChecker("xtensor", TestInstall.current_root_prefix)
                checker.check_install_integrity()
                assert checker.get_name_version_build() == pkg_name

    @pytest.mark.skipif(
        helpers.dry_run_tests is helpers.DryRun.ULTRA_DRY,
        reason="Running only ultra-dry tests",
    )
    @pytest.mark.parametrize("already_installed", [False, True])
    @pytest.mark.parametrize("valid", [False, True])
    def test_explicit_specs(self, already_installed, valid, existing_cache):
        spec_file_content = [
            "@EXPLICIT",
            "https://conda.anaconda.org/conda-forge/linux-64/xtensor-0.21.5-hc9558a2_0.tar.bz2#d330e02e5ed58330638a24601b7e4887",
        ]
        if not valid:
            spec_file_content += ["https://conda.anaconda.org/conda-forge/linux-64/xtl"]

        spec_file = os.path.join(TestInstall.root_prefix, "explicit_specs.txt")
        with open(spec_file, "w") as f:
            f.write("\n".join(spec_file_content))

        cmd = ("-p", TestInstall.prefix, "-q", "-f", spec_file)

        if valid:
            helpers.install(*cmd, default_channel=False)

            list_res = helpers.umamba_list("-p", TestInstall.prefix, "--json")
            assert len(list_res) == 1
            pkg = list_res[0]
            assert pkg["name"] == "xtensor"
            assert pkg["version"] == "0.21.5"
            assert pkg["build_string"] == "hc9558a2_0"
        else:
            with pytest.raises(subprocess.CalledProcessError):
                helpers.install(*cmd, default_channel=False)

    @pytest.mark.skipif(
        helpers.dry_run_tests is helpers.DryRun.ULTRA_DRY,
        reason="Running only ultra-dry tests",
    )
    @pytest.mark.parametrize(
        "alias",
        [
            "",
            "https://conda.anaconda.org/",
            "https://repo.mamba.pm/",
            "https://repo.mamba.pm",
        ],
    )
    def test_channel_alias(self, alias, existing_cache):
        if alias:
            res = helpers.install("xtensor", "--json", "--channel-alias", alias)
        else:
            res = helpers.install("xtensor", "--json")

        for to_link in res["actions"]["LINK"]:
            assert to_link["channel"] == "conda-forge"

    @pytest.mark.skipif(
        helpers.dry_run_tests is helpers.DryRun.ULTRA_DRY,
        reason="Running only ultra-dry tests",
    )
    def test_no_python_pinning(self, existing_cache):
        helpers.install("python=3.9.19", no_dry_run=True)
        res = helpers.install("setuptools=63.4.3", "--no-py-pin", "--json")

        keys = {"success", "prefix", "actions", "dry_run"}
        assert keys.issubset(set(res.keys()))

        action_keys = {"LINK", "UNLINK", "PREFIX"}
        assert action_keys.issubset(set(res["actions"].keys()))

        # When using `--no-py-pin`, it may or may not update the already installed
        # python version, but `python_abi` is installed in any case
        # The following tests/assertions consider both cases
        expected_link_packages = {"python_abi"}
        link_packages = {pkg["name"] for pkg in res["actions"]["LINK"]}
        assert expected_link_packages.issubset(link_packages)

        unlink_packages = {pkg["name"] for pkg in res["actions"]["UNLINK"]}
        if {"python"}.issubset(link_packages):
            assert {"python"}.issubset(unlink_packages)

            py_pkg = [pkg for pkg in res["actions"]["LINK"] if pkg["name"] == "python"][0]
            assert py_pkg["version"] != ("3.9.19")

            py_pkg = [pkg for pkg in res["actions"]["UNLINK"] if pkg["name"] == "python"][0]
            assert py_pkg["version"] == ("3.9.19")
        else:
            assert len(res["actions"]["LINK"]) == 2  # Should be setuptools and python_abi

            py_abi_pkg = [pkg for pkg in res["actions"]["LINK"] if pkg["name"] == "python_abi"][0]
            assert py_abi_pkg["version"] == ("3.9")
            setuptools_pkg = [pkg for pkg in res["actions"]["LINK"] if pkg["name"] == "setuptools"][
                0
            ]
            assert setuptools_pkg["version"] == ("63.4.3")

            assert len(res["actions"]["UNLINK"]) == 1  # Should be setuptools
            assert res["actions"]["UNLINK"][0]["name"] == "setuptools"

    @pytest.mark.skipif(
        helpers.dry_run_tests is helpers.DryRun.ULTRA_DRY,
        reason="Running only ultra-dry tests",
    )
    @pytest.mark.skipif(
        sys.platform == "win32" or (sys.platform == "darwin" and platform.machine() == "arm64"),
        reason="Python2 no available",
    )
    def test_python_pinning(self, existing_cache):
        """Black fails to install as it is not available for pinned Python 2."""
        res = helpers.install("python=2", "--json", no_dry_run=True)
        assert res["success"]
        # We do not have great way to check for the type of error for now
        try:
            helpers.install("black", "--py-pin", "--json")
            assert False
        except subprocess.CalledProcessError:
            pass

    @pytest.mark.skipif(
        helpers.dry_run_tests is helpers.DryRun.ULTRA_DRY,
        reason="Running only ultra-dry tests",
    )
    def test_freeze_installed(self, existing_cache):
        helpers.install("xtensor=0.24", no_dry_run=True)
        res = helpers.install("xtensor-blas", "--freeze-installed", "--json")

        # without freeze installed, xtensor-blas 0.21.0 should be installed and xtensor updated to 0.25
        keys = {"success", "prefix", "actions", "dry_run"}
        assert keys.issubset(set(res.keys()))

        action_keys = {"LINK", "PREFIX"}
        assert action_keys.issubset(set(res["actions"].keys()))

        expected_packages = {"xtensor-blas"}
        link_packages = {pkg["name"] for pkg in res["actions"]["LINK"]}
        assert expected_packages.issubset(link_packages)
        assert res["actions"]["LINK"][-1]["version"] == "0.20.0"

    def test_channel_specific(self, existing_cache):
        res = helpers.install("conda-forge::xtensor", "--json", default_channel=False, no_rc=True)

        keys = {"success", "prefix", "actions", "dry_run"}
        assert keys.issubset(set(res.keys()))

        action_keys = {"LINK", "PREFIX"}
        assert action_keys.issubset(set(res["actions"].keys()))

        expected_packages = {"xtensor", "xtl"}
        link_packages = {pkg["name"] for pkg in res["actions"]["LINK"]}
        assert expected_packages.issubset(link_packages)

        for pkg in res["actions"]["LINK"]:
            assert pkg["channel"] == "conda-forge"

    def test_explicit_noarch(self, existing_cache):
        helpers.install("python", no_dry_run=True)

        channel = "https://conda.anaconda.org/conda-forge/noarch/"
        explicit_spec = (
            channel + "appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b"
        )
        file_content = ["@EXPLICIT", explicit_spec]

        spec_file = os.path.join(TestInstall.root_prefix, "explicit_specs_no_arch.txt")
        with open(spec_file, "w") as f:
            f.write("\n".join(file_content))

        cmd = ("-p", TestInstall.prefix, "-q", "-f", spec_file)

        helpers.install(*cmd, default_channel=False)

        list_res = helpers.umamba_list("-p", TestInstall.prefix, "--json")
        pkgs = [p for p in list_res if p["name"] == "appdirs"]
        assert len(pkgs) == 1
        pkg = pkgs[0]
        assert pkg["version"] == "1.4.4"
        assert pkg["build_string"] == "pyh9f0ad1d_0"

    def test_broken_package_name(self):
        non_existing_url = "https://026e9ab9-6b46-4285-ae0d-427553801720.de/mypackage.tar.bz2"
        try:
            helpers.install(non_existing_url, default_channel=False)
        except subprocess.CalledProcessError as e:
            assert 'Missing name and version in filename "mypackage.tar.bz2"' in e.stderr.decode(
                "utf-8"
            )

    def test_no_reinstall(self, existing_cache):
        """Reinstalling is a no op."""
        res = helpers.install("xtensor", "--json")
        assert "xtensor" in {pkg["name"] for pkg in res["actions"]["LINK"]}

        reinstall_res = helpers.install("xtensor", "--json")
        assert "actions" not in reinstall_res

    def test_install_local_package_relative_path(self):
        """Attempts to install a locally built package from a relative local path."""
        spec = "./micromamba/tests/test-server/repo::test-package"
        res = helpers.install(spec, "--json", default_channel=False)
        assert res["success"]

        pkgs = res["actions"]["LINK"]
        assert len(pkgs) == 1
        pkg = pkgs[0]
        assert pkg["name"] == "test-package"
        assert pkg["version"] == "0.1"
        assert pkg["url"].startswith("file://")

    def test_force_reinstall(self, existing_cache):
        """Force reinstall installs existing package again."""
        res = helpers.install("xtensor", "--json")
        assert "xtensor" in {pkg["name"] for pkg in res["actions"]["LINK"]}

        reinstall_res = helpers.install("xtensor", "--force-reinstall", "--json")
        assert "xtensor" in {pkg["name"] for pkg in reinstall_res["actions"]["LINK"]}

    def test_force_reinstall_not_installed(self, existing_cache):
        """Force reinstall on non-installed packages is valid."""
        reinstall_res = helpers.install("xtensor", "--force-reinstall", "--json")
        assert "xtensor" in {pkg["name"] for pkg in reinstall_res["actions"]["LINK"]}

    def test_install_compatible_release(self, existing_cache):
        """Install compatible release."""
        res = helpers.install("numpy~=1.26.0", "--force-reinstall", "--json")
        assert "numpy" in {pkg["name"] for pkg in res["actions"]["LINK"]}

        numpy = [pkg for pkg in res["actions"]["LINK"] if pkg["name"] == "numpy"][0]
        assert Version(numpy["version"]) >= Version("1.26.0")


def test_install_check_dirs(tmp_home, tmp_root_prefix):
    env_name = "myenv"
    env_prefix = tmp_root_prefix / "envs" / env_name

    helpers.create("-n", env_name, "python=3.8")
    res = helpers.install("-n", env_name, "nodejs", "--json")

    assert os.path.isdir(env_prefix)
    assert "nodejs" in {pkg["name"] for pkg in res["actions"]["LINK"]}

    if helpers.platform.system() == "Windows":
        assert os.path.isdir(env_prefix / "lib" / "site-packages")
    else:
        assert os.path.isdir(env_prefix / "lib" / "python3.8" / "site-packages")


@pytest.mark.parametrize("output_flag", ["", "--json", "--quiet"])
def test_install_check_logs(tmp_home, tmp_root_prefix, output_flag):
    env_name = "env-install-check-logs"
    helpers.create("-n", env_name)
    res = helpers.install("-n", env_name, "xtensor", output_flag)

    if output_flag == "--json":
        assert res["success"]
    elif output_flag == "--quiet":
        assert res == ""
    else:
        assert "To activate this environment, use:" not in res


def test_install_local_package(tmp_home, tmp_root_prefix):
    env_name = "myenv"
    tmp_root_prefix / "envs" / env_name

    helpers.create("-n", env_name, default_channel=False)

    """Attempts to install a .tar.bz2 package from a local directory."""
    file_path = Path(__file__).parent / "data" / "cph_test_data-0.0.1-0.tar.bz2"
    res = helpers.install("-n", env_name, file_path, "--json", default_channel=False)

    assert len(res["actions"]["LINK"]) == 1
    pkg = res["actions"]["LINK"][0]

    assert pkg["name"] == "cph_test_data"
    assert pkg["version"] == "0.0.1"
    assert pkg["fn"] == "cph_test_data-0.0.1-0.tar.bz2"
    assert pkg["channel"].startswith("file:///")
    assert pkg["channel"].endswith("data")
    assert pkg["url"].startswith("file:///")
    assert pkg["url"].endswith("cph_test_data-0.0.1-0.tar.bz2")


@pytest.mark.skipif(
    sys.platform == "darwin" and platform.machine() == "arm64",
    reason="Python 3.7.9 not available",
)
def test_track_features(tmp_home, tmp_root_prefix):
    env_name = "myenv"
    tmp_root_prefix / "envs" / env_name

    # should install CPython since PyPy has track features
    version = "3.7.9"
    helpers.create("-n", env_name, default_channel=False, no_rc=False)
    helpers.install(
        "-n",
        env_name,
        "-q",
        f"python={version}",
        "--strict-channel-priority",
        no_rc=False,
    )
    res = helpers.umamba_run("-n", env_name, "python", "-c", "import sys; print(sys.version)")
    if helpers.platform.system() == "Windows":
        assert res.strip().startswith(version)
        assert "[MSC v." in res.strip()
    elif helpers.platform.system() == "Linux":
        assert res.strip().startswith(version)
        assert "[GCC" in res.strip()
    else:
        assert res.strip().startswith(version)
        assert "[Clang" in res.strip()

    if helpers.platform.system() == "Linux":
        # now force PyPy install
        helpers.install(
            "-n",
            env_name,
            "-q",
            f"python={version}=*pypy",
            "--strict-channel-priority",
            no_rc=False,
        )
        res = helpers.umamba_run("-n", env_name, "python", "-c", "import sys; print(sys.version)")

        assert res.strip().startswith(version)
        assert "[PyPy" in res.strip()


def test_reinstall_with_new_version(tmp_home, tmp_root_prefix):
    env_name = "myenv"
    tmp_root_prefix / "envs" / env_name

    version = "3.8"
    helpers.create("-n", env_name, default_channel=False, no_rc=False)
    helpers.install(
        "-n",
        env_name,
        "-q",
        f"python={version}",
        "pip",
        no_rc=False,
    )

    res = helpers.umamba_run("-n", env_name, "python", "-c", "import sys; print(sys.version)")
    assert version in res

    res = helpers.umamba_run("-n", env_name, "python", "-c", "import pip; print(pip.__version__)")
    assert len(res)

    # Update python version
    version = "3.9"
    helpers.install(
        "-n",
        env_name,
        "-q",
        f"python={version}",
        no_rc=False,
    )

    res = helpers.umamba_run("-n", env_name, "python", "-c", "import sys; print(sys.version)")
    assert version in res

    res = helpers.umamba_run("-n", env_name, "python", "-c", "import pip; print(pip.__version__)")
    assert len(res)


env_yaml_content_to_install_empty_base = """
channels:
- conda-forge
dependencies:
- python
- xtensor
"""


def test_install_empty_base(tmp_home, tmp_root_prefix, tmp_path):
    env_prefix = tmp_path / "env-install-empty-base"

    os.environ["MAMBA_ROOT_PREFIX"] = str(env_prefix)

    env_file_yml = tmp_path / "test_install_env_empty_base.yaml"
    env_file_yml.write_text(env_yaml_content_to_install_empty_base)

    cmd = ["-p", env_prefix, f"--file={env_file_yml}", "-y", "--json"]

    res = helpers.install(*cmd)
    assert res["success"]

    packages = helpers.umamba_list("-p", env_prefix, "--json")
    assert any(package["name"] == "xtensor" for package in packages)
    assert any(package["name"] == "python" for package in packages)


env_specific_pip = """
channels:
  - conda-forge
dependencies:
  - python
  - pip:
    - numpy
"""


# Test that dry runs works if package are specified for the `pip:` section
def test_dry_run_pip_section(tmp_home, tmp_root_prefix, tmp_path):
    env_prefix = tmp_path / "env-specific-pip"

    env_file_yml = tmp_path / "test_install_env_specific_pip.yaml"
    env_file_yml.write_text(env_specific_pip)

    res = helpers.create("-p", env_prefix, "--json", "pip")
    assert res["success"]
    packages_at_creation = helpers.umamba_list("-p", env_prefix, "--json")

    # Install from the environment file
    res = helpers.install("-p", env_prefix, "-f", env_file_yml, "--json", "--dry-run")
    assert res["success"]
    assert res["dry_run"]

    packages = helpers.umamba_list("-p", env_prefix, "--json")
    assert packages == packages_at_creation

    # Check that the packages are not installed using `pip`
    res = helpers.umamba_run("-p", env_prefix, "pip", "list")
    assert "numpy" not in res


def test_install_revision(tmp_home, tmp_root_prefix):
    env_name = "myenv"
    helpers.create("-n", env_name, "python=3.8")
    helpers.install("-n", env_name, "xtl=0.7.2", "nlohmann_json=3.12.0")
    helpers.update("-n", env_name, "xtl")
    helpers.uninstall("-n", env_name, "nlohmann_json")
    helpers.install("-n", env_name, "--revision", "1")
    res = helpers.umamba_list(
        "-n",
        env_name,
    )

    xtl_regex = re.compile(r"xtl\s+0.7.2")
    assert xtl_regex.search(res)
    assert "nlohmann_json" in res
