#!/usr/bin/env bash

# ============================================
# Lifecycle
# ============================================

function cmd::group::on_load() {
  flag::register --name
  flag::register --desc
  flag::register --peer
  flag::register --type
  flag::register --rule
  flag::register --new-name
  flag::register --main
  flag::register --force
}

# ============================================
# Help
# ============================================

function cmd::group::help() {
  cat <<EOF
Usage: wgctl group <subcommand> [options]

Manage peer groups. Operations like block/unblock act on all peers in a group.
A peer can belong to multiple groups (M:N relationship).
Group blocks track which groups blocked a peer — unblocking one group won't
unblock a peer still blocked by another group.

Subcommands:
  list, ls                    List all groups
  show                        Show group members and their status
  add, new, create            Create a new group
  remove, rm, del             Remove a group definition
  rename                      Rename a group
  peer add                    Add a peer to a group
  peer remove, peer rm        Remove a peer from a group
  rm-peers                    Remove all peers in group from WireGuard
  block                       Block all peers in group
  unblock                     Unblock all peers in group
  rule assign                 Assign a rule to all peers in group
  audit                       Audit firewall rules for all peers in group
  logs                        Show activity logs for all peers in group
  watch                       Live monitor for all peers in group

Options:
  --name <name>               Group name
  --desc <description>        Group description (for add)
  --peer <peer>               Peer name
  --type <type>               Peer device type (optional)
  --rule <rule>               Rule name (for rule assign)
  --new-name <name>           New group name (for rename)
  --limit <n>                 Max log entries per peer (for logs)
  --force                     Skip confirmation prompts

Examples:
  wgctl group list
  wgctl group add --name family --desc "Family devices"
  wgctl group peer add --name family --peer phone-nuno
  wgctl group show --name family
  wgctl group block --name family
  wgctl group unblock --name family
  wgctl group rule assign --name family --rule user
  wgctl group audit --name family
  wgctl group logs --name family --limit 20
  wgctl group watch --name family
EOF
}

# ============================================
# Run
# ============================================

function cmd::group::run() {
  local subcmd="${1:-help}"
  shift || true

  case "$subcmd" in
    list|ls)              cmd::group::list "$@"        ;;
    show)                 cmd::group::show "$@"        ;;
    add|new|create)       cmd::group::add "$@"         ;;
    remove|rm|del|delete) cmd::group::remove "$@"      ;;
    rename)               cmd::group::rename "$@"      ;;
    peer)                 cmd::group::peer "$@"        ;;
    rm-peers)             cmd::group::rm_peers "$@"    ;;
    set-main)             cmd::group::set_main "$@"    ;;
    block)                cmd::group::block "$@"       ;;
    unblock)              cmd::group::unblock "$@"     ;;
    rule)                 cmd::group::rule "$@"        ;;
    audit)                cmd::group::audit "$@"       ;;
    logs)                 cmd::group::logs "$@"        ;;
    watch)                cmd::group::watch "$@"       ;;
    help)                 cmd::group::help             ;;
    *)
      log::error "Unknown subcommand: '${subcmd}'"
      cmd::group::help
      return 1
      ;;
  esac
}

# ============================================
# List
# ============================================

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}..."

    local desc_col_width=35
    [[ "$desc" == "—" || -z "$desc" ]] && desc_col_width=37

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

  printf "\n"
}

# ============================================
# Show
# ============================================

