#!/usr/bin/env bash
# Collect targeted memory diagnostics for a macOS process.
# Produces 4 files (vmmap, heap, leaks, spindump) and a ZIP on the Desktop.

set -u

require_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "WARN: '$1' is not available. This step will be skipped."
    return 1
  fi
  return 0
}

read -r -p "Enter the application name (as shown in Activity Monitor, e.g., 'YourApp' — '.app' optional): " APP_INPUT
APP_NAME="${APP_INPUT%.app}"

if [[ -z "${APP_NAME}" ]]; then
  echo "ERROR: No application name provided."
  exit 1
fi

# Try to find PID(s)
pids=$(pgrep -x "${APP_NAME}" || true)

# Fallback: match the app bundle main binary path if pgrep -x fails
if [[ -z "${pids}" ]]; then
  pids=$(pgrep -f "${APP_NAME}.app/Contents/MacOS/${APP_NAME}" || true)
fi

if [[ -z "${pids}" ]]; then
  echo "ERROR: Could not find a running process matching '${APP_NAME}'."
  echo "Tip: Ensure the app is running and use the exact process name from Activity Monitor."
  exit 1
fi

# If multiple PIDs, let the user choose
if [[ $(wc -w <<<"${pids}") -gt 1 ]]; then
  echo "Multiple processes found for '${APP_NAME}':"
  i=1
  declare -a PID_LIST
  while read -r pid; do
    comm=$(ps -o comm= -p "${pid}" 2>/dev/null || echo "")
    echo "  [$i] PID=${pid}  COMM=${comm}"
    PID_LIST[$i]="${pid}"
    ((i++))
  done <<< "${pids}"

  read -r -p "Select the number of the PID to diagnose: " choice
  if ! [[ "${choice}" =~ ^[0-9]+$ ]] || [[ -z "${PID_LIST[$choice]:-}" ]]; then
    echo "ERROR: Invalid selection."
    exit 1
  fi
  PID="${PID_LIST[$choice]}"
else
  PID="${pids}"
fi

# Sanitize name for filenames
safe_app="$(echo "${APP_NAME}" | tr -cs '[:alnum:]_-' '_')"
ts="$(date +"%Y%m%d_%H%M%S")"

# Output directory on Desktop
OUT_DIR="${HOME}/Desktop/${safe_app}_diagnostics_${ts}"
mkdir -p "${OUT_DIR}"

echo "Using PID=${PID} for '${APP_NAME}'."
echo "Saving outputs to: ${OUT_DIR}"
echo

generated_files=()

# 1) vmmap -summary
if require_cmd vmmap; then
  vmmap_out="${OUT_DIR}/vmmap_${safe_app}_${ts}.txt"
  echo "Running: vmmap -summary ${PID}"
  if vmmap -summary "${PID}" > "${vmmap_out}" 2>&1; then
    generated_files+=("${vmmap_out}")
    echo "  -> ${vmmap_out}"
  else
    echo "WARN: vmmap failed. See ${vmmap_out} for details."
  fi
fi
echo

# 2) heap
if require_cmd heap; then
  heap_out="${OUT_DIR}/heap_${safe_app}_${ts}.txt"
  echo "Running: heap ${PID}"
  if heap "${PID}" > "${heap_out}" 2>&1; then
    generated_files+=("${heap_out}")
    echo "  -> ${heap_out}"
  else
    echo "WARN: heap failed. See ${heap_out} for details."
  fi
fi
echo

# 3) leaks
if require_cmd leaks; then
  leaks_out="${OUT_DIR}/leaks_${safe_app}_${ts}.txt"
  echo "Running: leaks ${PID} (this may take a while)"
  if leaks "${PID}" > "${leaks_out}" 2>&1; then
    generated_files+=("${leaks_out}")
    echo "  -> ${leaks_out}"
  else
    echo "WARN: leaks failed. See ${leaks_out} for details."
  fi
fi
echo

# 4) spindump (process-specific). Requires sudo.
if require_cmd spindump; then
  spindump_out="${OUT_DIR}/spindump_${safe_app}_${ts}.spindump"
  echo "Running: sudo spindump -i ${PID} -file ${spindump_out}"
  echo "Note: You may be prompted for your password to run spindump."
  if sudo spindump "${PID}" -file "${spindump_out}" >/dev/null 2>&1; then
    generated_files+=("${spindump_out}")
    echo "  -> ${spindump_out}"
  else
    echo "WARN: spindump failed (or was cancelled)."
  fi
fi
echo

# Create ZIP on Desktop
zip_path="${HOME}/Desktop/${safe_app}_diagnostics_${ts}.zip"
echo "Creating ZIP: ${zip_path}"
(
  cd "${OUT_DIR}" || exit 1
  # -r to include all files we generated (keep directory structure simple)
  if command -v zip >/dev/null 2>&1; then
    zip -r "${zip_path}" . >/dev/null
  else
    echo "WARN: 'zip' command not found. Skipping archive creation."
    zip_path=""
  fi
)

echo
echo "Done."
if [[ -n "${zip_path}" && -f "${zip_path}" ]]; then
  echo "Archive created: ${zip_path}"
  echo "You can attach this ZIP to your support ticket."
else
  echo "No ZIP archive was created. Individual files are in: ${OUT_DIR}"
fi