#!/usr/bin/env bash

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

function cmd::add::on_load() {
  flag::register --name
  flag::register --type
  flag::register --subtype
  flag::register --ip
  flag::register --preset
  flag::register --guest
  flag::register --tunnel
  flag::register --show-config
  flag::register --show-qr
}

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

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

Add a new WireGuard client.

Options:
  --name <name>       Client name (e.g. nuno)
  --type <type>       Device type: desktop, laptop, phone, tablet, guest
  --ip <ip>           Override auto-assigned IP (optional)
  --preset <name>     Apply a firewall preset (repeatable)
  --guest             Shorthand for --type guest
  --tunnel <mode>     Tunnel mode: split (default) or full
  --show-config       Shows the WireGuard peer config
  --show-qr           Shows the WireGuard config in a QR Code

Device Types and Subnets:
  desktop   10.1.1.x
  laptop    10.1.2.x
  phone     10.1.3.x
  tablet    10.1.4.x
  guest     10.1.100.x

Tunnel Modes:
  split     Route only VPN subnet + LAN through WireGuard (default)
  full      Route all traffic through WireGuard

Examples:
  wgctl add --name nuno --type phone
  wgctl add --name nuno --type laptop --ip 10.1.2.5
  wgctl add --name nuno --type phone --tunnel full
  wgctl add --name guest1 --type phone --guest
  wgctl add --name restricted --type desktop --preset no-docker --preset no-proxmox
EOF
}

# ============================================
# Validation
# ============================================

function cmd::add::validate() {
  local name="$1"
  local type="$2"
  local ip="$3"
  local tunnel="$4"

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

  if [[ -z "$type" ]]; then
    log::error "Missing required flag: --type"
    return 1
  fi

  if ! config::is_valid_type "$type"; then
    log::error "Invalid device type: ${type}"
    log::info  "Valid types: $(config::device_types | tr ' ' ', ')"
    return 1
  fi

  if [[ -n "$tunnel" && "$tunnel" != "split" && "$tunnel" != "full" ]]; then
    log::error "Invalid tunnel mode: ${tunnel} (use 'split' or 'full')"
    return 1
  fi

  if [[ -n "$ip" ]]; then
    ip::require_valid "$ip"
  fi

  local full_name="${type}-${name}"

  if [[ -f "$(ctx::clients)/${full_name}.conf" ]]; then
    log::error "Client already exists: ${full_name}"
    return 1
  fi
}

# ============================================
# Display helpers
# ============================================

function cmd::add::is_mobile() {
  local type="$1"
  [[ "$type" == "phone" || "$type" == "tablet" ]]
}

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

function cmd::add::run() {
  local name=""
  local type=""
  local subtype=""
  local ip=""
  local tunnel=""
  local guest=false
  local presets=()
  local show_config=false
  local show_qr=false

  # Parse flags
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name)         name="$2";           shift 2 ;;
      --type)         type="$2";           shift 2 ;;
      --subtype)      subtype="$2";        shift 2 ;;
      --ip)           ip="$2";             shift 2 ;;
      --preset)       presets+=("$2");     shift 2 ;;
      --guest)        guest=true;          shift   ;;
      --tunnel)       tunnel="$2";         shift 2 ;;
      --show-config)  show_config=true;    shift   ;;
      --show-qr)      show_qr=true;        shift   ;;
      --help)         cmd::add::help;      return  ;;
      *)
        log::error "Unknown flag: $1"
        cmd::add::help
        return 1
        ;;
    esac
  done

  # --guest shorthand
  if $guest; then
    type="guest"
  fi

  # Resolve guest subtype
  local effective_type="$type"
  if [[ "$type" == "guest" && -n "$subtype" ]]; then
    # Validate subtype
    local valid_subtypes="desktop laptop phone tablet"
    if ! echo "$valid_subtypes" | grep -qw "$subtype"; then
      log::error "Invalid subtype: ${subtype} (valid: desktop, laptop, phone, tablet)"
      return 1
    fi
    effective_type="guest-${subtype}"
  fi

  # Build full client name
  local full_name="${type}-${name}"

  # Validate
  cmd::add::validate "$name" "$type" "$ip" "$tunnel" || return 1

  # Resolve tunnel mode — flag > device default
  if [[ -z "$tunnel" ]]; then
    tunnel=$(config::default_tunnel_for "$type")
  fi

  local allowed_ips
  allowed_ips=$(config::allowed_ips_for "$effective_type" "$tunnel") || return 1

  log::section "Adding client: ${full_name}"

  # Auto-assign IP if not provided
  if [[ -z "$ip" ]]; then
    ip=$(ip::next_for_type "$effective_type") || return 1
  fi

  log::wg_add "Name:   ${full_name}"
  log::wg_add "Type:   ${type}"
  log::wg_add "IP:     ${ip}"
  log::wg_add "Tunnel: ${tunnel} (${allowed_ips})"

  # Generate keys
  keys::generate_pair "$full_name" || return 1

  # Create client config
  peers::create_client_config "$full_name" "$effective_type" "$ip" "$allowed_ips" || return 1

  # Store subtype in meta
  if [[ -n "$subtype" ]]; then
    peers::set_meta "$full_name" "subtype" "$subtype"
  fi

  # Add peer to server config
  local public_key
  public_key=$(keys::public "$full_name") || return 1
  peers::add_to_server "$full_name" "$public_key" "$ip" || return 1

  # Apply presets
  for preset in "${presets[@]}"; do
    firewall::apply_preset "$preset" "${ip}" || return 1
  done

  # Apply guest rules if guest type
  if config::is_guest_type "$type"; then
    firewall::apply_guest_rules
  fi

  # Reload WireGuard
  peers::reload || return 1

  log::wg_success "Client added successfully: ${full_name} (${ip}) [${tunnel} tunnel]"

  # Show QR for mobile by default, config for desktop/laptop
  local display_type="${subtype:-$type}"
  
  if cmd::add::is_mobile "$display_type"; then
    keys::qr "$full_name"
  else
    log::section "Client Config"
    cat "$(ctx::clients)/${full_name}.conf"
  fi
}