"""
Produce a lockfile for the prepared buildroot by Mock.  Once available, we
should use the DNF built-in command from DNF5:
https://github.com/rpm-software-management/dnf5/issues/833
"""

import json
import os

from mockbuild.podman import Podman, PodmanError
from mockbuild.installed_packages import query_packages, query_packages_location

requires_api_version = "1.1"


def init(plugins, conf, buildroot):
    """ The obligatory plugin entry point """
    BuildrootLockfile(plugins, conf, buildroot)


class BuildrootLockfile:
    """ Produces buildroot_lock.json file in resultdir """
    def __init__(self, plugins, conf, buildroot):
        self.buildroot = buildroot
        self.state = buildroot.state
        self.conf = conf
        self.inst_done = False
        plugins.add_hook("postdeps", self.produce_lockfile)

    def produce_lockfile(self):
        """
        Upon a request ('produce_lockfile' option set True), generate
        the mock-build-environment.json file in resultdir.  The file describes
        the Mock build environment, and the way to reproduce it.
        """

        filename = "buildroot_lock.json"
        statename = "Generating the buildroot lockfile: " + filename
        try:
            with self.buildroot.uid_manager:
                self.state.start(statename)
                out_file = os.path.join(self.buildroot.resultdir, filename)
                chrootpath = self.buildroot.make_chroot_path()

                # Ḿimic the Koji Content Generator metadata fields:
                # https://docs.pagure.org/koji/content_generator_metadata/#buildroots
                #
                # The query_packages() method below sorts its output according
                # to _values_ of the queried RPM headers, so keep name-arch pair
                # first to have the output sorted reasonably.
                query_fields = ["name", "arch", "license", "version", "release",
                                "epoch", "sigmd5", "signature"]

                def _executor(cmd):
                    with self.buildroot.uid_manager.elevated_privileges():
                        out, _ = self.buildroot.doOutChroot(cmd,
                                                            returnOutput=True,
                                                            returnStderr=False)
                        return out

                packages = query_packages(query_fields, chrootpath, _executor)
                query_packages_location(packages, chrootpath, _executor,
                                        dnf_cmd=self.buildroot.pkg_manager.command)

                data = {
                    # Try to semver.  The future Mock versions (the tool) should
                    # be able to read older Minor versions of the same Major.
                    # Anytime we break this assumption, bump the Major.  IOW,
                    # the latest Mock implementing with Major == 1 can read any
                    # version from the 1.Y.Z range.  Mock implementing v2.Y.Z
                    # no longer reads v1.Y.Z variants.
                    "version": "1.1.0",
                    "buildroot": {
                        "rpms": packages,
                    },
                    # Try to keep this as minimal as possible.  If possible,
                    # implement the config options as DEFAULTS in the
                    # hermetic-build.cfg, or in the
                    # process_hermetic_build_config() method.
                    "config": {}
                }
                for cfg_option in [
                    # These are hard-coded in the configuration file, but we
                    # work with a single-config-for-all-arches now.
                    "target_arch",
                    "legal_host_arches",
                    "dist",
                    "package_manager",
                    # At this point, we only support hermetic builds iff
                    # bootstrap_image_ready=True, so these two options are
                    # useful for implementing "assertion" in the
                    # process_hermetic_build_config() method.
                    "bootstrap_image",
                    "bootstrap_image_ready",
                    # Macros need to be inherited, e.g., to keep the original
                    # %vendor tag specification, or %_host_cpu hacks.
                    "macros",
                ]:
                    if cfg_option in self.buildroot.config:
                        data["config"][cfg_option] = self.buildroot.config[cfg_option]

                # The 'bootstrap' field is omitted when 'use_bootstrap_image'
                # is False.  Consequently, we cannot perform a subsequent
                # hermetic build using this lockfile.
                if self.buildroot.config["use_bootstrap_image"]:
                    with self.buildroot.uid_manager.elevated_privileges():
                        try:
                            podman = Podman(self.buildroot,
                                            data["config"]["bootstrap_image"])
                            data["bootstrap"] = podman.inspect_hermetic_metadata()
                            data["bootstrap"]["image_digest"] = podman.get_oci_digest()
                        except PodmanError:
                            data["bootstrap"] = {}

                with open(out_file, "w", encoding="utf-8") as fdlist:
                    fdlist.write(json.dumps(data, indent=4, sort_keys=True) + "\n")
        finally:
            self.state.finish(statename)
