#!/usr/bin/env bash
# SF | Uninstall Secureframe Federal MDM (macOS)
# 1. Reverts/cleans up settings written by Secureframe enforcements
# 2. Uninstalls the NinjaOne (Federal MDM) agent and related components
#
# Cleans up settings from:
# - Enable Screen Lock Timeout (Mac)
# - Enable Warning Banner (macOS)
# - Enable Firewall (macOS)
# - Enable Password Policy (macOS)
# - Disable autologin (macOS)
#
# Goal: remove Secureframe-imposed settings/traces (best-effort),
#       WITHOUT intentionally disabling core security (e.g., firewall stays ON),
#       then fully uninstall the NinjaOne agent.
#
# Updates custom fields when possible:
# - sfscreenlockstatus
# - sfwarningbannerstatus
# - sffirewallstatus
# - sfpasswordpolicystatus
# - sfautologindisabled
#
# NOTE: This script removes the agent from the local machine only.
#       The device record must be removed separately by an admin via the
#       Secureframe UI or NinjaOne dashboard.

[ -n "${BASH_VERSION:-}" ] || exec /bin/bash "$0" "$@"
set -euo pipefail

LOG_PATH="/tmp/NinjaOneReinstall.log"

# -----------------------------
# Must be root
# -----------------------------
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
  echo "This script must be run as root."
  exit 1
fi

# -----------------------------
# Logging helper
# -----------------------------
log_entry() {
    local message="$1"
    local timestamp
    timestamp=$(date +"%Y-%m-%d %H:%M:%S")
    echo "$timestamp - $message" >>"$LOG_PATH"
    echo "$timestamp - $message"
}

# -----------------------------
# CLI discovery
# -----------------------------
find_cli() {
  for p in \
    "/Applications/NinjaRMMAgent/programdata/ninjarmm-cli" \
    "/Library/NinjaRMMAgent/programdata/ninjarmm-cli" \
    "/Library/NinjaRMMAgent/bin/ninjarmm-cli" \
    "/opt/NinjaRMMAgent/bin/ninjarmm-cli" \
    "/opt/NinjaRMMAgent/programdata/ninjarmm-cli" \
    "/usr/local/bin/ninjarmm-cli" \
    "/usr/bin/ninjarmm-cli"
  do
    [[ -x "$p" ]] && { echo "$p"; return 0; }
  done
  echo ""
  return 1
}

CLI="$(find_cli || true)"

set_field_bool() {
  local field="$1"
  local val="$2" # true/false
  if [[ -n "${CLI:-}" ]]; then
    "$CLI" set "$field" "$val" >/dev/null 2>&1 || \
    "$CLI" set-asset-field -name "$field" -value "$val" >/dev/null 2>&1 || \
    echo "WARNING: failed to set custom field $field=$val"
  else
    echo "WARNING: ninjarmm-cli not found; skipping custom field update ($field=$val)."
  fi
}

# Best-effort runner (don't abort entire cleanup on one failure)
FAILURES=0
run_step() {
  local name="$1"
  shift
  echo
  echo "=== $name ==="
  if "$@"; then
    echo "OK: $name"
    return 0
  else
    echo "WARN: $name failed (continuing)"
    FAILURES=$((FAILURES + 1))
    return 0
  fi
}

# -----------------------------
# 1) Screen lock cleanup
# -----------------------------
cleanup_screenlock() {
  local field="sfscreenlockstatus"
  local console_user
  console_user="$(/usr/bin/stat -f %Su /dev/console 2>/dev/null || true)"

  if [[ -z "${console_user:-}" || "${console_user}" == "root" || "${console_user}" == "loginwindow" || "${console_user}" == "_mbsetupuser" ]]; then
    echo "No real console user detected; cannot remove per-user screensaver settings (not a failure)."
    set_field_bool "$field" false
    return 0
  fi

  echo "Console user: $console_user"

  sudo -u "$console_user" /usr/bin/defaults -currentHost delete com.apple.screensaver idleTime >/dev/null 2>&1 || true
  sudo -u "$console_user" /usr/bin/defaults -currentHost delete com.apple.screensaver askForPassword >/dev/null 2>&1 || true
  sudo -u "$console_user" /usr/bin/defaults -currentHost delete com.apple.screensaver askForPasswordDelay >/dev/null 2>&1 || true

  /usr/bin/killall -u "$console_user" cfprefsd >/dev/null 2>&1 || true

  set_field_bool "$field" false
  return 0
}

# -----------------------------
# 2) Warning banner cleanup
# -----------------------------
cleanup_warning_banner() {
  local field="sfwarningbannerstatus"
  local plist="/Library/Preferences/com.apple.loginwindow"

  echo "Removing LoginwindowText (best-effort)..."
  /usr/bin/defaults delete "$plist" LoginwindowText >/dev/null 2>&1 || true

  rm -f /Library/Security/PolicyBanner.* >/dev/null 2>&1 || true

  set_field_bool "$field" false
  return 0
}

