#!/usr/bin/env bash
# audit_resources.sh — Monitor CPU, memory, disk, battery on macOS
# Output: JSON lines to stdout, one per finding
set -euo pipefail

json_escape() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g' | tr '\n' ' '; }

json_finding() {
  local severity="$1" finding action details
  finding=$(json_escape "$2")
  action=$(json_escape "$3")
  details=$(json_escape "$4")
  printf '{"module":"resources","severity":"%s","finding":"%s","action":"%s","details":"%s"}\n' \
    "$severity" "$finding" "$action" "$details"
}

# Process deny-list (never suggest termination)
DENY_LIST="kernel_task|launchd|WindowServer|loginwindow|mds|mds_stores|opendirectoryd|coreaudiod|SystemUIServer|Finder|Dock"

# --- CPU ---
load_avg=$(sysctl -n vm.loadavg 2>/dev/null | tr -d '{}' | awk '{print $1}')
cpu_count=$(sysctl -n hw.ncpu 2>/dev/null || echo 1)

if command -v python3 &>/dev/null; then
  cpu_severity=$(python3 -c "
load=$load_avg; cores=$cpu_count
if load > cores * 2: print('critical')
elif load > cores: print('warning')
else: print('info')
" 2>/dev/null || echo "info")
else
  cpu_severity="info"
fi

json_finding "$cpu_severity" "Load average: ${load_avg} (${cpu_count} cores)" "review" ""

# Top CPU-consuming processes (excluding deny-list from action suggestions)
top_cpu=$(ps aux | sort -nrk 3 | head -5 || echo "")
if [ -n "$top_cpu" ]; then
  while IFS= read -r line; do
    proc_name=$(echo "$line" | awk '{print $11}' | xargs basename 2>/dev/null || echo "unknown")
    cpu_pct=$(echo "$line" | awk '{print $3}')
    mem_pct=$(echo "$line" | awk '{print $4}')
    pid=$(echo "$line" | awk '{print $2}')

    # Skip low-usage processes
    is_high=$(python3 -c "print('yes' if float('${cpu_pct}') > 10 else 'no')" 2>/dev/null || echo "no")
    if [ "$is_high" = "yes" ]; then
      if echo "$proc_name" | grep -qE "$DENY_LIST"; then
        json_finding "info" "High CPU: ${proc_name} (${cpu_pct}% CPU, PID ${pid})" "none" "System process - do not terminate"
      else
        json_finding "warning" "High CPU: ${proc_name} (${cpu_pct}% CPU, PID ${pid})" "quit" "User process - can be terminated"
      fi
    fi
  done <<< "$top_cpu"
fi

# --- Memory ---
vm_stat_output=$(vm_stat 2>/dev/null || echo "")
if [ -n "$vm_stat_output" ]; then
  page_size=$(vm_stat | head -1 | grep -o '[0-9]*' || echo 16384)

  free_pages=$(echo "$vm_stat_output" | grep "Pages free" | awk '{print $3}' | tr -d '.')
  active_pages=$(echo "$vm_stat_output" | grep "Pages active" | awk '{print $3}' | tr -d '.')
  inactive_pages=$(echo "$vm_stat_output" | grep "Pages inactive" | awk '{print $3}' | tr -d '.')
  wired_pages=$(echo "$vm_stat_output" | grep "Pages wired" | awk '{print $4}' | tr -d '.')
  compressed_pages=$(echo "$vm_stat_output" | grep "Pages stored in compressor" | awk '{print $5}' | tr -d '.' || echo 0)

  if command -v python3 &>/dev/null; then
    mem_summary=$(python3 -c "
ps=${page_size}
free_mb = int(${free_pages:-0}) * ps / 1048576
active_mb = int(${active_pages:-0}) * ps / 1048576
inactive_mb = int(${inactive_pages:-0}) * ps / 1048576
wired_mb = int(${wired_pages:-0}) * ps / 1048576
compressed_mb = int(${compressed_pages:-0}) * ps / 1048576
used_mb = active_mb + wired_mb + compressed_mb
total_mb = free_mb + active_mb + inactive_mb + wired_mb + compressed_mb
pct = used_mb / total_mb * 100 if total_mb > 0 else 0
print(f'{used_mb:.0f}MB used / {total_mb:.0f}MB total ({pct:.0f}%)')
if pct > 90: print('SEVERITY:critical')
elif pct > 75: print('SEVERITY:warning')
else: print('SEVERITY:info')
" 2>/dev/null || echo "unknown")
    mem_severity=$(echo "$mem_summary" | grep "SEVERITY:" | cut -d: -f2)
    mem_info=$(echo "$mem_summary" | head -1)
    json_finding "${mem_severity:-info}" "Memory: ${mem_info}" "review" ""
  fi
fi

# --- Swap ---
swap_info=$(sysctl vm.swapusage 2>/dev/null || echo "")
if [ -n "$swap_info" ]; then
  swap_used=$(echo "$swap_info" | grep -o "used = [0-9.]*M" | awk '{print $3}' | tr -d 'M')
  if [ -n "$swap_used" ] && command -v python3 &>/dev/null; then
    swap_severity=$(python3 -c "
s=float('${swap_used}')
if s > 4096: print('warning')
elif s > 1024: print('info')
else: print('info')
" 2>/dev/null || echo "info")
    json_finding "$swap_severity" "Swap: ${swap_used}MB used" "review" "$swap_info"
  fi
fi

# --- Disk usage ---
disk_info=$(df -h / 2>/dev/null | tail -1)
if [ -n "$disk_info" ]; then
  disk_used_pct=$(echo "$disk_info" | awk '{print $5}' | tr -d '%')
  disk_avail=$(echo "$disk_info" | awk '{print $4}')
  disk_total=$(echo "$disk_info" | awk '{print $2}')

  if [ "$disk_used_pct" -gt 90 ] 2>/dev/null; then
    json_finding "critical" "Disk ${disk_used_pct}% full (${disk_avail} free of ${disk_total})" "cleanup" "Consider running cleanup module"
  elif [ "$disk_used_pct" -gt 75 ] 2>/dev/null; then
    json_finding "warning" "Disk ${disk_used_pct}% full (${disk_avail} free of ${disk_total})" "monitor" ""
  else
    json_finding "info" "Disk ${disk_used_pct}% full (${disk_avail} free of ${disk_total})" "none" ""
  fi
fi

# --- Large directories (top 5 in home) ---
if command -v du &>/dev/null; then
  large_dirs=$(du -sh "$HOME"/*/ "$HOME"/.[!.]* 2>/dev/null | sort -hr | head -5 || echo "")
  if [ -n "$large_dirs" ]; then
    dir_summary=$(echo "$large_dirs" | awk '{printf "%s (%s), ", $2, $1}' | sed 's/, $//')
    json_finding "info" "Largest directories in home" "review" "$dir_summary"
  fi
fi

# --- Battery (laptops only) ---
battery_info=$(system_profiler SPPowerDataType 2>/dev/null || echo "")
if echo "$battery_info" | grep -q "Cycle Count"; then
  cycle_count=$(echo "$battery_info" | grep "Cycle Count" | awk '{print $NF}')
  condition=$(echo "$battery_info" | grep "Condition" | awk '{print $NF}')
  max_capacity=$(echo "$battery_info" | grep "Maximum Capacity" | awk '{print $NF}' || echo "unknown")

  if [ "$condition" = "Normal" ]; then
    json_finding "info" "Battery: ${condition}, ${cycle_count} cycles, ${max_capacity} capacity" "none" ""
  else
    json_finding "warning" "Battery: ${condition}, ${cycle_count} cycles, ${max_capacity} capacity" "review" "Battery may need service"
  fi
fi
