import os
import re
import sys
import json

from .constants import BASE_DIR
try:
    from importlib.metadata import version
    importlib = True
    ImportNotFound = BaseException
except ImportError:
    importlib = False
    version = None

if not importlib:
    try:
        import pkg_resources
        from pkg_resources import DistributionNotFound as ImportNotFound
        pkgresources = True
    except ImportError as e:
        pkgresources = False


def load_dependencies(optional=False):
    deps = list()
    if getattr(sys, 'frozen', False):
        pip_installed = os.path.join(BASE_DIR, ".pip_installed")
        if os.path.exists(pip_installed):
            with open(pip_installed) as f:
                exe_deps = json.loads("".join(f.readlines()))
        else:
            return deps
    if importlib or pkgresources:
        if optional:
            req_path = os.path.join(BASE_DIR, "optional-requirements.txt")
        else:
            req_path = os.path.join(BASE_DIR, "requirements.txt")
        if os.path.exists(req_path):
            with open(req_path, 'r') as f:
                for line in f:
                    if not line.startswith('#') and not line == '\n' and not line.startswith('git'):
                        res = re.match(r'(.*?)([<=>\s]+)([\d\.]+),?\s?([<=>\s]+)?([\d\.]+)?(?:\s?;\s?'
                                       r'(?:(python_version)\s?([<=>]+)\s?\'([\d\.]+)\'|'
                                       r'(sys_platform)\s?([\!=]+)\s?\'([\w]+)\'))?', line.strip())
                        try:
                            if res.group(7) and res.group(8):
                                val = res.group(8).split(".")
                                if not eval(str(sys.version_info[0]) + "." + "{:02d}".format(sys.version_info[1]) +
                                            res.group(7) + val[0] + "." + "{:02d}".format(int(val[1]))):
                                    continue
                            elif res.group(10) and res.group(11):
                                # only installed if platform is eqal, don't check if platform is not equal
                                if res.group(10) == "==":
                                    if sys.platform != res.group(11):
                                        continue
                                # installed if platform is not eqal, don't check if platform is equal
                                elif res.group(10) == "!=":
                                    if sys.platform == res.group(11):
                                        continue
                            if getattr(sys, 'frozen', False):
                                dep_version = exe_deps[res.group(1).lower().replace('_', '-')]
                            else:
                                if importlib:
                                    dep_version = version(res.group(1))
                                else:
                                    dep_version = pkg_resources.get_distribution(res.group(1)).version
                        except (ImportNotFound, KeyError):
                            if optional:
                                continue
                            dep_version = "not installed"
                        deps.append([dep_version, res.group(1), res.group(2), res.group(3), res.group(4), res.group(5)])
    return deps


def dependency_check(optional=False):
    d = list()
    dep_version_int = None
    low_check = None
    deps = load_dependencies(optional)
    for dep in deps:
        try:
            dep_version_int = [int(x) if x.isnumeric() else 0 for x in dep[0].split('.')[:3]]
            low_check = [int(x) for x in dep[3].split('.')]
            high_check = [int(x) for x in dep[5].split('.')]
        except AttributeError:
            high_check = []
        except ValueError:
            d.append({'name': dep[1],
                      'target': "available",
                      'found': "Not available"
                      })
            continue

        if dep[2].strip() == "==":
            if dep_version_int != low_check:
                d.append({'name': dep[1],
                          'found': dep[0],
                          "target": dep[2] + dep[3]})
                continue
        elif dep[2].strip() == ">=":
            if dep_version_int < low_check:
                d.append({'name': dep[1],
                          'found': dep[0],
                          "target": dep[2] + dep[3]})
                continue
        elif dep[2].strip() == ">":
            if dep_version_int <= low_check:
                d.append({'name': dep[1],
                          'found': dep[0],
                          "target": dep[2] + dep[3]})
                continue
        if dep[4] and dep[5]:
            if dep[4].strip() == "<":
                if dep_version_int >= high_check:
                    d.append(
                        {'name': dep[1],
                         'found': dep[0],
                         "target": dep[4] + dep[5]})
                    continue
            elif dep[4].strip() == "<=":
                if dep_version_int > high_check:
                    d.append(
                        {'name': dep[1],
                         'found': dep[0],
                         "target": dep[4] + dep[5]})
                    continue
    return d
