# -*- coding: utf-8 -*-

import argparse
import createrepo_c as cr
import gi
import logging
import os
import sys
import hawkey
from dnf.subject import Subject


gi.require_version('Modulemd', '2.0')
from gi.repository import Modulemd  # noqa: E402


DEFAULT_PROFILE = 'everything'


def parse_repodata(path):
    """
    Return a list of packages included in this repository
    """
    try:
        repomd = cr.Repomd(os.path.join(path, "repodata/repomd.xml"))
    except OSError as e:
        logging.error(e)
        exit(2)

    for record in repomd.records:
        if record.type == "primary":
            primary_xml_path = record.location_href

    def warningcb(warning_type, message):
        """Optional callback for warnings about
        wierd stuff and formatting in XML.
        :param warning_type: Integer value. One from
                             the XML_WARNING_* constants.
        :param message: String message.
        """
        logging.warning("PARSER WARNING: %s" % message)
        return True

    packages = []

    def pkgcb(pkg):
        # Called when whole package entry in xml is parsed
        packages.append(pkg)

    cr.xml_parse_primary(os.path.join(path, primary_xml_path),
                         pkgcb=pkgcb,
                         do_files=False,
                         warningcb=warningcb)

    return packages


def get_source_packages(packages):
    """
    Return the unique set of source package names
    """
    source_packages = set()
    for pkg in packages:
        # Get the source RPM NEVRA without the trailing ".rpm"
        subject = Subject(pkg.rpm_sourcerpm[:-4])

        # Now get just the source RPM name
        nevras = subject.get_nevra_possibilities(forms=[hawkey.FORM_NEVRA])
        for nevra in nevras:
            source_packages.add(nevra.name)

    return source_packages

def get_arg_parser():
    description = ("Generates modules.yaml file with a module, "
                   "that provides all RPM packages that are available "
                   "within a repository.")
    parser = argparse.ArgumentParser("repo2module", description=description)

    debug = parser.add_mutually_exclusive_group()
    debug.add_argument("--debug", action="store_true", default=False)
    debug.add_argument("--nodebug", action="store_false", dest="debug")

    parser.add_argument("-n", "--module-name",
                        default=os.path.basename(os.environ.get("PWD")),
                        help="Default is the current directory name")
    parser.add_argument("-s", "--module-stream", default="rolling")
    parser.add_argument("-v", "--module-version", default=1, type=int)
    parser.add_argument("-c", "--module-context", default="abcdef12")
    parser.add_argument("-O", "--to-stdout", default=False, action="store_true")
    parser.add_argument("repo_path")
    parser.add_argument("modules_yaml", default="modules.yaml", nargs="?")
    return parser


def cli():
    parser = get_arg_parser()
    args = parser.parse_args()

    if args.debug:
        logging.basicConfig(level=logging.DEBUG)

    if not os.path.isdir(args.repo_path):
        logging.error("No such directory: {0}".format(args.repo_path))
        exit(1)

    abs_repo_path = os.path.abspath(args.repo_path)
    if not args.to_stdout:
        abs_modules_yaml = os.path.abspath(args.modules_yaml)

    packages = parse_repodata(abs_repo_path)

    # Create module stream framework
    stream = Modulemd.ModuleStreamV2.new(args.module_name, args.module_stream)
    stream.set_version(args.module_version)
    stream.set_context(args.module_context)
    stream.set_summary('<auto-generated module summary>')
    stream.set_description('<auto-generated module description>')
    stream.add_module_license("MIT")
    stream.add_content_license("<FILL THIS IN>")

    source_packages = get_source_packages(packages)

    for srcpkg in source_packages:
        component = Modulemd.ComponentRpm.new(srcpkg)
        component.set_rationale('Present in the repository')
        stream.add_component(component)

    common_profile = Modulemd.Profile.new(DEFAULT_PROFILE)

    for pkg in packages:
        stream.add_rpm_artifact(pkg.nevra())
        stream.add_rpm_api(pkg.name)
        common_profile.add_rpm(pkg.name)

    stream.add_profile(common_profile)

    # Add defaults for this module
    defaults = Modulemd.DefaultsV1.new(args.module_name)
    defaults.set_default_stream(args.module_stream)
    defaults.add_default_profile_for_stream(args.module_stream, DEFAULT_PROFILE)

    index = Modulemd.ModuleIndex.new()
    index.add_module_stream(stream)
    index.add_defaults(defaults)

    if args.to_stdout:
        sys.stdout.write(index.dump_to_string())
        return

    logging.debug("Writing YAML to {}".format(abs_modules_yaml))
    try:
        with open(abs_modules_yaml, 'w') as output:
            output.write(index.dump_to_string())
    except PermissionError as e:
        logging.error("Could not write YAML to file: {}".format(e))
        exit(3)


if __name__ == "__main__":
    cli()