# -----------------------------
# 3) Firewall cleanup (do NOT disable firewall)
# -----------------------------
cleanup_firewall() {
  local field="sffirewallstatus"
  local plist="/Library/Preferences/com.apple.alf"

  /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on >/dev/null 2>&1 || true
  /usr/bin/defaults write "$plist" globalstate -int 1 >/dev/null 2>&1 || true

  /usr/bin/defaults delete "$plist" stealthenabled >/dev/null 2>&1 || true
  /usr/bin/defaults delete "$plist" allowsignedenabled >/dev/null 2>&1 || true
  /usr/bin/defaults delete "$plist" allowdownloadsignedenabled >/dev/null 2>&1 || true

  set_field_bool "$field" false
  return 0
}

# -----------------------------
# 4) Password policy cleanup (remove only tokens we set)
# -----------------------------
cleanup_password_policy() {
  local field="sfpasswordpolicystatus"

  local current
  current="$(pwpolicy -getglobalpolicy 2>/dev/null || true)"

  if [[ -z "${current// /}" ]]; then
    echo "No global pwpolicy set (empty). Nothing to clean."
    set_field_bool "$field" false
    return 0
  fi

  echo "Current global policy: $current"

  local extras_str=""
  local token
  for token in $current; do
    case "$token" in
      minChars=*|requiresAlpha=*|requiresNumeric=*)
        ;;
      *)
        extras_str="${extras_str} ${token}"
        ;;
    esac
  done

  local new_policy
  new_policy="$(echo "${extras_str}" | xargs || true)"

  echo "New global policy: ${new_policy:-<empty>}"

  if [[ -n "${new_policy:-}" ]]; then
    pwpolicy -setglobalpolicy "$new_policy" >/dev/null 2>&1 || true
  else
    pwpolicy -setglobalpolicy "" >/dev/null 2>&1 || true
  fi

  set_field_bool "$field" false
  return 0
}

# -----------------------------
# 5) Autologin cleanup (cannot restore what we deleted)
# -----------------------------
cleanup_autologin() {
  local field="sfautologindisabled"
  local plist="/Library/Preferences/com.apple.loginwindow"
  local kcpass="/etc/kcpassword"

  echo "Autologin restore is not possible without a saved backup of autoLoginUser + kcpassword."
  echo "Ensuring no lingering autologin artifacts exist (best-effort)."

  /usr/bin/defaults delete "$plist" autoLoginUser >/dev/null 2>&1 || true
  rm -f "$kcpass" >/dev/null 2>&1 || true

  set_field_bool "$field" false
  return 0
}