function cmd::group::show() {
  local name=""

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) util::require_flag "--name" "${2:-}" || return 1; 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
  group::require_exists "$name" || return 1

  local group_file
  group_file="$(group::path "$name")"

  log::section "Group: ${name}"

  local desc
  desc=$(json::get "$group_file" "desc")
  printf "\n  %-20s %s\n" "Description:" "${desc:-—}"

  # Load peers
  local peers_list=()
  mapfile -t peers_list < <(json::get "$group_file" "peers")
  # Filter empty entries
  local filtered=()
  for p in "${peers_list[@]:-}"; do
    [[ -n "$p" ]] && filtered+=("$p")
  done
  peers_list=("${filtered[@]:-}")
  local peer_count=${#peers_list[@]}

  [[ -z "${peers_list[0]}" ]] && peer_count=0

  printf "  %-20s %s\n" "Peers:" "$peer_count"
  printf "  %s\n" "$(printf '─%.0s' {1..50})"

  if [[ "$peer_count" -gt 0 ]]; then
    printf "\n  %-28s %-15s %-12s %s\n" "NAME" "IP" "RULE" "STATUS"
    printf "  %s\n" "$(printf '─%.0s' {1..65})"
    for peer_name in "${peers_list[@]}"; do
      [[ -z "$peer_name" ]] && continue

      # Skip if peer no longer exists
      if ! peers::require_exists "$peer_name" > /dev/null 2>&1; then
        log::wg_warning "Peer '${peer_name}' no longer exists — skipping"
        continue
      fi

      local ip rule status_str status_color
      ip=$(peers::get_ip "$peer_name")
      rule=$(peers::get_meta "$peer_name" "rule")
      rule="${rule:-—}"

      if peers::is_blocked "$peer_name" 2>/dev/null; then
        status_color="\033[1;31m"
        status_str="blocked"
      else
        status_color="\033[1;32m"
        status_str="active"
      fi

      printf "  %-28s %-15s %-12s %b\n" \
        "$peer_name" "0" "$rule" \
        "${status_str}\033[0m"
    done
  else
    printf "  —\n"
  fi

  printf "\n"
  return 0
}

# ============================================
# Add
# ============================================

function cmd::group::add() {
  local name="" desc=""

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) util::require_flag "--name" "${2:-}" || return 1; name="$2"; shift 2 ;;
      --desc) util::require_flag "--desc" "${2:-}" || return 1; desc="$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

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

  json::create_group "$(group::path "$name")" "$name" "$desc"

  log::wg_success "Group created: ${name}"
}

# ============================================
# Remove
# ============================================

function cmd::group::remove() {
  local name="" force=false

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

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

  if ! $force; then
    read -r -p "Remove group '${name}'? This only removes the group definition, not the peers. [y/N] " confirm
    case "$confirm" in
      [yY][eE][sS]|[yY]) ;;
      *) log::info "Aborted"; return 0 ;;
    esac
  fi

  rm -f "$(group::path "$name")"
  log::wg_success "Group removed: ${name}"
}

# ============================================
# Rename
# ============================================

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}"
}

# ============================================
# Peer subcommand
# ============================================

function cmd::group::peer() {
  local subcmd="${1:-help}"
  shift || true

  case "$subcmd" in
    add)           cmd::group::peer_add "$@"    ;;
    remove|rm|del) cmd::group::peer_remove "$@" ;;
    *)
      log::error "Unknown peer subcommand: '${subcmd}'"
      cmd::group::help
      return 1
      ;;
  esac
}

function cmd::group::peer_add() {
  local name="" peer="" type="" set_main=false

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) util::require_flag "--name" "${2:-}" || return 1; name="$2"; shift 2 ;;
      --peer) util::require_flag "--peer" "${2:-}" || return 1; peer="$2"; shift 2 ;;
      --type) util::require_flag "--type" "${2:-}" || return 1; type="$2"; shift 2 ;;
      --main) util::require_flag "--main" "${2:-}" || return 1; set_main=true; shift ;;
      --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 "$peer" ]] && log::error "Missing required flag: --peer" && return 1
  group::require_exists "$name" || return 1

  peer=$(peers::resolve_and_require "$peer" "$type") || return 1

  # Check if already in group
  if group::peers "$name" | grep -qF "$peer"; then
    log::wg_warning "'${peer}' is already in group '${name}'"
    return 0
  fi

  group::add_peer "$name" "$peer"
  log::wg_success "Added '${peer}' to group '${name}'"

  if $set_main; then
    peers::set_main_group "$peer_name" "$group_name"
    log::wg_success "Set '${group_name}' as main group for ${peer_name}"
  fi
}

