#!/bin/sh
# Install or remove the stable Wayscriber release on Arch-based systems.
#
# Safer usage: download this file, review it, then run it:
#   curl -fsSL https://wayscriber.com/arch-install.sh -o arch-install.sh
#   sh arch-install.sh --dry-run
#   sh arch-install.sh
#
# The installer downloads the release archive and checksums from the matching
# GitHub release, verifies and stages an allowlisted set of files, and installs
# them under /usr/local. It does not enable or start a stopped service. If the
# user service is already active, it restarts that unit unless --no-restart is
# passed. It refuses another copy under /usr, ~/.local/bin, or a user
# unit/drop-in whose ExecStart is not /usr/local/bin/wayscriber, unless
# --replace-other is passed, so PATH and the overlay daemon cannot follow a
# different file. A symlink that already resolves to /usr/local/bin/wayscriber
# is not treated as a second copy.

set -eu

REPOSITORY="devmobasa/wayscriber"
RELEASES_URL="https://github.com/${REPOSITORY}/releases"
INSTALL_PREFIX="/usr/local"
DEST="${INSTALL_PREFIX}/bin/wayscriber"
TMP_DIR=""
DRY_RUN=0
ACTION="install"
LEGACY_INSTALL=0
REPLACE_OTHER=0
NO_RESTART=0
REMOVE_UNMANAGED_USR=0

die() {
    printf 'error: %s\n' "$*" >&2
    exit 1
}

warn() {
    printf 'warning: %s\n' "$*" >&2
}

usage() {
    printf 'Usage: %s [--dry-run] [--replace-other] [--no-restart]\n' "${0##*/}"
    printf '       %s --uninstall [--dry-run] [--remove-unmanaged-usr]\n' "${0##*/}"
    printf '       %s --print-manifest\n' "${0##*/}"
    printf 'Install or remove the stable x86_64 Wayscriber release under /usr/local.\n'
    printf 'Install refuses an unmanaged /usr copy, ~/.local/bin/wayscriber, or a user unit/drop-in whose ExecStart is not /usr/local/bin/wayscriber, unless --replace-other is passed.\n'
    printf 'Install restarts an already-running user service unless --no-restart is passed.\n'
    printf 'Uninstall removes /usr/local only; pass --remove-unmanaged-usr to also clear leftover /usr files.\n'
}

# ARCH_INSTALL_MANIFEST_BEGIN
release_manifest() {
    printf '%s\n' \
        '0755 bin/wayscriber' \
        '0644 lib/systemd/user/wayscriber.service' \
        '0644 share/applications/wayscriber.desktop' \
        '0644 share/pixmaps/wayscriber.png' \
        '0644 share/icons/hicolor/16x16/apps/wayscriber.png' \
        '0644 share/icons/hicolor/16x16/status/wayscriber.png' \
        '0644 share/icons/hicolor/19x19/apps/wayscriber.png' \
        '0644 share/icons/hicolor/19x19/status/wayscriber.png' \
        '0644 share/icons/hicolor/22x22/apps/wayscriber.png' \
        '0644 share/icons/hicolor/22x22/status/wayscriber.png' \
        '0644 share/icons/hicolor/24x24/apps/wayscriber.png' \
        '0644 share/icons/hicolor/24x24/status/wayscriber.png' \
        '0644 share/icons/hicolor/38x38/apps/wayscriber.png' \
        '0644 share/icons/hicolor/38x38/status/wayscriber.png' \
        '0644 share/icons/hicolor/64x64/apps/wayscriber.png' \
        '0644 share/icons/hicolor/64x64/status/wayscriber.png' \
        '0644 share/icons/hicolor/128x128/apps/wayscriber.png' \
        '0644 share/icons/hicolor/128x128/status/wayscriber.png' \
        '0644 share/icons/hicolor/scalable/apps/wayscriber.svg' \
        '0644 share/icons/hicolor/symbolic/apps/wayscriber-symbolic.svg' \
        '0644 share/doc/wayscriber/config.example.toml' \
        '0644 share/doc/wayscriber/LICENSE' \
        '0644 share/doc/wayscriber/README.md' \
        '0644 share/licenses/wayscriber/LICENSE' \
        '0644 share/licenses/wayscriber/LICENSE.gtk4-layer-shell'
}
# ARCH_INSTALL_MANIFEST_END

