# ui::_render_endpoint_col
# Builds padded endpoint string: "raw_ip → resolved" or "raw_ip" or "-"
# Args: endpoint resolved w_endpoint
# Returns: padded colored string via stdout
function ui::_render_endpoint_col() {
  local endpoint="${1:-}" resolved="${2:-}" w_endpoint="${3:-20}"
  local colored visible_len pad_n
 
  if [[ -n "$endpoint" ]]; then
    if [[ -n "$resolved" ]]; then
      colored="${endpoint} \033[2m→ ${resolved}\033[0m"
      visible_len=$(( ${#endpoint} + 3 + ${#resolved} ))
    else
      colored="$endpoint"
      visible_len=${#endpoint}
    fi
  else
    colored="\033[2m—\033[0m"
    visible_len=1
  fi
 
  pad_n=$(( w_endpoint - visible_len ))
  [[ $pad_n -lt 0 ]] && pad_n=0
  printf "%b%*s" "$colored" "$pad_n" ""
}
# ui::_render_dest_col
# Builds padded destination string: "svc/proto (ip:port)" or raw
# Args: dest_ip dest_port proto svc_name w_dest resolved_only
# Returns: two vars via nameref — dest_colored dest_pad_n
function ui::_build_dest() {
  local dest_ip="${1:-}" dest_port="${2:-}" proto="${3:-}" \
        svc_name="${4:-}" w_dest="${5:-20}" resolved_only="${6:-false}"
  local svc_display raw_suffix="" raw_plain=""
 
  if [[ -n "$svc_name" ]]; then
    [[ -n "$dest_port" ]] && svc_display="${svc_name}/${proto}" \
                          || svc_display="${svc_name} (${proto})"
    if ! $resolved_only; then
      [[ -n "$dest_port" ]] && raw_suffix=" \033[2m(${dest_ip}:${dest_port})\033[0m" \
                            || raw_suffix=" \033[2m(${dest_ip})\033[0m"
      [[ -n "$dest_port" ]] && raw_plain=" (${dest_ip}:${dest_port})" \
                            || raw_plain=" (${dest_ip})"
    fi
  else
    [[ -n "$dest_port" ]] && svc_display="${dest_ip}:${dest_port}/${proto}" \
                          || svc_display="${dest_ip} (${proto})"
  fi
 
  local full_len=$(( ${#svc_display} + ${#raw_plain} ))
  local dest_pad_n=$(( w_dest - full_len ))
  [[ $dest_pad_n -lt 0 ]] && dest_pad_n=0
 
  # Output: svc_display|raw_suffix|dest_pad_n
  printf "%s\t%s\t%s" "$svc_display" "$raw_suffix" "$dest_pad_n"
}
function ui::watch::fw_row() {
  local ts="${1:-}" client="${2:-}" dest_ip="${3:-}" dest_port="${4:-}" \
        proto="${5:-}" svc_name="${6:-}" \
        src_endpoint="${7:-}" src_resolved="${8:-}" \
        w_client="${9:-20}" w_dest="${10:-18}" w_endpoint="${11:-0}"
 
  local ts_pad client_pad
  ts_pad=$(printf "%-11s" "$ts")
  client_pad=$(printf "%-${w_client}s" "$client")
 
  local dest_parts
  dest_parts=$(ui::_build_dest "$dest_ip" "$dest_port" "$proto" "$svc_name" "$w_dest" "false")
  local svc_display raw_suffix dest_pad_n
  IFS=$'\t' read -r svc_display raw_suffix dest_pad_n <<< "$dest_parts"
 
  if [[ "$w_endpoint" -gt 0 ]]; then
    local src_padded
    src_padded=$(ui::_render_endpoint_col "$src_endpoint" "$src_resolved" "$w_endpoint")
    printf "  %s  %s  %s  \033[1;31m→\033[0m %s%b%*s  \033[1;31mdrop\033[0m\n" \
      "$ts_pad" "$client_pad" "$src_padded" \
      "$svc_display" "$raw_suffix" "$dest_pad_n" ""
  else
    printf "  %s  %s  \033[1;31m→\033[0m %s%b%*s  \033[1;31mdrop\033[0m\n" \
      "$ts_pad" "$client_pad" \
      "$svc_display" "$raw_suffix" "$dest_pad_n" ""
  fi
}

 
function ui::watch::wg_row() {
  local ts="${1:-}" client="${2:-}" endpoint="${3:-}" event="${4:-}" \
        src_resolved="${5:-}" \
        w_client="${6:-20}" w_endpoint="${7:-18}"
 
  local event_color
  case "$event" in
    handshake) event_color="\033[1;32m" ;;
    attempt)   event_color="\033[1;31m" ;;
    *)         event_color="\033[0;37m" ;;
  esac
 
  local ep_padded
  ep_padded=$(ui::_render_endpoint_col "$endpoint" "$src_resolved" "$w_endpoint")
 
  local ts_pad client_pad
  ts_pad=$(printf "%-11s" "$ts")
  client_pad=$(printf "%-${w_client}s" "$client")
 
  printf "  %s  %s  %s  %b%s\033[0m\n" \
    "$ts_pad" "$client_pad" "$ep_padded" \
    "$event_color" "$event"
}
 