# -*- coding: utf-8 -*-
"""
Decides if vendor bundles are used or not.
Setup python path accordingly.
"""

from __future__ import absolute_import, print_function
import os.path
import sys

# -----------------------------------------------------------------------------
# DEFINES:
# -----------------------------------------------------------------------------
HERE = os.path.dirname(__file__)
TASKS_VENDOR_DIR = os.path.join(HERE, "_vendor")
INVOKE_BUNDLE = os.path.join(TASKS_VENDOR_DIR, "invoke.zip")
INVOKE_BUNDLE_VERSION = "1.2.0"

DEBUG_SYSPATH = False


# -----------------------------------------------------------------------------
# EXCEPTIONS:
# -----------------------------------------------------------------------------
class VersionRequirementError(SystemExit):
    pass


# -----------------------------------------------------------------------------
# FUNCTIONS:
# -----------------------------------------------------------------------------
def setup_path(invoke_minversion=None):
    """Setup python search and add ``TASKS_VENDOR_DIR`` (if available)."""
    # print("INVOKE.tasks: setup_path")
    if not os.path.isdir(TASKS_VENDOR_DIR):
        print("SKIP: TASKS_VENDOR_DIR=%s is missing" % TASKS_VENDOR_DIR)
        return
    elif os.path.abspath(TASKS_VENDOR_DIR) in sys.path:
        # -- SETUP ALREADY DONE:
        # return
        pass

    use_vendor_bundles = os.environ.get("INVOKE_TASKS_USE_VENDOR_BUNDLES", "no")
    if need_vendor_bundles(invoke_minversion):
        use_vendor_bundles = "yes"

    if use_vendor_bundles == "yes":
        syspath_insert(0, os.path.abspath(TASKS_VENDOR_DIR))
        if setup_path_for_bundle(INVOKE_BUNDLE, pos=1):
            import invoke
            bundle_path = os.path.relpath(INVOKE_BUNDLE, os.getcwd())
            print("USING: %s (version: %s)" % (bundle_path, invoke.__version__))
    else:
        # -- BEST-EFFORT: May rescue something
        syspath_append(os.path.abspath(TASKS_VENDOR_DIR))
        setup_path_for_bundle(INVOKE_BUNDLE, pos=len(sys.path))

    if DEBUG_SYSPATH:
        for index, p in enumerate(sys.path):
            print("  %d.  %s" % (index, p))


def require_invoke_minversion(min_version, verbose=False):
    """Ensures that :mod:`invoke` has at the least the :param:`min_version`.
    Otherwise,

    :param min_version: Minimal acceptable invoke version (as string).
    :param verbose:     Indicates if invoke.version should be shown.
    :raises: VersionRequirementError=SystemExit if requirement fails.
    """
    # -- REQUIRES: sys.path is setup and contains invoke
    try:
        import invoke
        invoke_version = invoke.__version__
    except ImportError:
        invoke_version = "__NOT_INSTALLED"

    if invoke_version < min_version:
        message = "REQUIRE: invoke.version >= %s (but was: %s)" % \
                  (min_version, invoke_version)
        message += "\nUSE: pip install invoke>=%s" % min_version
        raise VersionRequirementError(message)

    # pylint: disable=invalid-name
    INVOKE_VERSION = os.environ.get("INVOKE_VERSION", None)
    if verbose and not INVOKE_VERSION:
        os.environ["INVOKE_VERSION"] = invoke_version
        print("USING: invoke.version=%s" % invoke_version)


def need_vendor_bundles(invoke_minversion=None):
    invoke_minversion = invoke_minversion or "0.0.0"
    need_vendor_answers = []
    need_vendor_answers.append(need_vendor_bundle_invoke(invoke_minversion))
    # -- REQUIRE: path.py
    try:
        import path
        need_bundle = False
    except ImportError:
        need_bundle = True
    need_vendor_answers.append(need_bundle)

    # -- DIAG: print("INVOKE: need_bundle=%s" % need_bundle1)
    # return need_bundle1 or need_bundle2
    return any(need_vendor_answers)


def need_vendor_bundle_invoke(invoke_minversion="0.0.0"):
    # -- REQUIRE: invoke
    try:
        import invoke
        need_bundle = invoke.__version__ < invoke_minversion
        if need_bundle:
            del sys.modules["invoke"]
            del invoke
    except ImportError:
        need_bundle = True
    except Exception:   # pylint: disable=broad-except
        need_bundle = True
    return need_bundle


# -----------------------------------------------------------------------------
# UTILITY FUNCTIONS:
# -----------------------------------------------------------------------------
def setup_path_for_bundle(bundle_path, pos=0):
    if os.path.exists(bundle_path):
        syspath_insert(pos, os.path.abspath(bundle_path))
        return True
    return False


def syspath_insert(pos, path):
    if path in sys.path:
        sys.path.remove(path)
    sys.path.insert(pos, path)


def syspath_append(path):
    if path in sys.path:
        sys.path.remove(path)
    sys.path.append(path)