while [ "$#" -gt 0 ]; do
    case "$1" in
        --dry-run)
            [ "$DRY_RUN" -eq 0 ] || die "--dry-run was specified more than once"
            DRY_RUN=1
            ;;
        --uninstall)
            [ "$ACTION" = "install" ] || die "choose only one action"
            ACTION="uninstall"
            ;;
        --replace-other)
            [ "$REPLACE_OTHER" -eq 0 ] || die "--replace-other was specified more than once"
            REPLACE_OTHER=1
            ;;
        --no-restart)
            [ "$NO_RESTART" -eq 0 ] || die "--no-restart was specified more than once"
            NO_RESTART=1
            ;;
        --remove-unmanaged-usr)
            [ "$REMOVE_UNMANAGED_USR" -eq 0 ] || die "--remove-unmanaged-usr was specified more than once"
            REMOVE_UNMANAGED_USR=1
            ;;
        --print-manifest)
            [ "$ACTION" = "install" ] || die "choose only one action"
            ACTION="print-manifest"
            ;;
        --help|-h)
            usage
            exit 0
            ;;
        --)
            shift
            [ "$#" -eq 0 ] || die "unexpected argument: $1"
            break
            ;;
        -*)
            die "unknown option: $1"
            ;;
        *)
            die "unexpected argument: $1"
            ;;
    esac
    shift
done

if [ "$ACTION" = "print-manifest" ]; then
    [ "$DRY_RUN" -eq 0 ] || die "--dry-run cannot be used with --print-manifest"
    [ "$REPLACE_OTHER" -eq 0 ] || die "--replace-other cannot be used with --print-manifest"
    [ "$NO_RESTART" -eq 0 ] || die "--no-restart cannot be used with --print-manifest"
    [ "$REMOVE_UNMANAGED_USR" -eq 0 ] || die "--remove-unmanaged-usr cannot be used with --print-manifest"
    release_manifest
    exit 0
fi

if [ "$ACTION" = "uninstall" ]; then
    [ "$REPLACE_OTHER" -eq 0 ] || die "--replace-other cannot be used with --uninstall"
    [ "$NO_RESTART" -eq 0 ] || die "--no-restart cannot be used with --uninstall"
else
    [ "$REMOVE_UNMANAGED_USR" -eq 0 ] || die "--remove-unmanaged-usr cannot be used with install"
fi

cleanup() {
    if [ -n "$TMP_DIR" ] && [ -d "$TMP_DIR" ]; then
        rm -rf "$TMP_DIR"
    fi
}

trap cleanup 0 HUP INT TERM

release_file_mode() {
    release_manifest | awk -v path="$1" '
        $2 == path {
            print $1
            found = 1
            exit
        }
        END { if (!found) exit 1 }
    '
}

prepare_privilege_runner() {
    if [ "$(id -u)" -eq 0 ]; then
        SUDO=""
    else
        command -v sudo >/dev/null 2>&1 \
            || die "sudo is required to change files under /usr/local or /usr"
        SUDO="sudo"
    fi
}

run_privileged() {
    if [ -n "$SUDO" ]; then
        "$SUDO" "$@"
    else
        "$@"
    fi
}

