# Copyright (C) 2012 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
# Attempt to move any conda entries in PATH to the front of it.
# IDEs have their own ideas about how PATH should be managed and
# they do dumb stuff like add /usr/bin to the front of it
# meaning conda takes a submissive role and the wrong stuff
# runs (when other conda prefixes get activated they replace
# the wrongly placed entries with newer wrongly placed entries).
#
# Note, there's still condabin to worry about here, and also should
# we not remove all traces of conda instead of just this fixup?
# Ideally we'd have two modes, 'removed' and 'fixed'. I have seen
# condabin come from an entirely different installation than
# CONDA_PREFIX too in some instances and that really needs fixing.

import os
import sys
import warnings
from os.path import dirname, isfile, join, normpath
from pathlib import Path
from subprocess import check_output

from conda.common.compat import on_win


def encode_for_env_var(value) -> str:
    """Environment names and values need to be string."""
    if isinstance(value, str):
        return value
    elif isinstance(value, bytes):
        return value.decode()
    return str(value)


def conda_ensure_sys_python_is_base_env_python():
    # Exit if we try to run tests from a non-base env. The tests end up installing
    # menuinst into the env they are called with and that breaks non-base env activation
    # as it emits a message to stderr:
    # WARNING menuinst_win32:<module>(157): menuinst called from non-root env
    # C:\opt\conda\envs\py27
    # So lets just sys.exit on that.

    if "CONDA_PYTHON_EXE" in os.environ:
        if Path(os.environ["CONDA_PYTHON_EXE"]).resolve() != Path(sys.executable).resolve():
            warnings.warn(
                "ERROR :: Running tests from a non-base Python interpreter. "
                " Tests requires installing menuinst and that causes stderr "
                " output when activated.\n"
                f"- CONDA_PYTHON_EXE={os.environ['CONDA_PYTHON_EXE']}\n"
                f"- sys.executable={sys.executable}"
            )

            # menuinst only really matters on windows
            if on_win:
                sys.exit(-1)


def conda_move_to_front_of_PATH():
    if 'CONDA_PREFIX' in os.environ:
        from conda.activate import CmdExeActivator, PosixActivator
        if os.name == 'nt':
            activator_cls = CmdExeActivator
        else:
            activator_cls = PosixActivator
        activator = activator_cls()
        # But why not just use _replace_prefix_in_path? => because moving
        # the entries to the front of PATH is the goal here, not swapping
        # x for x (which would be pointless anyway).
        p = None
        # It might be nice to have a parameterised fixture with choices of:
        # 'System default PATH',
        # 'IDE default PATH',
        # 'Fully activated conda',
        # 'PATHly activated conda'
        # This will do for now => Note, if you have conda activated multiple
        # times it could mask some test failures but _remove_prefix_from_path
        # cannot be used multiple times; it will only remove *one* conda
        # prefix from the *original* value of PATH, calling it N times will
        # just return the same value every time, even if you update PATH.
        p = activator._remove_prefix_from_path(os.environ['CONDA_PREFIX'])

        # Replace any non sys.prefix condabin with sys.prefix condabin
        new_p = []
        found_condabin = False
        for pe in p:
            if pe.endswith('condabin'):
                if not found_condabin:
                    found_condabin = True
                    if join(sys.prefix, 'condabin') != pe:
                        condabin_path = join(sys.prefix, 'condabin')
                        print(f"Incorrect condabin, swapping {pe} to {condabin_path}")
                        new_p.append(condabin_path)
                    else:
                        new_p.append(pe)
            else:
                new_p.append(pe)

        new_path = os.pathsep.join(new_p)
        new_path = encode_for_env_var(new_path)
        os.environ['PATH'] = new_path
        activator = activator_cls()
        p = activator._add_prefix_to_path(os.environ['CONDA_PREFIX'])
        new_path = os.pathsep.join(p)
        new_path = encode_for_env_var(new_path)
        os.environ['PATH'] = new_path


def conda_check_versions_aligned():
    # Next problem. If we use conda to provide our git or otherwise do not
    # have it on PATH and if we also have no .version file then conda is
    # unable to figure out its version without throwing an exception. The
    # tests this broke most badly (test_activate.py) have a workaround of
    # installing git into one of the conda prefixes that gets used but it
    # is slow. Instead write .version if it does not exist, and also fix
    # it if it disagrees.

    import conda
    version_file = normpath(join(dirname(conda.__file__), '.version'))
    if isfile(version_file):
        version_from_file = open(version_file).read().split("\n")[0]
    else:
        version_from_file = None

    git_exe = 'git.exe' if sys.platform == 'win32' else 'git'
    version_from_git = None
    for pe in os.environ.get('PATH', '').split(os.pathsep):
        if isfile(join(pe, git_exe)):
            try:
                cmd = join(pe, git_exe) + ' describe --tags --long'
                version_from_git = check_output(cmd).decode('utf-8').split('\n')[0]
                from conda.auxlib.packaging import _get_version_from_git_tag
                version_from_git = _get_version_from_git_tag(version_from_git)
                break
            except:
                continue
    if not version_from_git:
        print("WARNING :: Could not check versions.")

    if version_from_git and version_from_git != version_from_file:
        print("WARNING :: conda/.version ({}) and git describe ({}) "
              "disagree, rewriting .version".format(version_from_git, version_from_file))
        with open(version_file, 'w') as fh:
            fh.write(version_from_git)
