# -*- coding=utf-8 -*-
from __future__ import print_function, absolute_import
import os
import six
import operator
from .models import SystemPath


class Finder(object):
    def __init__(self, path=None, system=False, global_search=True, ignore_unsupported=False):
        """Finder A cross-platform Finder for locating python and other executables.

        Searches for python and other specified binaries starting in `path`, if supplied,
        but searching the bin path of `sys.executable` if `system=True`, and then
        searching in the `os.environ['PATH']` if `global_search=True`.  When `global_search`
        is `False`, this search operation is restricted to the allowed locations of 
        `path` and `system`.

        :param path: A bin-directory search location, defaults to None
        :param path: str, optional
        :param system: Whether to include the bin-dir of `sys.executable`, defaults to False
        :param system: bool, optional
        :param global_search: Whether to search the global path from os.environ, defaults to True
        :param global_search: bool, optional
        :param ignore_unsupported: Whether to ignore unsupported python versions, if False, an error is raised, defaults to True
        :param ignore_unsupported: bool, optional
        :returns: a :class:`~pythonfinder.pythonfinder.Finder` object.
        """

        self.path_prepend = path
        self.global_search = global_search
        self.system = system
        self.ignore_unsupported = ignore_unsupported
        self._system_path = None
        self._windows_finder = None

    @property
    def system_path(self):
        if not self._system_path:
            self._system_path = SystemPath.create(
                path=self.path_prepend,
                system=self.system,
                global_search=self.global_search,
                ignore_unsupported=self.ignore_unsupported,
            )
        return self._system_path

    @property
    def windows_finder(self):
        if os.name == "nt" and not self._windows_finder:
            from .models import WindowsFinder

            self._windows_finder = WindowsFinder()
        return self._windows_finder

    def which(self, exe):
        return self.system_path.which(exe)

    def find_python_version(
        self, major, minor=None, patch=None, pre=None, dev=None, arch=None
    ):
        from .models import PythonVersion

        if (
            isinstance(major, six.string_types)
            and pre is None
            and minor is None
            and dev is None
            and patch is None
        ):
            if arch is None and "-" in major:
                major, arch = major.rsplit("-", 1)
                if not arch.isdigit():
                    major = "{0}-{1}".format(major, arch)
                else:
                    arch = "{0}bit".format(arch)
            version_dict = PythonVersion.parse(major)
            major = version_dict.get("major", major)
            minor = version_dict.get("minor", minor)
            patch = version_dict.get("patch", patch)
            pre = version_dict.get("is_prerelease", pre) if pre is None else pre
            dev = version_dict.get("is_devrelease", dev) if dev is None else dev
            arch = version_dict.get("architecture", arch) if arch is None else arch
        if os.name == "nt":
            match = self.windows_finder.find_python_version(
                major, minor=minor, patch=patch, pre=pre, dev=dev, arch=arch
            )
            if match:
                return match
        return self.system_path.find_python_version(
            major=major, minor=minor, patch=patch, pre=pre, dev=dev, arch=arch
        )

    def find_all_python_versions(
        self, major=None, minor=None, patch=None, pre=None, dev=None, arch=None
    ):
        version_sort = operator.attrgetter("as_python.version_sort")
        python_version_dict = getattr(self.system_path, "python_version_dict")
        if python_version_dict:
            paths = filter(
                None,
                [
                    path
                    for version in python_version_dict.values()
                    for path in version
                    if path.as_python
                ],
            )
            paths = sorted(paths, key=version_sort, reverse=True)
            return paths
        versions = self.system_path.find_all_python_versions(
            major=major, minor=minor, patch=patch, pre=pre, dev=dev, arch=arch
        )
        if not isinstance(versions, list):
            versions = [versions]
        paths = sorted(versions, key=version_sort, reverse=True)
        path_map = {}
        for path in paths:
            try:
                resolved_path = path.path.resolve()
            except OSError:
                resolved_path = path.path.absolute()
            if not path_map.get(resolved_path.as_posix()):
                path_map[resolved_path.as_posix()] = path
        return list(path_map.values())