#
from distutils.sysconfig import get_python_lib
import os
import inspect
import argparse
import re
import pkg_resources
import sys
import ctypes

sys_path_build = """# Auto generated by gaenv
import sys
import os
sys.path.insert(0, os.path.dirname(__file__))"""


def create_symlink(source, link_name):
    os_symlink = getattr(os, "symlink", None)
    if callable(os_symlink):
        os_symlink(source, link_name)
    else:
        csl = ctypes.windll.kernel32.CreateSymbolicLinkW
        csl.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32)
        csl.restype = ctypes.c_ubyte
        flags = 1 if os.path.isdir(source) else 0
        if csl(link_name, source, flags) == 0:
            raise ctypes.WinError()


def main():
    parser = argparse.ArgumentParser(description='Command line utility for managing appengine thirdparty packages')
    parser.add_argument('--requirements', type=str, default='requirements.txt',
                        help='specify the requirements file default(requirements.txt)')
    parser.add_argument('--lib', type=str, default='gaenv_lib',
                        help='change the output dir, default is gaenv_lib')
    parser.add_argument('--no-import', action='store_true',
                        help='will not add import statement on appengine_config.py')
    args = parser.parse_args()

    # Build requirements path & check for existence
    current_path = os.getcwd()
    requirement_path = os.path.join(current_path, args.requirements)
    if not os.path.exists(requirement_path):
        print 'requirements file %s not found' % requirement_path
        exit(0)

    with open(requirement_path, 'r') as file:
        requirements = file.readlines()
        pypi_requirements = []
        cvs_requirements = []
        for requirement in requirements:
            if requirement.find('+') == -1:
                pypi_requirements.append(requirement.strip())
            else:
                cvs_requirements.append(requirement.strip())
        requirements = [req for req in pkg_resources.parse_requirements(os.linesep.join(pypi_requirements))]

    # todo temp fix until https://github.com/pypa/pip/issues/1083 issue is fixed
    if cvs_requirements:
        for requirement in cvs_requirements:
            egg = re.findall('egg=([^&]+)', requirement)
            if egg:
                try:
                    requirements.append(pkg_resources.get_distribution(egg.pop()))
                except pkg_resources.DistributionNotFound:
                    print 'Please install [%s]' % requirement
    # end repo temp fix

    links = []
    package_path = get_python_lib()
    for requirement in requirements:
        try:
            if isinstance(requirement, pkg_resources.Distribution):
                dist = requirement
            else:
                dist = pkg_resources.get_provider(requirement)
        except pkg_resources.DistributionNotFound:
            print 'Please install [%s]' % requirement
            continue
        except pkg_resources.VersionConflict:
            print 'Version don\'t match [%s] - create virtualenv or match the version' % requirement
            continue

        if dist.has_metadata('top_level.txt'):
            links.extend(dist.get_metadata_lines('top_level.txt'))

        if dist.has_metadata('dependency_links.txt'):
            links.extend(dist.get_metadata_lines('dependency_links.txt'))

    # Now we create the links
    if links:
        libs = os.path.join(current_path, args.lib)
        if not os.path.exists(libs):
            os.makedirs(libs)
        else:
            # delete contents
            for f in os.listdir(libs):
                os.unlink(os.path.join(libs, f))

        with open(os.path.join(libs, '__init__.py'), 'wb') as f:
            f.write(sys_path_build)

        for link in links:
            link = link.strip()
            symlink = os.path.join(package_path, link)
            if not os.path.exists(symlink) and os.path.exists(symlink + '.py'):
                symlink += '.py'
                dest = os.path.join(libs, link + '.py')
            else:
                dest = os.path.join(libs, link)

            if os.path.exists(symlink) and not os.path.exists(dest):
                create_symlink(symlink, dest)

            print 'Linked: {}'.format(link)

        if not args.no_import:
            appengine_config = os.path.join(current_path, 'appengine_config.py')
            if not os.path.exists(appengine_config):
                print 'Created {}'.format(appengine_config)
                source_code = ''
            else:
                print 'Updated {}'.format(appengine_config)
                with open(appengine_config, 'r') as f:
                    source_code = f.read()

            # Replace if there is no import
            import_statement = 'import {}'.format(args.lib)
            if import_statement not in source_code:
                with open(appengine_config, 'wb') as f:
                    f.write(import_statement + '\n' + source_code)
                    print 'Added [{}] in [{}]'.format(import_statement, appengine_config)
            else:
                print 'Skipped import on [{}] exists'.format(appengine_config)


if __name__ == "__main__":
    main()