import os

import tox
import tox.venv


# This will store the pip version specified for each testenv
PER_ENV_PIP_VERSIONS = {}

TOX_PIP_VERSION_VAR = "TOX_PIP_VERSION"


def _testenv_create(venv, action):
    # For compatibility with the tox-venv and tox-conda plugins:
    #
    # 1. Detect if tox-venv is installed and invoke if so.
    # 2. Else, detect if tox-conda is installed and invoke if so
    # 3. Else, neither is installed, so proceed as normal
    #
    # We use `tryfirst=True` on our hookimpl to run before tox-venv does (no
    # plugins run after a plugin returns non-None from its hook function)
    try:
        from tox_venv.hooks import tox_testenv_create

        # tox-venv may not create the venv (like if the venv is python 2)
        if tox_testenv_create(venv, action):
            return
    except ImportError:
        pass

    try:
        from tox_conda.plugin import tox_testenv_create
        if tox_testenv_create(venv, action):
            return
    except ImportError:
        pass

    tox.venv.tox_testenv_create(venv, action)


def get_pip_package_version(pip_version):
    pip_version = pip_version.lower().strip()
    # tox.ini: pip_version = pip==19.0
    if pip_version.startswith('pip'):
        return pip_version
    # tox.ini: pip_version = 19.0
    return 'pip==%s' % pip_version


@tox.hookimpl
def tox_configure(config):
    for env, envconfig in config.envconfigs.items():
        pip_version = envconfig._reader.getstring("pip_version")
        if pip_version:
            PER_ENV_PIP_VERSIONS[env] = pip_version


@tox.hookimpl(tryfirst=True)
def tox_testenv_create(venv, action):
    _testenv_create(venv, action)

    # Grab the env this way to respect `setenv = TOX_PIP_VERSION`, if present.
    # But, fallback to the process-level environment if not present in `setenv`
    env = venv._get_os_environ()
    tox_pip_version_from_env = env.get(
        TOX_PIP_VERSION_VAR, os.getenv(TOX_PIP_VERSION_VAR)
    )

    # action.venvname is 'py36', for example.
    #
    # tox 3.8 changed action.venvname -> action.name, and removed action.id
    try:
        venvname = action.venvname
    except AttributeError:
        venvname = action.name

    # Use `pip_version` in tox.ini over the environment variable
    pip_version = PER_ENV_PIP_VERSIONS.get(venvname, tox_pip_version_from_env)
    if pip_version:
        package = get_pip_package_version(pip_version)

        # Is there a way to output this better? Genuine tox commands show up
        # colorized (as bold white text)...
        print("%s: pip_version is %s" % (venvname, package))

        # "private" _install method - unstable interface?
        venv._install([package], extraopts=["-U"], action=action)
    return True
