#!/bin/bash
# Remove the MDM-deployed Watcher client from a Mac. Run as root:
#
#     sudo ./uninstall-macos.sh             # remove it
#     sudo ./uninstall-macos.sh --dry-run   # show what would happen, change nothing
#     sudo ./uninstall-macos.sh --user jane # target a specific user's home
#
# Runs 'watcher uninstall' as the user, then removes any remaining login-agent
# files and binaries. User data is preserved.

set -euo pipefail

readonly LAUNCH_LABEL="ai.apolloresearch.watcher"

DRY_RUN=false
USER_OVERRIDE=""

log() { printf '[watcher-uninstall] %s\n' "$*"; }
die() { printf '[watcher-uninstall] ERROR: %s\n' "$*" >&2; exit 1; }

# Print commands instead of running them in dry-run mode.
run() {
    if [ "$DRY_RUN" = true ]; then
        log "DRY-RUN would run: $*"
        return 0
    fi
    "$@"
}

require_root() {
    [ "$(id -u)" -eq 0 ] || die "must run as root; use: sudo $0"
}

# The logged-in user, or empty when nobody is.
console_user() {
    local u
    u="$(/usr/bin/stat -f%Su /dev/console 2>/dev/null || true)"
    case "$u" in
        ""|root|loginwindow|_mbsetupuser|_securityagent) printf '' ;;
        *) printf '%s' "$u" ;;
    esac
}

user_home() {
    # `|| true` so a missing user doesn't trip pipefail and abort the uninstall.
    /usr/bin/dscl . -read "/Users/$1" NFSHomeDirectory 2>/dev/null | awk '{print $2}' || true
}

# Drop to the user when we're root; run directly when already that user (testing).
run_as_user() {
    local user="$1"; shift
    if [ "$(id -u)" -eq 0 ]; then
        run /usr/bin/sudo -u "$user" -H "$@"
    else
        run "$@"
    fi
}

# Use Watcher to remove its hooks before deleting its files.
remove_user_integration() {
    local user="$1" binary="$2"
    if [ -z "$user" ]; then
        log "no user logged in; nothing in a user's home to remove"
        return 0
    fi
    if [ ! -x "$binary" ]; then
        die "cannot remove agent hooks because the binary is missing at $binary; reinstall Watcher, then rerun this script"
    fi
    log "running 'watcher uninstall' for '$user'"
    run_as_user "$user" "$binary" uninstall \
        || die "'watcher uninstall' failed; reinstall or repair Watcher, then rerun this script"
}

# Remove any login-agent files left after Watcher uninstalls itself.
remove_login_agent() {
    local user="$1" home="$2"
    [ -n "$user" ] || return 0
    local uid plist
    uid="$(/usr/bin/id -u "$user" 2>/dev/null || true)"
    if [ -n "$uid" ]; then
        run /bin/launchctl bootout "gui/$uid/$LAUNCH_LABEL" || true
    fi
    plist="$home/Library/LaunchAgents/${LAUNCH_LABEL}.plist"
    if [ -n "$home" ] && [ -f "$plist" ]; then
        run rm -f "$plist"
    fi
}

# Remove the installed binary tree and its PATH symlink. Preserve ~/.apollo_monitor.
remove_binary_tree() {
    local home="$1"
    [ -n "$home" ] || return 0
    local lib_dir="$home/.local/share/apollo-watcher"
    local symlink="$home/.local/bin/watcher"
    if [ -e "$lib_dir" ]; then
        log "deleting $lib_dir"
        run rm -rf "$lib_dir"
    else
        log "no binary tree at $lib_dir; nothing to delete"
    fi
    # Remove this path only when it is a symlink; preserve regular files.
    if [ -L "$symlink" ]; then
        run rm -f "$symlink"
    fi
}

usage() {
    cat <<EOF
Usage: sudo $0 [--dry-run] [--user NAME]

Removes Watcher hooks, login-agent files, and binaries from this Mac.
Data under ~/.apollo_monitor is preserved.

  --dry-run     Print what would happen without changing anything.
  --user NAME   Target this user instead of the auto-detected console user.
  -h, --help    Show this help.
EOF
}

main() {
    while [ $# -gt 0 ]; do
        case "$1" in
            --dry-run) DRY_RUN=true ;;
            --user) shift; [ $# -gt 0 ] || die "--user needs a value"; USER_OVERRIDE="$1" ;;
            -h|--help) usage; exit 0 ;;
            *) die "unknown argument: $1 (try --help)" ;;
        esac
        shift
    done

    # Deleting another user's files needs root, except for a dry-run or a test run
    # against your own account (WATCHER_MDM_USER set).
    if [ "$DRY_RUN" = false ] && [ -z "${WATCHER_MDM_USER:-}" ]; then
        require_root
    fi

    local user
    user="${USER_OVERRIDE:-${WATCHER_MDM_USER:-$(console_user)}}"
    [ -n "$user" ] \
        || die "no console user; rerun after login or pass --user NAME"

    local home
    home="$(user_home "$user")"
    local binary="$home/.local/share/apollo-watcher/watcher/watcher"

    remove_user_integration "$user" "$binary"
    remove_login_agent "$user" "$home"
    remove_binary_tree "$home"

    if [ -n "$user" ] && [ -n "$home" ]; then
        log "kept user data (remove manually if desired): $home/.apollo_monitor"
    fi
    log "uninstall complete."
}

main "$@"