# -----------------------------
# 6) Uninstall NinjaOne agent and Ninja Remote
# -----------------------------
uninstall_ninja_agent() {
  log_entry "Beginning NinjaOne agent and Ninja Remote removal..."

  # --- Remove LaunchDaemons ---
  local daemon_dir="/Library/LaunchDaemons"
  local LaunchDaemons
  LaunchDaemons=$(ls "$daemon_dir" 2>/dev/null | grep 'ninjarmm' || true)
  if [[ -z "${LaunchDaemons// /}" ]]; then
    log_entry "No NinjaRMM Launch Daemons found"
  else
    for Daemon in $LaunchDaemons; do
      local daemon_path="$daemon_dir/$Daemon"
      local service_name="${Daemon%.plist}"
      log_entry "Removing $daemon_path"
      launchctl unload "$daemon_path" 2>/dev/null || true
      launchctl remove "$service_name" 2>/dev/null || true
      rm -f "$daemon_path"
    done
  fi

  # --- Remove LaunchAgents ---
  local agent_dir="/Library/LaunchAgents"
  local LaunchAgents
  LaunchAgents=$(ls "$agent_dir" 2>/dev/null | grep 'ninjarmm' || true)
  if [[ -z "${LaunchAgents// /}" ]]; then
    log_entry "No NinjaRMM Launch Agents found"
  else
    for Agent in $LaunchAgents; do
      local agent_path="$agent_dir/$Agent"
      local service_name="${Agent%.plist}"
      log_entry "Removing $agent_path"
      launchctl unload "$agent_path" 2>/dev/null || true
      launchctl remove "$service_name" 2>/dev/null || true
      rm -f "$agent_path"
    done
  fi

  # --- Remove NinjaRMMAgent application directory ---
  local NinjaDir="/Applications/NinjaRMMAgent"
  if [[ -d "$NinjaDir" ]]; then
    log_entry "Removing $NinjaDir"
    rm -rf "$NinjaDir"
  else
    log_entry "NinjaRMMAgent directory not found at $NinjaDir"
  fi

  # --- Kill NinjaRMM processes ---
  local NinjaProcesses
  NinjaProcesses=($(pgrep ninjarmm 2>/dev/null)) || true
  if [[ ${#NinjaProcesses[@]} -gt 0 ]]; then
    for NP in "${NinjaProcesses[@]}"; do
      log_entry "Killing NinjaRMM process $NP"
      kill -9 "$NP" 2>/dev/null || true
    done
    local CheckRemaining
    CheckRemaining=$(pgrep ninjarmm 2>/dev/null || true)
    if [[ -z "$CheckRemaining" ]]; then
      log_entry "Successfully killed all NinjaRMM processes."
    else
      log_entry "WARNING: Not able to kill all NinjaRMM processes."
      log_entry "Remaining process(es): $CheckRemaining"
    fi
  else
    log_entry "No running NinjaRMM processes found"
  fi

  # --- Kill Ninja Remote (ncstreamer) processes ---
  local NinjaRemoteProcess
  NinjaRemoteProcess=($(pgrep ncstreamer 2>/dev/null)) || true
  if [[ ${#NinjaRemoteProcess[@]} -gt 0 ]]; then
    for NRP in "${NinjaRemoteProcess[@]}"; do
      log_entry "Killing Ninja Remote process $NRP"
      kill -9 "$NRP" 2>/dev/null || true
    done
    local CheckRemaining
    CheckRemaining=$(pgrep ncstreamer 2>/dev/null || true)
    if [[ -z "$CheckRemaining" ]]; then
      log_entry "Successfully killed all Ninja Remote processes."
    else
      log_entry "WARNING: Not able to kill all Ninja Remote processes. Make sure there are no active NR sessions."
      log_entry "Remaining process(es): $CheckRemaining"
    fi
  else
    log_entry "No running Ninja Remote processes found"
  fi

  # --- Remove NinjaRMM user preference files ---
  local SettingsPath="Library/Preferences"
  for UserPath in /Users/*; do
    local User
    User=$(basename "$UserPath")
    if [[ "$User" != "Shared" ]]; then
      local FullPath="/Users/$User/$SettingsPath"
      if [[ -d "$FullPath" ]]; then
        local NRSettingsFiles
        NRSettingsFiles=$(ls "$FullPath" 2>/dev/null | grep 'ninjarmm' || true)
        if [[ -n "${NRSettingsFiles// /}" ]]; then
          for NRFile in $NRSettingsFiles; do
            log_entry "Removing $FullPath/$NRFile"
            rm -f "$FullPath/$NRFile"
          done
        fi
      fi
    fi
  done

  # --- Remove Ninja Remote printer ---
  local NRPrinter="/Library/Printers/NinjaRemote"
  if [[ -d "$NRPrinter" ]]; then
    log_entry "Removing Ninja Remote printer at $NRPrinter"
    rm -rf "$NRPrinter"
  fi

  local NRPrinterBackend="/usr/libexec/cups/backend/nrprinter"
  if [[ -f "$NRPrinterBackend" ]]; then
    log_entry "Removing Ninja Remote CUPS backend at $NRPrinterBackend"
    rm -f "$NRPrinterBackend"
  fi

  if lpstat -p "NinjaRemote" >/dev/null 2>&1; then
    log_entry "Removing Ninja Remote printer from CUPS"
    lpadmin -x NinjaRemote 2>/dev/null || true
  fi

  local NRPShared="/Users/Shared/NrPdfPrint"
  if [[ -f "$NRPShared" ]]; then
    log_entry "Removing shared printer file"
    rm -f "$NRPShared"
  fi

  # --- Remove Ninja Remote application directory ---
  local NRDir="/Applications/NinjaRemote"
  if [[ -d "$NRDir" ]]; then
    log_entry "Removing Ninja Remote directory"
    rm -rf "$NRDir"
  fi

  # --- Final verification ---
  local remaining
  remaining=$(pgrep ninjarmm 2>/dev/null || true)
  if [[ -z "$remaining" ]]; then
    log_entry "Verification: No NinjaRMM processes running. Agent fully removed."
  else
    log_entry "WARNING: NinjaRMM processes still detected after removal: $remaining"
  fi

  log_entry "NinjaOne agent and Ninja Remote removal completed."
  return 0
}

# =============================
# Execute all steps
# =============================
run_step "Cleanup: Screen Lock Settings" cleanup_screenlock
run_step "Cleanup: Warning Banner" cleanup_warning_banner
run_step "Cleanup: Firewall Enforcements (keep ON)" cleanup_firewall
run_step "Cleanup: Password Policy Tokens" cleanup_password_policy
run_step "Cleanup: Autologin (cannot restore)" cleanup_autologin
run_step "Uninstall: NinjaOne Agent" uninstall_ninja_agent

echo
if [[ "$FAILURES" -gt 0 ]]; then
  echo "Completed with $FAILURES warning(s). See $LOG_PATH for details."
  exit 1
else
  echo "Cleanup and uninstall completed successfully. See $LOG_PATH for details."
  echo
  echo "NOTE: The device record still exists in the NinjaOne dashboard."
  echo "An admin must remove it via the Secureframe UI or NinjaOne console."
  exit 0
fi