uninstall_release_files() {
    for PREFIX in "$@"; do
        release_manifest | while IFS=' ' read -r _ RELATIVE_PATH; do
            TARGET_PATH="${PREFIX}/${RELATIVE_PATH}"
            if [ ! -e "$TARGET_PATH" ] && [ ! -L "$TARGET_PATH" ]; then
                continue
            fi

            if PACKAGE_OWNER="$(pacman -Qoq "$TARGET_PATH" 2>/dev/null)"; then
                warn "leaving package-owned file ${TARGET_PATH} (${PACKAGE_OWNER})"
                continue
            fi

            if [ "$ACTION" = "install" ] && [ "$PREFIX" = "/usr" ] && \
                [ "$RELATIVE_PATH" = "bin/wayscriber" ] && same_file "$TARGET_PATH" "$DEST"; then
                warn "leaving ${TARGET_PATH} (same file as ${DEST})"
                continue
            fi

            if [ "$DRY_RUN" -eq 1 ]; then
                printf 'Would remove %s\n' "$TARGET_PATH"
            else
                printf 'Removing %s\n' "$TARGET_PATH"
                run_privileged rm -f -- "$TARGET_PATH" \
                    || exit 1
            fi
        done || return 1
    done
}

print_binary_identity() {
    path="$1"
    if [ ! -e "$path" ] && [ ! -L "$path" ]; then
        printf '  %s (missing)\n' "$path"
        return 0
    fi
    printf '  %s\n' "$path"
    if [ -f "$path" ] && command -v sha256sum >/dev/null 2>&1; then
        printf '    sha256: %s\n' "$(sha256sum "$path" | awk '{ print $1 }')"
    fi
    if [ -x "$path" ]; then
        printf '    version: %s\n' "$("$path" --version 2>/dev/null || printf 'unreadable')"
    fi
}

canonical_path() {
    readlink -f "$1" 2>/dev/null || printf '%s' "$1"
}

same_file() {
    [ -e "$1" ] || [ -L "$1" ] || return 1
    _left="$(canonical_path "$1")"
    _right="$(canonical_path "$2")"
    [ -n "$_left" ] && { [ "$_left" = "$_right" ] || [ "$_left" = "$2" ]; }
}

systemd_user_dir() {
    if [ -n "${XDG_CONFIG_HOME:-}" ]; then
        printf '%s\n' "${XDG_CONFIG_HOME}/systemd/user"
    elif [ -n "${HOME:-}" ]; then
        printf '%s\n' "${HOME}/.config/systemd/user"
    fi
}

file_has_conflicting_exec_start() {
    _dest="$1"
    _file="$2"
    [ -f "$_file" ] || return 1
    grep -Eq '^[[:space:]]*ExecStart=' "$_file" || return 1
    if grep -E '^[[:space:]]*ExecStart=' "$_file" | grep -Fq "$_dest"; then
        return 1
    fi
    for _other in /usr/bin/wayscriber /usr/local/bin/wayscriber; do
        grep -E '^[[:space:]]*ExecStart=' "$_file" | grep -Fq "$_other" || continue
        same_file "$_other" "$_dest" && return 1
        return 0
    done
    if [ -n "${HOME:-}" ]; then
        if grep -E '^[[:space:]]*ExecStart=' "$_file" | grep -Fq "${HOME}/.local/bin/wayscriber"; then
            same_file "${HOME}/.local/bin/wayscriber" "$_dest" && return 1
            return 0
        fi
    fi
    return 0
}

user_unit_conflicts() {
    _dir="$(systemd_user_dir)"
    [ -n "$_dir" ] || return 1
    if [ -f "${_dir}/wayscriber.service" ] && \
        file_has_conflicting_exec_start "$DEST" "${_dir}/wayscriber.service"; then
        return 0
    fi
    if [ -d "${_dir}/wayscriber.service.d" ]; then
        for _conf in "${_dir}/wayscriber.service.d/"*.conf; do
            [ -f "$_conf" ] || continue
            file_has_conflicting_exec_start "$DEST" "$_conf" && return 0
        done
    fi
    return 1
}

user_unit_file_starts_dest() {
    _file="$1"
    [ -f "$_file" ] || return 1
    grep -E '^[[:space:]]*ExecStart=' "$_file" | grep -Fq "$DEST"
}