function cmd::group::peer_remove() {
  local name="" peer="" type=""

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) util::require_flag "--name" "${2:-}" || return 1; name="$2"; shift 2 ;;
      --peer) util::require_flag "--peer" "${2:-}" || return 1; peer="$2"; shift 2 ;;
      --type) util::require_flag "--type" "${2:-}" || return 1; type="$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 "$peer" ]] && log::error "Missing required flag: --peer" && return 1
  group::require_exists "$name" || return 1

  peer=$(peers::resolve_and_require "$peer" "$type") || return 1
  group::remove_peer "$name" "$peer"
  log::wg_success "Removed '${peer}' from group '${name}'"
}

function cmd::group::set_main() {
  local group_name="" peer_name="" type=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) group_name="$2"; shift 2 ;;
      --peer) peer_name="$2";  shift 2 ;;
      --type) type="$2";       shift 2 ;;
      *) log::error "Unknown flag: $1"; return 1 ;;
    esac
  done

  [[ -z "$group_name" ]] && log::error "Missing --name" && return 1
  [[ -z "$peer_name"  ]] && log::error "Missing --peer" && return 1

  # Resolve peer name
  peer_name=$(peers::resolve_and_require "$peer_name" "$type") || return 1

  # Verify peer is in the group
  if ! group::has_peer "$group_name" "$peer_name"; then
    log::error "Peer '${peer_name}' is not in group '${group_name}'"
    log::info  "Add them first: wgctl group peer add --name ${group_name} --peer ${peer_name}"
    return 1
  fi

  peers::set_main_group "$peer_name" "$group_name"
  log::wg_success "Main group for '${peer_name}' set to '${group_name}'"
}

# ============================================
# Remove peers from WireGuard
# ============================================

function cmd::group::rm_peers() {
  local name="" force=false

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

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

  local peers_list=()
  mapfile -t peers_list < <(group::peers "$name")
  local peer_count=${#peers_list[@]}
  [[ -z "${peers_list[0]:-}" ]] && peer_count=0

  if [[ "$peer_count" -eq 0 ]]; then
    log::wg_warning "Group '${name}' has no peers"
    return 0
  fi

  if ! $force; then
    read -r -p "Remove all ${peer_count} peers in group '${name}' from WireGuard? [y/N] " confirm
    case "$confirm" in
      [yY][eE][sS]|[yY]) ;;
      *) log::info "Aborted"; return 0 ;;
    esac
  fi

  load_command remove
  group::each_peer "$name" cmd::group::_rm_peer_cb
  log::wg_success "Removed peers from group '${name}' (definition kept)"
}

function cmd::group::_rm_peer_cb() {
  local peer_name="${1:-}"
  if ! group::_peer_exists_check "$peer_name"; then
    log::wg_warning "Peer '${peer_name}' no longer exists — skipping"
    return 0
  fi
  cmd::remove::run --name "$peer_name" --force
}

# ============================================
# Block / Unblock
# ============================================

