#!/usr/bin/env bash

function cmd::inspect::on_load() {
  flag::register --name
  flag::register --type
  flag::register --config
  flag::register --qr
}

function cmd::inspect::help() {
  cat <<EOF
Usage: wgctl inspect --name <name> [--type <type>]
       wgctl inspect <full-name>

Show detailed information for a single client.

Options:
  --name <name>     Client name
  --type <type>     Device type (optional, combines with --name)
  --config          Show raw client config
  --qr              Show QR code

Examples:
  wgctl inspect --name phone-nuno
  wgctl inspect --name nuno --type phone
  wgctl inspect --name phone-nuno --config
  wgctl inspect --name phone-nuno --qr
EOF
}

# ============================================
# Private helpers
# ============================================

function cmd::inspect::_section() {
  local title="$1"
  printf "\n  \033[0;37m── %s ──────────────────────────────────\033[0m\n" "$title"
}

function cmd::inspect::_peer_info() {
  local name="${1:-}"

  local ip type rule public_key allowed_ips
  ip=$(peers::get_ip "$name")
  type=$(peers::get_type "$name")
  rule=$(peers::get_meta "$name" "rule")
  public_key=$(keys::public "$name" 2>/dev/null || echo "")
  allowed_ips=$(grep "^AllowedIPs" "$(ctx::clients)/${name}.conf" \
    2>/dev/null | cut -d'=' -f2- | xargs)

  # Status
  local handshake_ts is_blocked last_ts
  handshake_ts=$(monitor::get_handshake_ts "$public_key")
  peers::is_blocked "$name" && is_blocked="true" || is_blocked="false"
  last_ts=$(monitor::last_attempt "$name")

  local status last_seen endpoint
  status=$(peers::format_status "$name" "$public_key" \
    "$is_blocked" "false" "$handshake_ts" "$last_ts")
  last_seen=$(peers::format_last_seen "$name" "$public_key" \
    "$is_blocked" "$last_ts" "" "$handshake_ts")
  endpoint=$(monitor::get_cached_endpoint "$name")

  local activity_total
  activity_total=$(peers::format_activity_total "$public_key")

  local activity_current
  activity_current=$(peers::format_activity_current "$public_key")

  local subtype
  subtype=$(peers::get_meta "$name" "subtype")

  cmd::inspect::_section "Client"
  ui::row "Name"       "$name"
  ui::row "IP"         "$ip"
  ui::row "Type"       "$(peers::display_type "$type" "$subtype")"
  ui::row "Rule"       "${rule:-—}"
  ui::row "Status"     "$(echo -e "$status")"
  ui::row "Endpoint"   "${endpoint:-—}"
  ui::row "Last seen"  "$last_seen"
  ui::row "AllowedIPs" "$allowed_ips"
  ui::row "Public key" "${public_key:-—}"
  ui::row "Activity"   "Total: $activity_total | Current: $activity_current"
}

function cmd::inspect::_rule_info() {
  local name="$1"
  local rule
  rule=$(peers::get_meta "$name" "rule")
  [[ -z "$rule" ]] && return 0

  rule::exists "$rule" || return 0

  local rule_file
  rule_file="$(ctx::rule::path "${rule}.rule")"

  ui::section "Rule: ${rule}"

  local desc dns_redirect
  desc=$(json::get "$rule_file" "desc")
  dns_redirect=$(json::get "$rule_file" "dns_redirect")
  ui::row "Description" "${desc:-—}"
  ui::row "DNS Redirect" "${dns_redirect:-false}"

  local allow_ports allow_ips block_ips block_ports
  allow_ports=$(json::get "$rule_file" "allow_ports")
  allow_ips=$(json::get "$rule_file" "allow_ips")
  block_ips=$(json::get "$rule_file" "block_ips")
  block_ports=$(json::get "$rule_file" "block_ports")

  if [[ -n "$allow_ports" || -n "$allow_ips" ]]; then
    printf "  %-20s\n" "Allows:"
    ui::print_list "+" "$allow_ports"
    ui::print_list "+" "$allow_ips"
  else
    ui::row "Allows" "—"
  fi

  if [[ -n "$block_ips" || -n "$block_ports" ]]; then
    printf "  %-20s\n" "Blocks:"
    ui::print_list "-" "$block_ips"
    ui::print_list "-" "$block_ports"
  else
    ui::row "Blocks" "—"
  fi
}

function cmd::inspect::_group_info() {
  local name="$1"

  ui::section "Groups"

  local groups=()
  mapfile -t groups < <(json::peer_groups "$(ctx::groups)" "$name")

  if [[ ${#groups[@]} -eq 0 ]] || [[ -z "${groups[0]:-}" ]]; then
    printf "  —\n"
    return 0
  fi

  for g in "${groups[@]}"; do
    [[ -z "$g" ]] && continue
    local count
    count=$(json::count "$(group::path "$g")" "peers")
    printf "  %-20s %s peers\n" "$g" "$count"
  done
}

function cmd::inspect::_firewall_info() {
  local name="$1" show_nflog="${2:-false}"
  local ip
  ip=$(peers::get_ip "$name")

  ui::section "Firewall"

  local count=0
  while IFS=":" read -r pname pcount; do
    [[ "$pname" == "$name" ]] && count="$pcount" && break
  done < <(json::audit_fw_counts "$(ctx::clients)")

  ui::row "Active rules" "$count"

if [[ "$count" -gt 0 ]]; then
    printf "\n"
    iptables -L FORWARD -n </dev/null | grep -F "$ip" | while IFS= read -r rule; do
      [[ -z "$rule" ]] && continue
      echo "$rule" | grep -q "NFLOG" && continue  # skip NFLOG
      ui::firewall_rule "$rule"
    done
  fi
}

function cmd::inspect::_config() {
  local name="$1"
  cmd::inspect::_section "Config"
  printf "\n"
  cat "$(ctx::clients)/${name}.conf"
  printf "\n"
}

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

function cmd::inspect::run() {
  local name="" type="" show_config=false show_qr=false

  if [[ $# -gt 0 && "$1" != "--"* ]]; then
    name="$1"
    shift
  fi

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name)   name="$2";             shift 2 ;;
      --type)   type="$2";             shift 2 ;;
      --config) show_config=true;      shift   ;;
      --qr)     show_qr=true;          shift   ;;
      --help)   cmd::inspect::help;    return  ;;
      *)
        log::error "Unknown flag: $1"
        cmd::inspect::help
        return 1
        ;;
    esac
  done

  if [[ -z "$name" ]]; then
    log::error "Missing required flag: --name"
    cmd::inspect::help
    return 1
  fi

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

  load_command list

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

  cmd::inspect::_peer_info "$name"
  cmd::inspect::_rule_info "$name"
  cmd::inspect::_group_info "$name"
  cmd::inspect::_firewall_info "$name"

  if $show_config; then
    cmd::inspect::_config "$name"
  fi

  if $show_qr; then
    cmd::inspect::_section "QR Code"
    printf "\n"
    load_command qr
    cmd::qr::run --name "$name"
  fi

  printf "\n"
}