user_unit_starts_dest() {
    _dir="$(systemd_user_dir)"
    [ -n "$_dir" ] || return 1
    user_unit_file_starts_dest "${_dir}/wayscriber.service" && return 0
    if [ -d "${_dir}/wayscriber.service.d" ]; then
        for _conf in "${_dir}/wayscriber.service.d/"*.conf; do
            [ -f "$_conf" ] || continue
            user_unit_file_starts_dest "$_conf" && return 0
        done
    fi
    return 1
}

warn_uninstall_leftovers() {
    if [ -n "${HOME:-}" ] && { [ -e "${HOME}/.local/bin/wayscriber" ] || [ -L "${HOME}/.local/bin/wayscriber" ]; }; then
        warn "${HOME}/.local/bin/wayscriber remains; a login-shell PATH can still prefer it over the AUR copy"
    fi
    if user_unit_conflicts; then
        warn "a user unit or drop-in still has ExecStart other than ${DEST}; that override can shadow the AUR service. Inspect: systemctl --user show wayscriber.service -p ExecStart,FragmentPath"
    elif user_unit_starts_dest; then
        warn "a user unit or drop-in still starts ${DEST}, which uninstall removes from ${INSTALL_PREFIX}; delete that override before enabling the AUR unit. Inspect: systemctl --user show wayscriber.service -p ExecStart,FragmentPath"
    fi
}

remove_conflicting_user_unit() {
    _dir="$(systemd_user_dir)"
    [ -n "$_dir" ] || return 0
    for _file in "${_dir}/wayscriber.service" "${_dir}/wayscriber.service.d/"*.conf; do
        [ -f "$_file" ] || continue
        file_has_conflicting_exec_start "$DEST" "$_file" || continue
        if [ "$DRY_RUN" -eq 1 ]; then
            printf 'Would remove %s (ExecStart is not %s)\n' "$_file" "$DEST"
        else
            printf 'Removing %s (ExecStart is not %s)\n' "$_file" "$DEST"
            rm -f -- "$_file"
        fi
    done
}

print_install_identity() {
    printf 'Installed binary:\n'
    print_binary_identity "$DEST"
    if { [ -e /usr/bin/wayscriber ] || [ -L /usr/bin/wayscriber ]; } && \
        ! same_file /usr/bin/wayscriber "$DEST"; then
        warn "another wayscriber still exists at /usr/bin/wayscriber; overlay spawn follows the daemon file, not whichever path you inspect"
        print_binary_identity /usr/bin/wayscriber
    fi
    if [ -n "${HOME:-}" ] && { [ -e "${HOME}/.local/bin/wayscriber" ] || [ -L "${HOME}/.local/bin/wayscriber" ]; } && \
        ! same_file "${HOME}/.local/bin/wayscriber" "$DEST"; then
        warn "another wayscriber still exists at ${HOME}/.local/bin/wayscriber; overlay spawn follows the daemon file, not whichever path you inspect"
        print_binary_identity "${HOME}/.local/bin/wayscriber"
    fi
    if command -v systemctl >/dev/null 2>&1; then
        EXEC_START="$(systemctl --user show wayscriber.service -p ExecStart --value 2>/dev/null || true)"
        FRAGMENT="$(systemctl --user show wayscriber.service -p FragmentPath --value 2>/dev/null || true)"
        MAINPID="$(systemctl --user show wayscriber.service -p MainPID --value 2>/dev/null || true)"
        [ -n "$EXEC_START" ] && printf 'User service ExecStart: %s\n' "$EXEC_START"
        [ -n "$FRAGMENT" ] && printf 'User service unit: %s\n' "$FRAGMENT"
        if [ -n "$MAINPID" ] && [ "$MAINPID" != "0" ]; then
            RUNNING_EXE="$(readlink -f "/proc/${MAINPID}/exe" 2>/dev/null || true)"
            if [ -n "$RUNNING_EXE" ]; then
                printf 'Running daemon: %s\n' "$RUNNING_EXE"
            else
                printf 'Running daemon pid: %s\n' "$MAINPID"
            fi
        fi
    fi
}

