#!/bin/bash
. /usr/share/beakerlib/beakerlib.sh || exit 1
. ../../images.sh || exit 1

function fetch_downloaded_packages () {
    local image="$1"
    local in_subdirectory="$2"

    if [ ! -e $package_cache/tree.rpm ]; then
        # Transform image mode qcow2 URL to a distro compatible container image for artifact download.
        # We want artifacts to come from the same distribution, but using standard fedora container
        # images is enough, they are smaller and rpm compatible with image mode based container images.
        [ "$IMAGE_MODE" = "yes" ] && image=${IMAGE_MODE_QCOW2_CONTAINER_MAP["$image"]}

        # For some reason, this command will get stuck in rlRun...
        container_id="$(podman run -d $image sleep 3600)"

        rlRun "podman exec $container_id bash -c \"set -x; \
                                                    dnf install -y 'dnf-command(download)' \
                                                    && dnf download --destdir /tmp tree diffutils \
                                                    && mv /tmp/tree*.rpm /tmp/tree.rpm \
                                                    && mv /tmp/diffutils*.rpm /tmp/diffutils.rpm\""
        rlRun "podman cp $container_id:/tmp/tree.rpm $package_cache/"
        rlRun "podman cp $container_id:/tmp/diffutils.rpm $package_cache/"
        rlRun "podman kill $container_id"
        rlRun "podman rm $container_id"
    fi

    if [ -z "$in_subdirectory" ]; then
        rlRun "cp $package_cache/tree.rpm ./"
        rlRun "cp $package_cache/diffutils.rpm ./"
    else
        rlRun "mkdir -p ./downloaded-rpms"
        rlRun "cp $package_cache/tree.rpm ./downloaded-rpms"
        rlRun "cp $package_cache/diffutils.rpm ./downloaded-rpms"
    fi
}

