function cmd::group::list() {
  local groups_dir
  groups_dir="$(ctx::groups)"

  local groups=("${groups_dir}"/*.group)
  if [[ ! -f "${groups[0]}" ]]; then
    log::wg "No groups configured"
    return 0
  fi

  log::section "Groups"
  printf "\n  %-20s %-35s %-8s %s\n" "NAME" "DESCRIPTION" "PEERS" "STATUS"
  printf "  %s\n" "$(printf '─%.0s' {1..75})"

  while IFS="|" read -r name desc total blocked; do
    [[ -z "$name" ]] && continue

    local status_color="" status_str="active"
    if [[ "$total" -gt 0 ]]; then
      if [[ "$blocked" -eq "$total" ]]; then
        status_color="\033[1;31m"
        status_str="blocked"
      elif [[ "$blocked" -gt 0 ]]; then
        status_color="\033[1;33m"
        status_str="blocked (${blocked}/${total})"
      else
        status_color="\033[1;32m"
        status_str="active"
      fi
    fi

    local short_desc="${desc:0:33}"
    [[ ${#desc} -gt 33 ]] && short_desc="${short_desc}..."

    printf "  %-20s %-35s %-8s %b\n" \
      "$name" "${short_desc:-—}" "$total" \
      "${status_color}${status_str}\033[0m"
  done < <(json::group_list_data "$groups_dir" "$(ctx::blocks)")

  printf "\n"
}

function cmd::rule::list() {
  local rules_dir
  rules_dir="$(ctx::rules)"

  local rules=("${rules_dir}"/*.rule)
  if [[ ! -f "${rules[0]}" ]]; then
    log::wg "No rules configured"
    return 0
  fi

  log::section "Firewall Rules"
  printf "\n  %-20s %-45s %-8s %-8s %s\n" \
    "NAME" "DESCRIPTION" "ALLOWS" "BLOCKS" "PEERS"
  printf "  %s\n" "$(printf '─%.0s' {1..95})"

  while IFS="|" read -r name desc n_allows n_blocks peer_count; do
    [[ -z "$name" ]] && continue
    local short_desc="${desc:0:43}"
    [[ ${#desc} -gt 43 ]] && short_desc="${short_desc}..."
    printf "  %-20s %-45s %-8s %-8s %s\n" \
      "$name" "${short_desc:-—}" "$n_allows" "$n_blocks" "${peer_count} peers"
  done < <(json::rule_list_data "$rules_dir" "$(ctx::meta)")

  printf "\n"
}