if [ "$ACTION" = "uninstall" ]; then
    command -v awk >/dev/null 2>&1 || die "awk is required"
    command -v id >/dev/null 2>&1 || die "id is required"
    command -v pacman >/dev/null 2>&1 \
        || die "pacman is required; this installer supports Arch-based systems only"
    command -v rm >/dev/null 2>&1 || die "rm is required"
    if [ "$DRY_RUN" -eq 0 ] && [ "$(id -u)" -eq 0 ]; then
        die "run --uninstall as the desktop user, without sudo; the script requests sudo only for file removal"
    fi

    SERVICE_IN_USE=0
    if command -v systemctl >/dev/null 2>&1; then
        if systemctl --user is-active --quiet wayscriber.service 2>/dev/null || \
            systemctl --user is-enabled --quiet wayscriber.service 2>/dev/null; then
            SERVICE_IN_USE=1
        fi
    fi

    if [ "$SERVICE_IN_USE" -eq 1 ]; then
        if [ "$DRY_RUN" -eq 1 ]; then
            warn "disable and stop the user service before uninstalling: systemctl --user disable --now wayscriber.service"
        else
            die "disable and stop the user service first: systemctl --user disable --now wayscriber.service"
        fi
    fi

    if [ "$DRY_RUN" -eq 0 ]; then
        prepare_privilege_runner
    fi

    if [ "$REMOVE_UNMANAGED_USR" -eq 1 ]; then
        uninstall_release_files "$INSTALL_PREFIX" /usr \
            || die "could not remove the unmanaged Wayscriber release files"
    else
        uninstall_release_files "$INSTALL_PREFIX" \
            || die "could not remove the unmanaged Wayscriber release files"
    fi

    if [ "$DRY_RUN" -eq 1 ]; then
        printf 'Uninstall dry run complete; no files were removed.\n'
        warn_uninstall_leftovers
        exit 0
    fi

    if command -v systemctl >/dev/null 2>&1; then
        systemctl --user daemon-reload 2>/dev/null || \
            warn "could not reload the user systemd manager in this session"
    fi

    printf 'Removed unmanaged Wayscriber release files from %s.\n' "$INSTALL_PREFIX"
    if [ "$REMOVE_UNMANAGED_USR" -eq 1 ]; then
        printf 'Also removed matching unmanaged files from /usr.\n'
    elif [ -e /usr/bin/wayscriber ] || [ -L /usr/bin/wayscriber ]; then
        if PACKAGE_OWNER="$(pacman -Qoq /usr/bin/wayscriber 2>/dev/null)"; then
            printf 'Left package-owned /usr/bin/wayscriber (%s).\n' "$PACKAGE_OWNER"
        else
            warn "unmanaged /usr/bin/wayscriber remains; remove it with --remove-unmanaged-usr if that copy should go too"
        fi
    fi
    printf 'You can now install the AUR package: yay -S wayscriber-bin\n'
    warn_uninstall_leftovers
    exit 0
fi

command -v curl >/dev/null 2>&1 || die "curl is required"
command -v tar >/dev/null 2>&1 || die "tar is required"
command -v sha256sum >/dev/null 2>&1 || die "sha256sum is required"
command -v awk >/dev/null 2>&1 || die "awk is required"
command -v sed >/dev/null 2>&1 || die "sed is required"
command -v grep >/dev/null 2>&1 || die "grep is required"
command -v mktemp >/dev/null 2>&1 || die "mktemp is required"
command -v find >/dev/null 2>&1 || die "find is required"
command -v id >/dev/null 2>&1 || die "id is required"
command -v install >/dev/null 2>&1 || die "install is required"
command -v pacman >/dev/null 2>&1 || die "pacman is required; this installer supports Arch-based systems only"

ARCH="$(uname -m)"
[ "$ARCH" = "x86_64" ] || die "the published binary currently supports x86_64 only (found ${ARCH})"

