#! /usr/bin/python3
# SPDX-FileCopyrightText: 2023 Sandro Knauß <hefee@debian.org>
# SPDX-License-Identifier: LGPL-2.1-or-later

#INTROSPECTABLE: CONFIG-FILES pkgfile(qmlfiles) path(debian/qmldeps.overrides) path(debian/qmldeps.optional)

import copy
import logging
import os
import pathlib
import subprocess
import sys
import typing

from debian.debian_support import DpkgArchTable

PKGKDE_GETQMLDEPENDS = "pkgkde-getqmldepends"

sys.path.insert(0,'/usr/share/pkg-kde-tools')
parent_path = pathlib.Path(__file__).parent.absolute()
if parent_path not in ("/usr/bin", "/bin"):
    sys.path.insert(0, str(parent_path))
    PKGKDE_GETQMLDEPENDS = parent_path/"pkgkde-getqmldepends"

from pythonlib import pkgkde
from pythonlib import qmldeps

QT_CONFIGS = qmldeps.get_config()
QT_VERSIONS = {i.qt_name: k for k,i in QT_CONFIGS.items()}

logging.basicConfig(format='%(levelname).1s: %(module)s:%(lineno)d: %(message)s')

log = logging.getLogger()
log.setLevel(logging.INFO)

def qmlfiles_args(pkg_name: str) -> list[str | pathlib.Path]:
    qmlfiles_path = pathlib.Path(f"debian/{pkg_name}.qmlfiles")
    ret = []
    multiarch = qmldeps.deb_host_multiarch()

    replace_args = {
            "${DEB_HOST_MULTIARCH}" : lambda x: multiarch,
            "${QMLDEPS_AUTODETECT_MODULES}": autodetect_modules,
            "${QMLDEPS_AUTODETECT_FILES}": autodetect_files,
            "${QMLDEPS_AUTODETECT_SOURCE_FILES}": autodetect_source_files,
    }

    if qmlfiles_path.exists():
        content = qmlfiles_path.read_text()
        args = content.split()
        for arg in args:
            for test_arg,func in replace_args.items():
                if test_arg == arg:
                    arg = func(pkg_name)
                elif test_arg in arg:
                    arg = arg.replace(test_arg, func(pkg_name))

            if "*" in arg:
                ret.extend(pathlib.Path().glob(arg))
            elif type(arg) == list:
                ret.extend(arg)
            else:
                ret.append(arg)
    return ret

def qt_version_from_files(files: list[str|pathlib.Path]) -> typing.Optional[str]:
    qt_version = None
    for path in files:
        if qt_version:
            break
        if not isinstance(path, pathlib.Path):
            continue
        if not qt_version:
            for p, ver in QT_VERSIONS.items():
                if p in path.parts:
                    qt_version = ver
                    break
    return qt_version

def autodetect_modules(pkg_name: str) -> list[pathlib.Path]:
    """returns a list of all qml module paths shipped within a binary package."""
    return list(p.parent for p in pathlib.Path(f"debian/{pkg_name}").glob("**/qmldir"))

def autodetect_files(pkg_name: str) -> list[pathlib.Path]:
    """returns a list of all qml files shipped within a binnry package."""
    return list(pathlib.Path(f"debian/{pkg_name}").glob("**/*.qml"))

def autodetect_source_files(pkg_name: str) -> list[pathlib.Path]:
    """returns a list of all qml modules that are shipped within the source package and all binary packages.
       This function is mostly usefull for a single binary package mode.
       pkg_name is not used. It needs the same arguments than the other autodetect functions."""
    return list(i for i in pathlib.Path(".").glob("**/*.qml") if "tests/" not in str(i))


def main(command_line_arguments: typing.List[str]):
    control = pkgkde.DebianControl(pathlib.Path("debian/control"))
    single_pkg = control.isSinglePackage()

    failed = False

    getqmldepends_glob_args = command_line_arguments

    arch_any = "-a" in getqmldepends_glob_args
    arch_all = "-i" in getqmldepends_glob_args

    try:
        host_arch = os.environ["DEB_HOST_ARCH"]
    except KeyError:
        host_arch = subprocess.check_output(["dpkg-architecture", "-qDEB_HOST_ARCH"]).strip().decode()

    archtable = DpkgArchTable.load_arch_table()

    if not arch_any and not arch_all:
        arch_any = True
        arch_all = True

    for pkg_name, pkg in control.packages.items():
        archs =  pkg.get("Architecture", "").split()

        skip = True
        if archs == []:
            skip = False
        elif arch_all and "all" in archs:
            skip = False
        elif arch_any and any(archtable.matches_architecture(host_arch, arch) for arch in archs):
            skip = False

        if skip:
            continue

        for qt_version, config_qt in QT_CONFIGS.items():
            var_name = config_qt.substvar_name("Depends")
            var = f"${{{var_name}}}"
            for field in ("Depends", "Recommends", "Suggests"):
                if var in pkg.get(field, ""):
                    break
            else:
                continue
            break
        else:
            qt_version = None

        extra_args = qmlfiles_args(pkg_name)

        if not extra_args:
            if root_path := autodetect_modules(pkg_name):
                extra_args = ["-d", "Depends", "-rootPath"] + root_path

        if not extra_args:
            files = autodetect_files(pkg_name)

            if files:
                examples_files = list(filter(lambda i:"examples" in i.parts, files))
                if examples_files:
                    files = list(filter(lambda i:"examples" not in i.parts, files))
                    extra_args += ["-d", "Recommends", "-qmlFiles"] + examples_files

            elif single_pkg and not files:
                files = autodetect_source_files(pkg_name)

            if files:
                extra_args += ["-d", "Depends", "-qmlFiles"] + files

        if extra_args:
            if not qt_version:
                qt_version = qt_version_from_files(extra_args)
            cmd = copy.copy(getqmldepends_glob_args)

            cmd.extend(["-p", pkg_name])
            if qt_version:
                cmd.extend(["--qt", qt_version])

            cont = True
            start = 0

            while cont:
                try:
                    pos = extra_args.index("-d", start+1)
                    args_part = extra_args[start:pos]
                    start = pos
                except ValueError:
                    args_part=extra_args[start:]
                    cont = False

                if args_part[0] == "-d":
                    _cmd = cmd + args_part[:2] + ["--"] + args_part[2:]
                else:
                    _cmd = cmd + ["--"] + args_part
                log.info(f"Execute {' '.join(str(i) for i in _cmd)}")
                try:
                    qmldeps.main([str(i) for i in _cmd])
                except Exception:
                    failed = True
        elif qt_version:
            log.warning(f"{pkg_name}: No automatic qml files found for package you need to add the files by hand to debian/{pkg_name}.qmlfiles")
        elif single_pkg:
            log.error(f"{pkg_name}: No automatic qml files found for package you need to add the files by hand to debian/{pkg_name}.qmlfiles")
            failed = True

    if failed:
        sys.exit(1)

if __name__ == '__main__':
    main(sys.argv[1:])
