#!/usr/bin/env bash
set -Eeuo pipefail

source "$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)/core.sh"

LOG_LEVEL=DEBUG

# ============================================
# Modules
# ============================================

load_module log
load_module config
load_module ip
load_module keys
load_module peers
load_module firewall
load_module monitor
load_module rule
load_module group

# ============================================
# Alias Map
# ============================================

declare -A CMD_ALIASES=(
  # Client
  [new]=add
  [create]=add
  [rm]=remove
  [del]=remove
  [delete]=remove
  [mv]=rename
  [ls]=list
  [show]=list
  [monitor]=watch
  [ban]=block

  # Service
  [up]=service
  [down]=service
  [reload]=service
  [stat]=service
  [log]=service
  [start]=service
  [stop]=service
  [restart]=service
  [status]=service
  [enable]=service
  [disable]=service
)


# ============================================
# Dispatch
# ============================================

function wgctl::resolve_alias() {
  local cmd="$1"
  echo "${CMD_ALIASES[$cmd]:-$cmd}"
}

function wgctl::dispatch() {
  local raw_cmd="${1:-help}"
  shift || true

  local cmd
  cmd="$(wgctl::resolve_alias "$raw_cmd")"

  case "$cmd" in
    help) wgctl::help; return ;;
  esac

  # If alias resolved to service, pass original cmd as subcommand
  if [[ "$cmd" == "service" ]]; then
    load_command service
    command::run service "$raw_cmd" "$@"
    return
  fi

  if load_command "$cmd"; then
    if command::exists "$cmd"; then
      command::run "$cmd" "$@"
    else
      log::error "Command '${cmd}' loaded but $(command::fn "$cmd" run) is not defined"
      exit 1
    fi
  else
    log::error "Unknown command: '${raw_cmd}'"
    echo "Run 'wgctl help' to see available commands."
    exit 1
  fi
}

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

function wgctl::help() {
cat <<EOF
$(log::section "wgctl — WireGuard Management" 2>/dev/null || printf "\n  wgctl — WireGuard Management\n")

Usage: wgctl <command> [options]

  Client Commands:
    add, new          Add a new client
    remove, rm        Remove a client
    rename, mv        Rename a client
    list, ls          List all clients
    inspect           Show detailed client info
    config            Show client config
    qr                Show QR code for a client

  Access Control:
    block, ban        Block a client entirely
    unblock, unban    Restore client access
    rule              Manage firewall rules (list, show, add, assign...)

  Organization:
    group             Manage peer groups (list, show, block, watch...)

  Monitoring:
    watch             Live monitor of WireGuard activity
    logs              Show activity and firewall logs
    audit             Verify firewall rules are correctly applied
    fw                Inspect firewall rules

  Service:
    service           Manage WireGuard service (start/stop/restart/status)
    restart           Restart WireGuard
    shell             Start interactive wgctl shell

  Development:
    test              Run the wgctl test suite

  Common examples:
    wgctl add --name nuno --type phone
    wgctl add --name visitor --type guest --subtype phone --group family
    wgctl list --blocked
    wgctl list --group family
    wgctl block --name phone-nuno
    wgctl inspect --name phone-nuno
    wgctl rule assign --name admin --peer laptop-nuno
    wgctl group block --name family
    wgctl logs --follow
    wgctl audit

Run 'wgctl <command> --help' for command-specific help.
EOF
}

# ============================================
# Main
# ============================================

function wgctl::main() {
  system::require_root
  wgctl::dispatch "$@"
}

wgctl::main "$@"