LATEST_URL="$(curl --disable -fsSL --proto '=https' --proto-redir '=https' \
    --retry 3 --connect-timeout 15 --max-time 60 --max-filesize 1048576 \
    -o /dev/null -w '%{url_effective}' "${RELEASES_URL}/latest")" \
    || die "could not resolve the latest GitHub release"

VERSION="$(printf '%s\n' "$LATEST_URL" | sed -nE 's#^https://github\.com/devmobasa/wayscriber/releases/tag/v([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?)/?$#\1#p')"
printf '%s\n' "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$' \
    || die "GitHub returned an unexpected latest-release URL: ${LATEST_URL}"

TAG="v${VERSION}"
ARCHIVE="wayscriber-v${VERSION}-linux-x86_64.tar.gz"
BASE_URL="${RELEASES_URL}/download/${TAG}"

TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/wayscriber-install.XXXXXX")"
ARCHIVE_PATH="${TMP_DIR}/${ARCHIVE}"
CHECKSUMS_PATH="${TMP_DIR}/checksums.txt"

printf 'Downloading Wayscriber %s...\n' "$VERSION"
curl --disable -fL --proto '=https' --proto-redir '=https' \
    --retry 3 --connect-timeout 15 --max-time 180 --max-filesize 104857600 \
    -o "$ARCHIVE_PATH" "${BASE_URL}/${ARCHIVE}" \
    || die "could not download ${ARCHIVE}"
curl --disable -fL --proto '=https' --proto-redir '=https' \
    --retry 3 --connect-timeout 15 --max-time 60 --max-filesize 1048576 \
    -o "$CHECKSUMS_PATH" "${BASE_URL}/checksums.txt" \
    || die "could not download release checksums"

EXPECTED_SHA="$(awk -v name="$ARCHIVE" '$2 == name { print $1; exit }' "$CHECKSUMS_PATH")"
printf '%s\n' "$EXPECTED_SHA" | grep -Eq '^[0-9a-fA-F]{64}$' \
    || die "checksums.txt does not contain a SHA-256 entry for ${ARCHIVE}"

printf '%s  %s\n' "$EXPECTED_SHA" "$ARCHIVE" \
    | (cd "$TMP_DIR" && sha256sum -c -) \
    || die "checksum verification failed for ${ARCHIVE}"

