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

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

LOG_LEVEL=DEBUG

WGCTL_VERSION="0.7.1"

function wgctl::version() { echo "$WGCTL_VERSION"; }

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

load_module ip
load_module ui
load_module display
load_module config
load_module keys
load_module peers
load_module firewall
load_module monitor
load_module rule
load_module block
load_module net
load_module group
load_module subnet
load_module identity
load_module policy
load_module hosts
load_module resolve

# ============================================
# 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 ;;
    shell) : ;;
    *) config::validate || exit 1 ;;
  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 (--type, --subtype, --rule, --group)
    remove, rm        Remove a client
    rename, mv        Rename a client
    list, ls          List all clients (--type, --rule, --group, --blocked, --restricted...)
    inspect           Show detailed client info (--config, --qr)
    config            Show client config
    qr                Show QR code for a client

  Access Control:
    block, ban        Block a client entirely or restrict specific IPs/ports/services
    unblock, unban    Restore client access (overrides group blocks)
    rule              Manage firewall rules with inheritance
                        list, show, add, update, assign, reapply...

  Organization:
    group             Manage peer groups
                        list, show, add, block, unblock, watch, logs...

  Network Services:
    net               Manage named network services
                        list, show, add, rm
                        Used with block/unblock --service and rule --block-service

  Monitoring:
    watch             Live monitor — handshakes, fw drops, blocked attempts
    logs              Show and manage activity logs
                        show, remove, rotate, --follow
    audit             Verify firewall rules match configuration
    fw                Inspect iptables firewall rules

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

  Development:
    test              Run the wgctl test suite

  Common examples:
    wgctl add --name nuno --type phone --rule admin --group family
    wgctl list --blocked
    wgctl list --restricted
    wgctl list --rule user --group family
    wgctl block --name phone-nuno
    wgctl block --name phone-nuno --service proxmox
    wgctl inspect --name phone-nuno
    wgctl rule list --tree
    wgctl rule show --name guest
    wgctl rule add --name dev-01 --group vm-rules --extends no-lan
    wgctl net add --name proxmox --ip 10.0.0.100
    wgctl net add --name proxmox:web-ui --port 8006:tcp
    wgctl group block --name family
    wgctl logs --follow
    wgctl logs rotate --days 7
    wgctl audit --fix
    wgctl fw list --rule guest

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

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

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

wgctl::main "$@"
