#!/usr/bin/env bash

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

function cmd::unblock::on_load() {
  flag::register --name
  flag::register --type
  flag::register --force
  flag::register --quiet
  flag::register --ip
  flag::register --port
  flag::register --proto
  flag::register --subnet
  flag::register --all
}

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

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

Remove block rules for a client.

Options:
  --name <name>         Client name (e.g. phone-nuno)
  --ip <ip>             Unblock specific IP (repeatable)
  --subnet <cidr>       Unblock specific subnet (repeatable)
  --port <ip:port:proto> Unblock specific port (repeatable)
  --all                 Remove all block rules for this client

Examples:
  wgctl unblock --name phone-nuno --all
  wgctl unblock --name phone-nuno --ip 10.0.0.210
  wgctl unban --name phone-nuno --all
EOF
}

# ============================================
# Helpers
# ============================================

function cmd::unblock::get_client_ip() {
  local name="$1"
  local conf
  conf="$(ctx::clients)/${name}.conf"

  if [[ ! -f "$conf" ]]; then
    log::error "Client not found: ${name}"
    return 1
  fi

  grep "^Address" "$conf" | awk '{print $3}' | cut -d'/' -f1
}

# ============================================
# Unblock Run
# ============================================

function cmd::unblock::run() {
  local name=""
  local type=""
  local ips=()
  local subnets=()
  local ports=()
  local all=false
  local quiet=false

  while [[ $# -gt 0 ]]; do
    case "$1" in
      --name)   name="$2";          shift 2 ;;
      --type)   type="$2";          shift 2 ;;
      --ip)     ips+=("$2");        shift 2 ;;
      --force)  force=true;         shift   ;;
      --quiet)  quiet=true;         shift   ;;
      --subnet) subnets+=("$2");    shift 2 ;;
      --port)   ports+=("$2");      shift 2 ;;
      --all)    all=true;           shift   ;;
      --help)   cmd::unblock::help; return  ;;
      *)
        log::error "Unknown flag: $1"
        cmd::unblock::help
        return 1
        ;;
    esac
  done

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

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

    # Check if actually blocked
  if ! peers::is_blocked "$name" && [[ ! -f "$(ctx::block::path "${name}.block")" ]]; then
    log::wg_warning "Client is not blocked: ${name}"
    return 0
  fi

  # Default to full unblock if no specific flags given
  if [[ ${#ips[@]} -eq 0 && ${#subnets[@]} -eq 0 && ${#ports[@]} -eq 0 ]]; then
    all=true
  fi

  local client_ip
  client_ip=$(cmd::unblock::get_client_ip "$name") || return 1

  # $quiet || log::section "Unblocking client: ${name} (${client_ip})"

    if $all; then
      fw::unblock_all "$client_ip"
      fw::remove_block_file "$name"
      monitor::unwatch_client "$name"

    # Re-add peer to server if missing
    if ! peers::exists_in_server "$name"; then
      local public_key
      public_key=$(keys::public "$name") || return 1
      peers::add_to_server "$name" "$public_key" "$client_ip"
      peers::reload
    fi

    $quiet || log::wg_success "${name} has been unblocked."
    return 0
  fi

  # Unblock specific IPs
  for ip in "${ips[@]}"; do
    fw::unblock_ip "$client_ip" "$ip"
  done

  # Unblock specific subnets
  for subnet in "${subnets[@]}"; do
    fw::unblock_subnet "$client_ip" "$subnet"
  done

  # Unblock specific ports
  for entry in "${ports[@]}"; do
    local target port proto
    IFS=":" read -r target port proto <<< "$entry"
    proto="${proto:-tcp}"
    fw::unblock_port "$client_ip" "$target" "$port" "$proto"
  done

  $quiet || log::wg_success "Unblock rules applied for: ${name}"
}