rlJournalStart
    rlPhaseStartSetup
        rlRun "PROVISION_HOW=${PROVISION_HOW:-container}"
        rlRun "IMAGE_MODE=${IMAGE_MODE:-no}"

        if [ "$IMAGE_MODE" = "yes" ]; then
            rlRun "IMAGES='$TEST_IMAGE_MODE_IMAGES'"
            rlRun "SECONDARY_IMAGES=''"

        elif [ "$PROVISION_HOW" = "container" ]; then
            rlRun "IMAGES='$TEST_CONTAINER_IMAGES'"
            rlRun "SECONDARY_IMAGES='$TEST_CONTAINER_IMAGES_SECONDARY'"

            build_container_images

        elif [ "$PROVISION_HOW" = "virtual" ]; then
            rlRun "IMAGES='$TEST_VIRTUAL_IMAGES'"
            rlRun "SECONDARY_IMAGES='$TEST_VIRTUAL_IMAGES_SECONDARY'"

        else
            rlRun "IMAGES="
        fi

        rlRun "package_cache=\$(mktemp -d)" 0 "Create cache directory for downloaded packages"
        rlRun "run=\$(mktemp -d -p /var/tmp)" 0 "Create run directory"
        rlRun "pushd data"

        rlRun "export TMT_BOOT_TIMEOUT=300"
        rlRun "export TMT_CONNECT_TIMEOUT=300"
    rlPhaseEnd

    while IFS= read -r image; do
        phase_prefix="$(test_phase_prefix $image)"

        rlPhaseStartTest "$phase_prefix Prepare runtime"
            [ "$PROVISION_HOW" = "container" ] && rlRun "podman images $image"

            if is_fedora_rawhide "$image"; then
                rlRun "distro=fedora-rawhide"
                rlRun "package_manager=dnf5"

            elif is_fedora_eln "$image"; then
                rlRun "distro=fedora-eln"
                rlRun "package_manager=dnf5"

            elif is_fedora_42 "$image"; then
                rlRun "distro=fedora-42"
                rlRun "package_manager=dnf5"

            elif is_fedora_43 "$image"; then
                rlRun "distro=fedora-43"
                rlRun "package_manager=dnf5"

            elif is_centos_stream_9 "$image"; then
                rlRun "distro=centos-stream-9"
                rlRun "package_manager=dnf"

            elif is_centos_stream_10 "$image"; then
                rlRun "distro=centos-stream-10"
                rlRun "package_manager=dnf"

            elif is_centos_7 "$image"; then
                rlRun "distro=centos-7"
                rlRun "package_manager=yum"

            elif is_ubuntu "$image"; then
                rlRun "distro=ubuntu"
                rlRun "package_manager=apt"

            elif is_debian "$image"; then
                rlRun "distro=debian"
                rlRun "package_manager=apt"

            elif is_fedora_coreos "$image"; then
                rlRun "distro=fedora-coreos"

                if is_ostree "$image"; then

                    if [ "$PROVISION_HOW" = "virtual" ]; then
                      rlRun "package_manager=bootc"

                    else
                      rlRun "package_manager=rpm-ostree"

                    fi

                elif [ "$PROVISION_HOW" = "virtual" ]; then
                    rlRun "package_manager=dnf"

                else
                    rlRun "package_manager=dnf5"

                fi

            elif is_ubi_8 "$image"; then
                rlRun "distro=rhel-8"
                rlRun "package_manager=dnf"

            elif is_ubi_9 "$image"; then
                rlRun "distro=rhel-9"
                rlRun "package_manager=dnf"

            elif is_fedora "$image"; then
                rlRun "distro=fedora"
                rlRun "package_manager=dnf5"

            elif is_alpine "$image"; then
                rlRun "distro=alpine"
                rlRun "package_manager=apk"

            else
                rlFail "Cannot infer distro for image $image"
            fi

            if is_image_mode "$image"; then
                rlRun "package_manager=bootc"
            fi

            tmt_run="tmt -vvv -c distro=$distro run --id $run --scratch"
            tmt_steps="cleanup discover provision --how $PROVISION_HOW --image $image prepare"
            tmt="$tmt_run $tmt_steps"
        rlPhaseEnd

        # TODO: find out whether all those exceptions can be simplified and parametrized...

        # TODO: cannot *successfully* install on ubi without subscribing first?
        rlPhaseStartTest "$phase_prefix Install existing packages (plan)"
            rlRun -s "$tmt plan --name /existing"

            rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

            if is_image_mode "$image"; then
                rlAssertGrep "package: building container image with dependencies" $rlRun_LOG
                rlAssertGrep "switching to new image" $rlRun_LOG
                rlAssertGrep "rebooting to apply new image" $rlRun_LOG
            fi

            if is_ubuntu "$image" || is_debian "$image"; then
                # Runs 1 extra phase, to populate local caches.
                rlAssertGrep "summary: 3 preparations applied" $rlRun_LOG
            else
                rlAssertGrep "summary: 2 preparations applied" $rlRun_LOG
            fi
        rlPhaseEnd

        # On image mode, verify packages persist after reboot
        if is_image_mode "$image"; then
            rlPhaseStartTest "$phase_prefix Reboot persistence"
                rlRun -s "$tmt_run --all provision --how $PROVISION_HOW --image $image plan --name /reboot-persistence"

                rlAssertGrep "package: building container image with dependencies" $rlRun_LOG
                rlAssertGrep "switching to new image" $rlRun_LOG
                rlAssertGrep "rebooting to apply new image" $rlRun_LOG

                # should see the tree and diffutils version printed twice (before and after the test reboot)
                rlAssertEquals "Verify tree available after reboot" $(grep "stdout: tree v" $rlRun_LOG | wc -l) 2
                rlAssertEquals "Verify diffutils available after reboot" $(grep "stdout: diff (GNU diffutils)" $rlRun_LOG | wc -l) 2

                rlAssertGrep "total: 1 test passed" $rlRun_LOG
            rlPhaseEnd
        fi

        # Here the basic functionality check ends for the secondary distros.
        if [[ "$SECONDARY_IMAGES" =~ "$image" ]]; then
            continue
        fi

        rlPhaseStartTest "$phase_prefix Install existing packages (CLI)"
            if is_ubi "$image"; then
                rlRun -s "$tmt --insert --how install --package dconf --package libpng plan --name /empty"
            else
                rlRun -s "$tmt --insert --how install --package tree --package diffutils plan --name /empty"
            fi

            rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

            if is_ubuntu "$image" || is_debian "$image"; then
                # Runs 1 extra phase, to populate local caches.
                rlAssertGrep "summary: 3 preparations applied" $rlRun_LOG
            else
                rlAssertGrep "summary: 2 preparations applied" $rlRun_LOG
            fi
        rlPhaseEnd

        # Limit these test cases to:
        # * container provisioner - to save resources, they do not provide additional value with the virtual provisioner
        # * image mode - the code handling is different in this case, so we need to make sure these cases work well
        # * fedora - the tests use rpms
        if ([ "$PROVISION_HOW" = "container" ] || is_image_mode "$image") && is_fedora "$image"; then
            rlPhaseStartTest "$phase_prefix Install downloaded packages from current directory (plan)"
                fetch_downloaded_packages "$image"

                rlRun -s "$tmt plan --name /downloaded/in-cwd"

                rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

                rlAssertGrep "summary: 2 preparations applied" $rlRun_LOG
            rlPhaseEnd

            rlPhaseStartTest "$phase_prefix Install downloaded packages from current directory (CLI)"
                fetch_downloaded_packages "$image"

                rlRun -s "$tmt prepare --insert --how install --package tree*.rpm --package diffutils*.rpm plan --name /empty"

                rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

                rlAssertGrep "summary: 2 preparations applied" $rlRun_LOG
            rlPhaseEnd

            rlPhaseStartTest "$phase_prefix Install downloaded packages from subdirectory (plan)"
                fetch_downloaded_packages "$image" "yes"

                rlRun -s "$tmt plan --name /downloaded/in-subdirectory"

                rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

                rlAssertGrep "summary: 2 preparations applied" $rlRun_LOG
            rlPhaseEnd

            rlPhaseStartTest "$phase_prefix Install downloaded packages from subdirectory (CLI)"
                fetch_downloaded_packages "$image" "yes"

                rlRun -s "$tmt prepare --insert --how install --package downloaded-rpms/tree.rpm --package downloaded-rpms/diffutils.rpm plan --name /empty"

                rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

                rlAssertGrep "summary: 2 preparations applied" $rlRun_LOG
            rlPhaseEnd

            rlPhaseStartTest "$phase_prefix Install downloaded directory (plan)"
                fetch_downloaded_packages "$image" "yes"

                rlRun -s "$tmt plan --name /downloaded/as-directory"

                rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

                rlAssertGrep "summary: 2 preparations applied" $rlRun_LOG
            rlPhaseEnd

            rlPhaseStartTest "$phase_prefix Install downloaded directory (CLI)"
                fetch_downloaded_packages "$image" "yes"

                rlRun -s "$tmt prepare --insert --how install --directory downloaded-rpms plan --name /empty"

                rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

                rlAssertGrep "summary: 2 preparations applied" $rlRun_LOG
            rlPhaseEnd
        fi

        rlPhaseStartTest "$phase_prefix Install existing and invalid packages (plan)"
            rlRun -s "$tmt plan --name /missing" 2

            rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

            if is_centos_7 "$image"; then
                rlAssertGrep "stdout: no package provides tree-but-spelled-wrong" $rlRun_LOG

            elif is_image_mode "$image"; then
                if is_fedora "$image"; then
                    rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG
                else
                    rlAssertGrep "stderr: Error: Unable to find a match: tree-but-spelled-wrong" $rlRun_LOG
                fi

            elif is_ostree "$image"; then
                if [ "$PROVISION_HOW" = "virtual" ]; then
                    rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG
                else
                    rlAssertGrep "stderr: error: Packages not found: tree-but-spelled-wrong" $rlRun_LOG
                fi

            elif is_fedora_coreos "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_fedora_rawhide "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_fedora_eln "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_fedora_43 "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_ubuntu "$image" || is_debian "$image"; then
                rlAssertGrep "stderr: E: Unable to locate package tree-but-spelled-wrong" $rlRun_LOG

            elif is_alpine "$image"; then
                rlAssertGrep "stderr:   tree-but-spelled-wrong (no such package)" $rlRun_LOG

            else
                rlAssertGrep "stderr: Error: Unable to find a match: tree-but-spelled-wrong" $rlRun_LOG
            fi

            rlAssertGrep "Other failed packages:" $rlRun_LOG
            rlAssertGrep "tree-but-spelled-wrong" $rlRun_LOG
        rlPhaseEnd

        rlPhaseStartTest "$phase_prefix Install existing and invalid packages (test)"
            rlRun -s "$tmt plan --name /missing-from-test" 2

            rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

            if is_centos_7 "$image"; then
                rlAssertGrep "stdout: no package provides tree-but-spelled-wrong" $rlRun_LOG

            elif is_image_mode "$image"; then
                if is_fedora "$image"; then
                    rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG
                else
                    rlAssertGrep "stderr: Error: Unable to find a match: tree-but-spelled-wrong" $rlRun_LOG
                fi

            elif is_ostree "$image"; then
                if [ "$PROVISION_HOW" = "virtual" ]; then
                    rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG
                else
                    rlAssertGrep "stderr: error: Packages not found: tree-but-spelled-wrong" $rlRun_LOG
                fi

            elif is_fedora_coreos "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_fedora_rawhide "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_fedora_eln "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_fedora_43 "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_ubuntu "$image" || is_debian "$image"; then
                rlAssertGrep "stderr: E: Unable to locate package tree-but-spelled-wrong" $rlRun_LOG

            elif is_alpine "$image"; then
                rlAssertGrep "stderr:   tree-but-spelled-wrong (no such package)" $rlRun_LOG

            else
                rlAssertGrep "stderr: Error: Unable to find a match: tree-but-spelled-wrong" $rlRun_LOG
            fi

            rlAssertGrep "Required packages failed to install, aborting:" $rlRun_LOG
            rlAssertGrep "tree-but-spelled-wrong: required by: /test-with-invalid-package" $rlRun_LOG
        rlPhaseEnd

        rlPhaseStartTest "$phase_prefix Install existing and invalid packages (CLI)"
            rlRun -s "$tmt --insert --how install --package tree-but-spelled-wrong --package diffutils plan --name /empty" 2

            rlAssertGrep "package manager: $package_manager$" $rlRun_LOG

            if is_centos_7 "$image"; then
                rlAssertGrep "stdout: no package provides tree-but-spelled-wrong" $rlRun_LOG

            elif is_image_mode "$image"; then
                if is_fedora "$image"; then
                    rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG
                else
                    rlAssertGrep "stderr: Error: Unable to find a match: tree-but-spelled-wrong" $rlRun_LOG
                fi

            elif is_ostree "$image"; then
                if [ "$PROVISION_HOW" = "virtual" ]; then
                    rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG
                else
                    rlAssertGrep "stderr: error: Packages not found: tree-but-spelled-wrong" $rlRun_LOG
                fi

            elif is_fedora_coreos "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_fedora_rawhide "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_fedora_eln "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_fedora_43 "$image"; then
                rlAssertGrep "stderr: No match for argument: tree-but-spelled-wrong" $rlRun_LOG

            elif is_ubuntu "$image" || is_debian "$image"; then
                rlAssertGrep "stderr: E: Unable to locate package tree-but-spelled-wrong" $rlRun_LOG

            elif is_alpine "$image"; then
                rlAssertGrep "stderr:   tree-but-spelled-wrong (no such package)" $rlRun_LOG

            else
                rlAssertGrep "stderr: Error: Unable to find a match: tree-but-spelled-wrong" $rlRun_LOG
            fi
            rlAssertGrep "Other failed packages:" $rlRun_LOG
            rlAssertGrep "tree-but-spelled-wrong" $rlRun_LOG
        rlPhaseEnd

        rlPhaseStartTest "$phase_prefix Empty prepare install with exclude"
            rlRun "$tmt execute plan --name empty-with-exclude"
        rlPhaseEnd

        # TODO: at least copr is RH-specific, but package name escaping and debuginfo should be
        # possible to extend to other distros.
        # TODO: image mode copr support depends on #4748
        if ! is_image_mode "$image" && ((is_fedora "$image" && ! is_fedora_coreos "$image") || is_centos "$image" || is_ubi "$image"); then
            if ! is_centos_7 "$image" && ! is_ubi_8 "$image" && ! is_fedora_eln "$image"; then
                rlPhaseStartTest "$phase_prefix Just enable copr"
                    rlRun "$tmt execute plan --name copr"
                rlPhaseEnd

                rlPhaseStartTest "$phase_prefix Exclude selected packages"
                    rlRun "$tmt execute plan --name exclude"
                rlPhaseEnd
            fi

            if is_fedora_eln "$image"; then
                rlPhaseStartTest "$phase_prefix Escape package names"
                    rlRun "$tmt_run -e COPR_PLUGIN=\"dnf5-command(copr)\" -e COPR_PLUGIN_PACKAGE=\"dnf5-plugins\" $tmt_steps execute plan --name escape"
                rlPhaseEnd
            else
                rlPhaseStartTest "$phase_prefix Escape package names"
                    rlRun "$tmt_run -e COPR_PLUGIN=\"dnf-command(copr)\" -e COPR_PLUGIN_PACKAGE=\"dnf-plugins-core\" $tmt_steps execute plan --name escape"
                rlPhaseEnd
            fi

            if is_centos_7 "$image"; then
                rlPhaseStartTest "$phase_prefix Install from epel7 copr"
                    rlRun "$tmt execute plan --name epel7"
                rlPhaseEnd
            fi

            if is_centos_stream_9 "$image"; then
                rlPhaseStartTest "$phase_prefix Install remote packages"
                    rlRun "$tmt execute plan --name epel9-remote"
                rlPhaseEnd
            fi

            if is_ubi_8 "$image"; then
                rlPhaseStartTest "$phase_prefix Install remote packages"
                    rlRun "$tmt execute plan --name epel8-remote"
                rlPhaseEnd
            fi

            rlPhaseStartTest "$phase_prefix Install debuginfo packages"
                rlRun "$tmt execute plan --name debuginfo"
            rlPhaseEnd
        fi
    done <<< "$IMAGES"

    rlPhaseStartCleanup
        rlRun "popd"
        rlRun "rm -r $package_cache" 0 "Remove package cache directory"
        rlRun "rm -r $run" 0 "Remove run directory"
    rlPhaseEnd
rlJournalEnd
