import os
import platform
import subprocess
import shutil
from pathlib import Path
from setuptools import setup, Extension, find_packages
from setuptools.command.build_ext import build_ext


# ---- PROJECT SETTING ---------- #
PROJECT = "timp_pcbcam"
LIBNAME = "libpcbcam"
VERSION = "1.0.0"
DESCRIPTION = "timp_pcbcam lib"
# 要编译的版本[5|6]
BUILD_QT_VERSION = 5
if BUILD_QT_VERSION == 5:
    # Qt 5.15.2
    PYSIDE = 'PySide2'
    SHIBOKEN = 'shiboken2'
    SHIBOKEN_GENERATOR = 'shiboken2_generator'
    QT_DIR_ENV = 'QT5_DIR'
elif BUILD_QT_VERSION == 6:
    PROJECT = "timp_pcbcam_qt6"
    # Qt 6.2.1
    PYSIDE = 'PySide6'
    SHIBOKEN = 'shiboken6'
    SHIBOKEN_GENERATOR = 'shiboken6_generator'
# ---- END OF PROJECT SETTING ----#


class CMakeExtension(Extension):
    """ CMake编译扩展类 """

    def __init__(self, name: str, libname: str = "", sourcedir: str = ""):
        Extension.__init__(self, name, sources=[])
        self.libname = libname
        self.sourcedir = os.path.abspath(sourcedir)


class CMakeBuild(build_ext):
    """ CMake编译方法类 """

    def build_extension(self, ext):
        # setuptools 打包文件时创建的临时路径
        py_build_dir = Path(os.path.abspath(self.build_lib))
        py_build_dir = py_build_dir.joinpath(ext.name)

        # c++源码所在路径,在不同系统下使用不同的编译目录
        build_temp = Path(ext.sourcedir).joinpath('build-' + platform.system())
        if not build_temp.exists():
            os.makedirs(build_temp)

        # 追加QT路径至PATH环境变中, 以便CMake的FindPackage能够找到Qt相关依赖
        qt_dir = self.get_qt_dir()
        qt_bin = os.path.join(qt_dir, "bin")
        path_sep = ';' if platform.system() == "Windows" else ':'
        env_path = qt_bin + path_sep + os.environ.get("PATH")
        os.environ.update(PATH=env_path)

        # Windows下初始化Visual Studio C++编译环境
        self.init_msvc_env()

        # 执行CMake进行编译
        subprocess.check_call('cmake .. -B. -G Ninja -D CMAKE_BUILD_TYPE=Release', cwd=build_temp)
        subprocess.check_call(['ninja'], cwd=build_temp)
        subprocess.check_call(['ninja', 'install'], cwd=build_temp)

        # 拷贝动态库至打包目录
        libray_files = []
        if platform.system() == "Windows":
            libray_files.append("{}.pyd".format(ext.name))
            libray_files.append("{}.dll".format(ext.libname))
        elif platform.system() == "Darwin":
            libray_files.append("{}.so".format(ext.name))
            libray_files.append("lib{}.dylib".format(ext.name))
        else:
            libray_files.append("{}.so".format(ext.name))
            libray_files.append("lib{}.so".format(ext.name))

        print('copying dynamic library file')
        # pak_dir = Path(ext.sourcedir).parent.joinpath(ext.name)
        for lib in libray_files:
            src_file = build_temp.joinpath(lib)
            print(f'copying {src_file} -> {py_build_dir}')
            shutil.copy(src_file, py_build_dir)

    def get_qt_dir(self) -> str:
        """ 获取QT路径 """

        timp_qt_dir = ''
        if QT_DIR_ENV in os.environ:
            timp_qt_dir = os.environ.get(QT_DIR_ENV)
        elif 'TIMP_QT_DIR' in os.environ:
            timp_qt_dir = os.environ.get('TIMP_QT_DIR')
        elif 'QT6_DIR' in os.environ:
            timp_qt_dir = os.environ.get('QT6_DIR')
        elif 'QT_DIR' in os.environ:
            timp_qt_dir = os.environ.get('QT_DIR')

        if not timp_qt_dir:
            raise Exception('Please set TIMP_QT_DIR into environment')

        return timp_qt_dir

    def init_msvc_env(self) -> None:
        """ 初始化Visual Studio C++ 编译环境"""

        if platform.system() != "Windows":
            return

        vcvar = ''
        qt_dir = self.get_qt_dir()
        if 'msvc2015' in qt_dir:
            vcvar = '"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat" amd64'
        elif 'msvc2019' in qt_dir:
            vcvar = '"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat"'

        pipe = os.popen("{0} && {1}".format(vcvar, 'set'))
        output = pipe.read()
        pipe.close()
        env = dict((e[0].upper(), e[1]) for e in [p.rstrip().split("=", 1) for p in output.split('\n')] if len(e) == 2)
        os.environ.update(env)


setup(
    name=PROJECT,
    version=VERSION,
    author="toplinker",
    author_email="service@topibd.com",
    description=DESCRIPTION,
    long_description=DESCRIPTION,
    ext_modules=[CMakeExtension(name=PROJECT, libname=LIBNAME, sourcedir="src/cxx")],
    cmdclass={"build_ext": CMakeBuild},
    package_dir={'': 'src'},
    packages=find_packages(where='src', include=[PROJECT]),
    python_requires='>=3.8',
    install_requires=[
        PYSIDE,
        SHIBOKEN
    ],
    setup_requires=[
        PYSIDE,
        SHIBOKEN,
        SHIBOKEN_GENERATOR
    ],
    tests_require=[],
    extras_require={},
    dependency_links=["http://nexus.topibd.net/repository/pypi-public/simple"],
    zip_safe=False
)