TOP_LEVEL="wayscriber-v${VERSION}-linux-x86_64"
tar -tzf "$ARCHIVE_PATH" \
    | awk -v root="${TOP_LEVEL}/" '
        {
            valid_root = ($0 == root || $0 == root "usr" || index($0, root "usr/") == 1)
            unsafe = ($0 ~ /^\// || $0 ~ /(^|\/)\.\.(\/|$)/)
            if (!valid_root || unsafe) bad = 1
        }
        END { exit bad }
    ' \
    || die "release archive contains an unexpected or unsafe path"

mkdir -p "${TMP_DIR}/stage"
tar -xzf "$ARCHIVE_PATH" -C "${TMP_DIR}/stage"
STAGED_ROOT="${TMP_DIR}/stage/${TOP_LEVEL}"
INSTALL_LIST="${TMP_DIR}/install-files.txt"
MANIFEST_LIST="${TMP_DIR}/release-manifest.txt"
LOCAL_SERVICE="${TMP_DIR}/wayscriber.service"

if (
    cd "$STAGED_ROOT"
    LC_ALL=C find . -mindepth 1 ! -regex '\./[-A-Za-z0-9._/+]*' -print -quit | grep -q .
); then
    die "release archive contains a path with unsupported characters"
fi
find "$STAGED_ROOT" ! -type d ! -type f -print -quit | grep -q . \
    && die "release archive contains a symbolic link or special file"
find "$STAGED_ROOT" -type f -links +1 -print -quit | grep -q . \
    && die "release archive contains a hard-linked file"
[ -f "${STAGED_ROOT}/usr/bin/wayscriber" ] && [ -x "${STAGED_ROOT}/usr/bin/wayscriber" ] \
    || die "release archive does not contain the expected Wayscriber binary"
[ -f "${STAGED_ROOT}/usr/lib/systemd/user/wayscriber.service" ] \
    || die "release archive does not contain the expected user service"

awk -v binary="${INSTALL_PREFIX}/bin/wayscriber" '
    $0 == "ExecStart=/usr/bin/wayscriber --daemon" ||
    $0 == "ExecStart=\"/usr/bin/wayscriber\" --daemon" {
        print "ExecStart=\"" binary "\" --daemon"
        matches++
        next
    }
    { print }
    END { if (matches != 1) exit 1 }
' "${STAGED_ROOT}/usr/lib/systemd/user/wayscriber.service" > "$LOCAL_SERVICE" \
    || die "release user service does not contain the expected ExecStart line"
grep -Fq '/usr/bin/wayscriber' "$LOCAL_SERVICE" \
    && die "release user service contains another hard-coded /usr/bin/wayscriber path"

(
    cd "${STAGED_ROOT}/usr"
    find . -type f -print
) > "$INSTALL_LIST"

while IFS= read -r RELATIVE_PATH; do
    RELATIVE_PATH="${RELATIVE_PATH#./}"
    release_file_mode "$RELATIVE_PATH" >/dev/null \
        || die "release archive contains an unexpected file: usr/${RELATIVE_PATH}"
done < "$INSTALL_LIST"

release_manifest > "$MANIFEST_LIST"
while IFS=' ' read -r _ RELATIVE_PATH; do
    [ -f "${STAGED_ROOT}/usr/${RELATIVE_PATH}" ] \
        || die "release archive is missing required file: usr/${RELATIVE_PATH}"
done < "$MANIFEST_LIST"

if ! MISSING_DEPS="$(pacman -T 'glibc>=2.39' gcc-libs cairo wayland pango \
    libxkbcommon 'gtk4>=4.12' wl-clipboard grim slurp 2>/dev/null)"; then
    printf 'Missing required Arch packages:\n%s\n' "$MISSING_DEPS" >&2
    die "install them with: sudo pacman -S --needed glibc gcc-libs cairo wayland pango libxkbcommon gtk4 wl-clipboard grim slurp"
fi

for SYSTEM_PATH in \
    /usr/bin/wayscriber \
    /usr/lib/systemd/user/wayscriber.service \
    /usr/share/applications/wayscriber.desktop
do
    [ -e "$SYSTEM_PATH" ] || continue
    if PACKAGE_OWNER="$(pacman -Qoq "$SYSTEM_PATH" 2>/dev/null)"; then
        die "${SYSTEM_PATH} is owned by Arch package ${PACKAGE_OWNER}; remove or update that package instead of shadowing it"
    fi
    if [ "$SYSTEM_PATH" = "/usr/bin/wayscriber" ] && same_file "$SYSTEM_PATH" "$DEST"; then
        continue
    fi
    if [ "$SYSTEM_PATH" = "/usr/lib/systemd/user/wayscriber.service" ] && \
        ! file_has_conflicting_exec_start "$DEST" "$SYSTEM_PATH"; then
        continue
    fi
    LEGACY_INSTALL=1
done

USER_LOCAL_INSTALL=0
if [ -n "${HOME:-}" ] && { [ -e "${HOME}/.local/bin/wayscriber" ] || [ -L "${HOME}/.local/bin/wayscriber" ]; } && \
    ! same_file "${HOME}/.local/bin/wayscriber" "$DEST"; then
    USER_LOCAL_INSTALL=1
fi

if [ "$LEGACY_INSTALL" -eq 1 ] || [ "$USER_LOCAL_INSTALL" -eq 1 ] || user_unit_conflicts; then
    if [ "$REPLACE_OTHER" -eq 0 ]; then
        die "another Wayscriber copy would stay beside ${INSTALL_PREFIX}/bin/wayscriber (unmanaged /usr, ${HOME}/.local/bin, or a user unit/drop-in whose ExecStart is not ${INSTALL_PREFIX}/bin/wayscriber). Remove the other copy first, or rerun with --replace-other"
    fi
    warn "another Wayscriber copy exists; --replace-other will remove the unmanaged /usr files, ${HOME}/.local/bin/wayscriber, and a conflicting user unit/drop-in"
fi

while IFS= read -r RELATIVE_PATH; do
    RELATIVE_PATH="${RELATIVE_PATH#./}"
    INSTALL_PATH="${INSTALL_PREFIX}/${RELATIVE_PATH}"
    if [ -e "$INSTALL_PATH" ] || [ -L "$INSTALL_PATH" ]; then
        if PACKAGE_OWNER="$(pacman -Qoq "$INSTALL_PATH" 2>/dev/null)"; then
            die "${INSTALL_PATH} is owned by Arch package ${PACKAGE_OWNER}; remove or update that package instead of overwriting it"
        fi
    fi
done < "$INSTALL_LIST"

if [ "$DRY_RUN" -eq 1 ]; then
    if [ "$LEGACY_INSTALL" -eq 1 ]; then
        uninstall_release_files /usr \
            || die "could not list unmanaged /usr files that --replace-other would remove"
    fi
    if [ "$USER_LOCAL_INSTALL" -eq 1 ]; then
        printf 'Would remove %s\n' "${HOME}/.local/bin/wayscriber"
    fi
    if user_unit_conflicts; then
        remove_conflicting_user_unit
    fi
    printf 'Validated Wayscriber %s (%s); no files were installed.\n' "$VERSION" "$ARCHIVE"
    exit 0
fi

prepare_privilege_runner

if [ "$LEGACY_INSTALL" -eq 1 ]; then
    uninstall_release_files /usr \
        || die "could not remove the unmanaged Wayscriber files under /usr"
fi
if [ "$USER_LOCAL_INSTALL" -eq 1 ]; then
    printf 'Removing %s\n' "${HOME}/.local/bin/wayscriber"
    rm -f -- "${HOME}/.local/bin/wayscriber"
fi
if user_unit_conflicts; then
    remove_conflicting_user_unit
fi

printf 'Installing into %s...\n' "$INSTALL_PREFIX"
while IFS= read -r RELATIVE_PATH; do
    RELATIVE_PATH="${RELATIVE_PATH#./}"
    FILE_MODE="$(release_file_mode "$RELATIVE_PATH")" \
        || die "release archive contains an unexpected file: usr/${RELATIVE_PATH}"
    SOURCE_PATH="${STAGED_ROOT}/usr/${RELATIVE_PATH}"
    if [ "$RELATIVE_PATH" = "lib/systemd/user/wayscriber.service" ]; then
        SOURCE_PATH="$LOCAL_SERVICE"
    fi
    run_privileged install -D -m "$FILE_MODE" -- \
        "$SOURCE_PATH" "${INSTALL_PREFIX}/${RELATIVE_PATH}"
done < "$INSTALL_LIST"

if command -v systemctl >/dev/null 2>&1; then
    systemctl --user daemon-reload 2>/dev/null || \
        warn "could not reload the user systemd manager in this session"
fi

printf '\nInstalled Wayscriber %s.\n' "$VERSION"
print_install_identity
if command -v systemctl >/dev/null 2>&1 && \
    systemctl --user is-active --quiet wayscriber.service 2>/dev/null; then
    if [ "$NO_RESTART" -eq 1 ]; then
        warn "the running service was not restarted (--no-restart); restart it when ready with: systemctl --user restart wayscriber.service"
    elif systemctl --user restart wayscriber.service; then
        printf 'Restarted the user service so it uses %s/bin/wayscriber.\n' "$INSTALL_PREFIX"
        print_install_identity
    else
        warn "could not restart wayscriber.service; restart it with: systemctl --user restart wayscriber.service"
    fi
else
    printf 'Start it when ready: systemctl --user enable --now wayscriber.service\n'
fi
