#!/usr/bin/env bash

# The parts of an install that depend on what the machine actually is: the
# NVIDIA driver, the machine owner key that lets it load under Secure Boot,
# Fedora's preinstalled extras, and firmware.
#
# Runs last. MOK enrollment arms a prompt consumed at the next boot and firmware
# updates can ask for a reboot, so neither belongs in front of the package work
# or the dotfiles -- a machine that reboots out of this stage has already been
# fully configured.
#
# Nothing here decides anything. Every branch is an answer the interview
# collected before the run began, and an absent answer means no, which is what
# makes this safe to re-run by hand while repairing one piece of a machine.
#
# sunhat's version of this opened an editor in the middle of the run so grub
# could be hand-corrected. That is the exact failure this repository exists to
# avoid, and it is unnecessary: grubby replaces an argument that already exists
# rather than appending a second copy, so the duplicates that had to be cleaned
# up by hand cannot accumulate in the first place.

set -uo pipefail

log()  { echo -e "\033[1;34m[INFO]\033[0m $*"; }
warn() { echo -e "\033[1;33m[WARN]\033[0m $*" >&2; }

# Fedora ships these and Panama uses none of them. Named here rather than in the
# interview so there is one list: the interview asks for it with --debloat-list
# to name what it is about to remove, and this stage removes it. A package that
# is not installed is skipped rather than passed to dnf, so the list can outlive
# a Fedora release -- totem left in Fedora 43 and the list should not start
# failing because of it.
DEBLOAT=(gnome-contacts gnome-tour gnome-maps showtime)

if [[ "${1:-}" == "--debloat-list" ]]; then
    printf '%s\n' "${DEBLOAT[@]}"
    exit 0
fi

# ── NVIDIA ───────────────────────────────────────────────────────────────────

if [[ "${PANAMA_NVIDIA:-no}" == yes ]]; then
    # The interview asks about MOK enrollment only when mokutil was present to
    # see Secure Boot at all. Re-check here rather than trusting that the
    # question was ever asked: installing akmod-nvidia and blacklisting
    # nouveau under Secure Boot with no key to enroll produces a machine that
    # reboots into an unloadable driver with its fallback disabled -- the one
    # failure in this installer that costs a person their display.
    if mokutil --sb-state 2>/dev/null | grep -qi 'secureboot enabled' \
        && [[ -z "${PANAMA_MOK_HASH:-}" ]]; then
        warn "Secure Boot is on and no MOK enrollment was prepared; refusing to install"
        warn "the NVIDIA driver, which could not load. Re-run ./install and answer the"
        warn "Secure Boot question, or disable Secure Boot first."
    else
    log "Installing the NVIDIA driver"
    if sudo dnf install -y akmod-nvidia xorg-x11-drv-nvidia-cuda; then
        # nouveau has to be out of the way before the kernel would otherwise
        # bind it, which is why these are kernel arguments and not a modprobe
        # drop-in. modeset=1 is what makes the Wayland session work at all.
        if command -v grubby >/dev/null 2>&1; then
            sudo grubby --update-kernel=ALL \
                --args="rd.driver.blacklist=nouveau modprobe.blacklist=nouveau nvidia-drm.modeset=1"
            log "Kernel arguments set for every installed kernel"
        else
            warn "grubby is not installed; nouveau was not blacklisted"
        fi

        # Suspend and resume are where a proprietary driver most visibly fails.
        # These units save and restore VRAM across it.
        sudo systemctl enable nvidia-hibernate.service nvidia-suspend.service \
            nvidia-resume.service nvidia-powerd.service
        log "NVIDIA power management services enabled"
    else
        warn "The NVIDIA driver did not install; skipping its kernel arguments and services"
    fi
    fi
fi

# ── Secure Boot ──────────────────────────────────────────────────────────────
#
# akmods signs the modules it builds with a key it generates on installation.
# Under Secure Boot that key means nothing until it is enrolled, and enrollment
# is deliberately a thing only somebody at the physical machine can complete:
# the request is queued here, and the next boot shows a blue screen asking for
# the password before it will trust the key.
#
# The password itself never reaches this stage. The interview hashed it and
# recorded the hash, so nothing readable is passed on a command line or left in
# this process's environment -- which is the whole reason mokutil has
# --generate-hash and --hash-file.

mok_hash="${PANAMA_MOK_HASH:-}"
if [[ -n "$mok_hash" ]]; then
    # Overridable so the contract can exercise this against a certificate it is
    # allowed to create. Nothing else sets it.
    cert="${PANAMA_MOK_CERT:-/etc/pki/akmods/certs/public_key.der}"

    if [[ ! -r "$cert" ]]; then
        warn "No akmods certificate at $cert, so there is no key to enroll"
    elif mokutil --test-key "$cert" 2>/dev/null | grep -q 'already enrolled'; then
        log "The akmods key is already enrolled"
    else
        hash_file="$(mktemp -t panama-mok.XXXXXX)"
        chmod 600 "$hash_file"
        printf '%s\n' "$mok_hash" >"$hash_file"
        if sudo mokutil --import "$cert" --hash-file "$hash_file"; then
            log "Key enrollment requested"
            log "At the next boot, choose 'Enroll MOK' and enter the password you gave the installer"
        else
            warn "Key enrollment failed; the NVIDIA module will not load until it is enrolled"
        fi
        rm -f "$hash_file"
    fi
fi

# ── Fedora's preinstalled extras ─────────────────────────────────────────────

if [[ "${PANAMA_DEBLOAT:-no}" == yes ]]; then
    present=()
    for package in "${DEBLOAT[@]}"; do
        rpm -q "$package" >/dev/null 2>&1 && present+=("$package")
    done

    if (( ${#present[@]} > 0 )); then
        log "Removing ${present[*]}"
        sudo dnf remove -y "${present[@]}" >/dev/null \
            || warn "Some packages could not be removed"
    else
        log "None of Fedora's extras are installed"
    fi
fi

# ── Firmware ─────────────────────────────────────────────────────────────────
#
# Panama's Updates page covers this from then on; the installer covers the
# first run. --no-reboot-check because deciding to reboot is not this stage's
# call to make in the middle of an unattended install.

if [[ "${PANAMA_FIRMWARE:-no}" == yes ]]; then
    if command -v fwupdmgr >/dev/null 2>&1; then
        log "Refreshing firmware metadata"
        sudo fwupdmgr refresh --force >/dev/null 2>&1
        log "Applying firmware updates"
        sudo fwupdmgr update -y --no-reboot-check \
            || log "No firmware updates were applied"
    else
        warn "fwupdmgr is not installed; skipping firmware"
    fi
fi
