function cmd::group::rename() {
  local name="" new_name=""

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name)     util::require_flag "--name" "${2:-}" || return 1; name="$2"; shift 2 ;;
      --new-name) util::require_flag "--new-name" "${2:-}" || return 1; new_name="$2"; shift 2 ;;
      --help) cmd::group::help; return ;;
      *) log::error "Unknown flag: $1"; return 1 ;;
    esac
  done

  [[ -z "$name" ]] && log::error "Missing required flag: --name" && return 1
  [[ -z "$new_name" ]] && log::error "Missing required flag: --new-name" && return 1
  group::require_exists "$name" || return 1

  if group::exists "$new_name"; then
    log::error "Group already exists: ${new_name}"
    return 1
  fi

  local old_file new_file
  old_file="$(group::path "$name")"
  new_file="$(group::path "$new_name")"

  # Update name field in file
  json::set "$old_file" "name" "\"$new_name\""
  mv "$old_file" "$new_file"

  log::wg_success "Group renamed: ${name} → ${new_name}"
}

function cmd::group::purge_stale() {
  local name="" force=false all=false
  local dry_run=false

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name)  util::require_flag "--name" "${2:-}" || return 1; name="$2"; shift 2 ;;
      --force) force=true;  shift ;;
      --all)   all=true;    shift ;;
      --dry-run) dry_run=true; shift ;;
      --help)  cmd::group::help; return ;;
      *) log::error "Unknown flag: $1"; return 1 ;;
    esac
  done
 
  [[ -z "$name" && "$all" == "false" ]] && \
    log::error "Specify --name <group> or --all" && return 1
 
  # Build list of groups to process
  local -a groups=()
  if $all; then
    while IFS= read -r group_file; do
      groups+=("$(basename "$group_file" .group)")
    done < <(find "$(ctx::groups)" -name "*.group" 2>/dev/null | sort)
  else
    group::require_exists "$name" || return 1
    groups=("$name")
  fi
 
  local total_removed=0 total_groups=0
 
  for group_name in "${groups[@]}"; do
    [[ -z "$group_name" ]] && continue
 
    # Find stale peers — in group but no .conf file
    local -a stale=()
    while IFS= read -r peer_name; do
      [[ -z "$peer_name" ]] && continue
      if [[ ! -f "$(ctx::clients)/${peer_name}.conf" ]]; then
        stale+=("$peer_name")
      fi
    done < <(group::peers "$group_name" 2>/dev/null)
 
    [[ ${#stale[@]} -eq 0 ]] && continue
 
    (( total_groups++ )) || true
 
    if ! $force; then
      printf "  Group '%s' has %d stale peer(s): %s\n" \
        "$group_name" "${#stale[@]}" "${stale[*]}"
      read -r -p "  Remove them? [y/N] " confirm
      case "$confirm" in
        [yY]*) ;;
        *) log::info "Skipped '${group_name}'"; continue ;;
      esac
    fi
 
    local group_file
    group_file="$(group::path "$group_name")"
    for peer_name in "${stale[@]}"; do
      if $dry_run; then
        printf "  \033[2m[dry-run]\033[0m Would remove '%s' from group '%s'\n" \
          "$peer_name" "$group_name"
      else
        json::remove "$group_file" "peers" "$peer_name" 2>/dev/null || true
        log::debug "Removed stale peer '${peer_name}' from group '${group_name}'"
      fi
      (( total_removed++ )) || true
    done
  done
 
  local action="Removed"
  $dry_run && action="Would remove"
  log::wg_success "${action} ${total_removed} stale peer(s)..."

  if $all; then
    if [[ "$total_removed" -eq 0 ]]; then
      log::wg_warning "No stale peers found in any group"
    else
      log::wg_success "${action} ${total_removed} stale peer(s)..."
    fi
  fi
}