function cmd::group::block() {
  local name="" force=false

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

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

  local peers_list=()
  mapfile -t peers_list < <(group::peers "$name")
  
  if [[ ${#peers_list[@]} -eq 0 ]] || [[ -z "${peers_list[0]:-}" ]]; then
    log::wg_warning "Group '${name}' has no peers"
    return 0
  fi

  local count=0 skipped=0 blocked_names=()
  local filtered=()
  for p in "${peers_list[@]:-}"; do
    [[ -n "$p" ]] && filtered+=("$p")
  done
  [[ ${#filtered[@]} -eq 0 ]] && log::wg_warning "Group '${name}' has no peers" && return 0

  for peer_name in "${filtered[@]}"; do
    if cmd::group::_block_peer "$peer_name" "$name"; then
      (( count++ )) || true
    else
      (( skipped++ )) || true
    fi
  done

  if [[ "$count" -gt 0 ]]; then
    log::wg_block "All peers from ${name} have been blocked (${count} peers)."
  fi

  if [[ "$skipped" -gt 0 ]]; then
    log::wg_warning "${skipped} peers already blocked"
  fi
}

function cmd::group::unblock() {
  local name="" force=false

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

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

  local peers_list=()
  mapfile -t peers_list < <(group::peers "$name")

  local filtered=()
  for p in "${peers_list[@]:-}"; do [[ -n "$p" ]] && filtered+=("$p"); done
  [[ ${#filtered[@]} -eq 0 ]] && log::wg_warning "Group '${name}' has no peers" && return 0

  local count=0 skipped=0

  for peer_name in "${filtered[@]}"; do
    if cmd::group::_unblock_peer "$peer_name" "$name"; then
      (( count++ )) || true
    else
      (( skipped++ )) || true
    fi
  done

  if [[ "$count" -gt 0 ]]; then
    log::wg_unblock "All peers from ${name} have been unblocked."
  fi

  if [[ "$skipped" -gt 0 ]]; then
    log::wg_warning "${skipped} peer(s) remain blocked (blocked directly or by other groups)"
  fi
}

function cmd::group::_block_peer() {
  local peer_name="${1:-}" group_name="${2:-}"
  if ! group::_peer_exists_check "$peer_name"; then
    log::wg_warning "Peer '${peer_name}' no longer exists — skipping"
    return 0
  fi

  local client_ip
  client_ip=$(peers::get_ip "$peer_name")

  # Check if already blocked by this group
  local current_blocked_groups
  current_blocked_groups=$(block::get_groups "$peer_name")

  local IFS=','
  for g in $current_blocked_groups; do
    if [[ "$g" == "$group_name" ]]; then
      log::wg_warning "${peer_name} — already blocked by group '${group_name}'"
      return 1
    fi
  done

  # Add group to block tracking
  block::add_group "$peer_name" "$client_ip" "$group_name"

  # Apply fw rules only if peer is still in WG server (not yet blocked)
  if peers::exists_in_server "$peer_name"; then
    block::apply_full "$peer_name" "$client_ip"
  fi
}

function cmd::group::_unblock_peer() {
  local peer_name="${1:-}" group_name="${2:-}"

  if ! group::_peer_exists_check "$peer_name"; then
    log::wg_warning "Peer '${peer_name}' no longer exists — skipping"
    return 1
  fi

  # Check if blocked by this group at all
  if ! block::has_file "$peer_name"; then
    log::wg_warning "${peer_name} — not blocked"
    return 1
  fi

  local current_groups
  current_groups=$(block::get_groups "$peer_name")
  if [[ "$current_groups" != *"$group_name"* ]]; then
    log::wg_warning "${peer_name} — not blocked by group '${group_name}'"
    return 1
  fi

  local client_ip
  client_ip=$(peers::get_ip "$peer_name")

  block::remove_group "$peer_name" "$client_ip" "$group_name"

  if block::is_blocked "$peer_name"; then
    local groups
    groups=$(block::get_groups "$peer_name")

    local direct
    direct=$(block::is_blocked_direct "$peer_name")

    if [[ "$direct" == "true" ]]; then
      log::wg_warning "${peer_name} — still blocked directly, skipping"
    else
      log::wg_warning "${peer_name} — still blocked by group(s): ${groups}, skipping"
    fi

    return 1
  fi

  block::restore_peer "$peer_name" "$client_ip"
  block::remove_file "$peer_name"

  local rule
  rule=$(peers::get_meta "$peer_name" "rule")

  [[ -n "$rule" ]] && rule::exists "$rule" && \
    rule::apply "$rule" "$client_ip" "$peer_name"
}

# ============================================
# Rule assign
# ============================================

function cmd::group::rule() {
  local subcmd="${1:-help}"
  shift || true
  case "$subcmd" in
    assign) cmd::group::rule_assign "$@" ;;
    *)
      log::error "Unknown rule subcommand: '${subcmd}'"
      cmd::group::help
      return 1
      ;;
  esac
}

function cmd::group::rule_assign() {
  local name="" rule=""

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) util::require_flag "--name" "${2:-}" || return 1; name="$2"; shift 2 ;;
      --rule) util::require_flag "--rule" "${2:-}" || return 1; rule="$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 "$rule" ]] && log::error "Missing required flag: --rule" && return 1
  group::require_exists "$name" || return 1
  rule::require_exists "$rule"  || return 1

  local peers_list=()
  mapfile -t peers_list < <(group::peers "$name")
  [[ -z "${peers_list[0]:-}" ]] && log::wg_warning "Group '${name}' has no peers" && return 0

  group::each_peer "$name" cmd::group::_rule_assign_cb "$rule"
  log::wg_success "Assigned rule '${rule}' to group '${name}'"
}

function cmd::group::_rule_assign_cb() {
  local peer_name="${1:-}" rule="${2:-}"
  if ! group::_peer_exists_check "$peer_name"; then
    log::wg_warning "Peer '${peer_name}' no longer exists — skipping"
    return 0
  fi
  load_command rule
  cmd::rule::assign --name "$rule" --peer "$peer_name"
}

# ============================================
# Audit
# ============================================

function cmd::group::audit() {
  local name=""

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) util::require_flag "--name" "${2:-}" || return 1; 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
  group::require_exists "$name" || return 1

  local peers_list=()
  mapfile -t peers_list < <(group::peers "$name")
  [[ -z "${peers_list[0]}" ]] && log::wg_warning "Group '${name}' has no peers" && return 0

  # Run audit filtered to group peers
  load_command audit
  # Pass first peer as filter — audit handles the rest per-peer
  # Actually run full audit and filter output
  local peer_args=()
  for peer_name in "${peers_list[@]}"; do
    [[ -z "$peer_name" ]] && continue
    peer_args+=("$peer_name")
  done

  test::reset
  log::section "Audit: Group '${name}'"

  # Precompute fw counts
  declare -A peer_fw_counts
  while IFS=":" read -r pname count; do
    [[ -n "$pname" ]] && peer_fw_counts["$pname"]="$count"
  done < <(json::audit_fw_counts "$(ctx::clients)")

  test::section "Peer Rules"
  for peer_name in "${peer_args[@]}"; do
    # Skip if peer no longer exists
    if ! peers::require_exists "$peer_name" > /dev/null 2>&1; then
      log::wg_warning "Peer '${peer_name}' no longer exists — skipping"
      continue
    fi
    cmd::audit::check_peer "$peer_name" false "${peer_fw_counts[$peer_name]:-0}"
  done

  test::summary
}

# ============================================
# Logs
# ============================================

function cmd::group::logs() {
  local name="" limit=50

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name)  util::require_flag "--name" "${2:-}" || return 1; name="$2"; shift 2 ;;
      --limit) util::require_flag "--limit" "${2:-}" || return 1; limit="$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
  group::require_exists "$name" || return 1

  local peers_list=()
  mapfile -t peers_list < <(group::peers "$name")
  [[ -z "${peers_list[0]}" ]] && log::wg_warning "Group '${name}' has no peers" && return 0

  log::section "Logs: Group '${name}'"

  for peer_name in "${peers_list[@]}"; do
    [[ -z "$peer_name" ]] && continue
    # Skip if peer no longer exists
    if ! peers::require_exists "$peer_name" > /dev/null 2>&1; then
      log::wg_warning "Peer '${peer_name}' no longer exists — skipping"
      continue
    fi
    printf "\n  \033[1;37m── %s ──\033[0m\n" "$peer_name"
    load_command logs
    cmd::logs::show --name "$peer_name" --limit "$limit"
  done
}

# ============================================
# Watch
# ============================================

function cmd::group::watch() {
  local name=""

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name) util::require_flag "--name" "${2:-}" || return 1; 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
  group::require_exists "$name" || return 1

  local peers_list=()
  mapfile -t peers_list < <(group::peers "$name")
  [[ -z "${peers_list[0]}" ]] && log::wg_warning "Group '${name}' has no peers" && return 0

  local peer_filter
  peer_filter=$(IFS=','; echo "${peers_list[*]}")

  # Build comma-separated peer list for watch filter
  # Watch already supports --type filter but not multiple peers
  # For now, use follow mode filtered to group peers one at a time
  # or just run watch with no filter (shows all, user sees group context)
  log::section "Live Monitor: Group '${name}'"
  printf "  Monitoring: %s\n\n" "${peers_list[*]}"

  load_command watch
  cmd::watch::run --peers "$peer_filter"
}
