"""
It's possible to use multiple types of host pythons to create virtual environments and all should work:

- host installation
- invoking from a venv (if Python 3.3+)
- invoking from an old style virtualenv (<17.0.0)
- invoking from our own venv
"""
from __future__ import absolute_import, unicode_literals

import subprocess
import sys

import pytest

from virtualenv.discovery.py_info import PythonInfo
from virtualenv.info import IS_WIN
from virtualenv.run import cli_run
from virtualenv.util.path import Path
from virtualenv.util.subprocess import Popen

CURRENT = PythonInfo.current_system()


# noinspection PyUnusedLocal
def root(tmp_path_factory, session_app_data):
    return CURRENT.system_executable


def venv(tmp_path_factory, session_app_data):
    if CURRENT.is_venv:
        return sys.executable
    elif CURRENT.version_info.major == 3:
        root_python = root(tmp_path_factory, session_app_data)
        dest = tmp_path_factory.mktemp("venv")
        process = Popen([str(root_python), "-m", "venv", "--without-pip", str(dest)])
        process.communicate()
        # sadly creating a virtual environment does not tell us where the executable lives in general case
        # so discover using some heuristic
        exe_path = CURRENT.discover_exe(prefix=str(dest)).original_executable
        return exe_path


def old_virtualenv(tmp_path_factory, session_app_data):
    if CURRENT.is_old_virtualenv:
        return CURRENT.executable
    else:
        env_for_old_virtualenv = tmp_path_factory.mktemp("env-for-old-virtualenv")
        result = cli_run(["--no-download", "--activators", "", str(env_for_old_virtualenv), "--no-periodic-update"])
        # noinspection PyBroadException
        try:
            process = Popen(
                [
                    str(result.creator.script("pip")),
                    "install",
                    "--no-index",
                    "--disable-pip-version-check",
                    str(Path(__file__).resolve().parent / "virtualenv-16.7.9-py2.py3-none-any.whl"),
                    "-v",
                ],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
            _, __ = process.communicate()
            assert not process.returncode
        except Exception:
            return RuntimeError("failed to install old virtualenv")
        # noinspection PyBroadException
        try:
            old_virtualenv_at = tmp_path_factory.mktemp("old-virtualenv")
            cmd = [
                str(result.creator.script("virtualenv")),
                str(old_virtualenv_at),
                "--no-pip",
                "--no-setuptools",
                "--no-wheel",
            ]
            process = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            _, __ = process.communicate()
            assert not process.returncode
            if result.creator.interpreter.implementation == "PyPy" and IS_WIN:
                # old virtualenv creates pypy paths wrong on windows, so have to hardcode it
                return str(old_virtualenv_at / "bin" / "pypy.exe")
            exe_path = CURRENT.discover_exe(session_app_data, prefix=str(old_virtualenv_at)).original_executable
            return exe_path
        except Exception as exception:
            return RuntimeError("failed to create old virtualenv {}".format(exception))


PYTHON = {
    "root": root,
    "venv": venv,
    "old_virtualenv": old_virtualenv,
}


@pytest.fixture(params=list(PYTHON.values()), ids=list(PYTHON.keys()), scope="session")
def python(request, tmp_path_factory, session_app_data):
    result = request.param(tmp_path_factory, session_app_data)
    if isinstance(result, Exception):
        pytest.skip("could not resolve interpreter based on {} because {}".format(request.param.__name__, result))
    if result is None:
        pytest.skip("requires interpreter with {}".format(request.param.__name__))
    return result
