Ctrl K
ComunidadGuías…

npm-api.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/bin/bash

# Nginx Proxy Manager CLI Script
#   Github [ https://github.com/Erreur32/nginx-proxy-manager-Bash-API ]
#   By Erreur32 - July 2024
#   NPM api https://github.com/NginxProxyManager/nginx-proxy-manager/tree/develop/backend/schema
#           https://github.com/NginxProxyManager/nginx-proxy-manager/tree/develop/backend/schema/components

VERSION="3.6.9"

#################################
# This script allows you to manage Nginx Proxy Manager via the API. It provides
# functionalities such as creating proxy hosts, managing users, listing hosts,
# backing up configurations, and more.
#
#################################
# PERSISTENT Config
#################################
# Create config file  $SCRIPT_DIR/npm-api.conf and Edit Variables (required)

# NGINX_IP="127.0.0.1"
# NGINX_PORT="81"
# API_USER="admin@example.com"
# API_PASS="changeme"
#
# Optional (only if you want in other placer than script directory)
# DATA_DIR="/path/nginx_backup/dir"
#
################################

# Optional (for a future version, not use)
# NGINX_PATH_DOCKER="/home/docker/nginx_proxy/nginx"

#################################
# Common Examples
#
# 1. Create a new proxy host:
#    ./npm-api.sh --host-create example.com -i 192.168.1.10 -p 8080
#
# 2. Enable SSL for a host:
#    ./npm-api.sh --host-ssl-enable 1
#
# 3. Create a new user:
#    ./npm-api.sh --user-create admin admin@example.com password123
#
# 4. List all proxy hosts:
#    ./npm-api.sh --host-list
#
# 5. Generate SSL certificate:
#    ./npm-api.sh --cert-generate example.com admin@example.com
#    ./npm-api.sh --cert-generate "*.example.com" \
#      --dns-provider cloudflare --dns-credentials '{"dns_cloudflare_api_token":"your_token"}'
#
# 6. Show host details:
#    ./npm-api.sh --host-show 1
#

# debug version
set -eu -o pipefail
#set -x  # Active dbog
#set -eu -o pipefail

# Check if config file npm-api.conf exist
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="$SCRIPT_DIR/npm-api.conf"

################################
# Variables to Edit (required) #
#   or create a config file    #
################################

# set default variables
DEFAULT_NGINX_IP="127.0.0.1"
DEFAULT_NGINX_PORT="81"
DEFAULT_API_USER="admin@example.com"
DEFAULT_API_PASS="changeme"
DEFAULT_NGINX_PATH_DOCKER="/path/docker/npm"
# default backup directoy (You can override with your path)
DEFAULT_DATA_DIR="$SCRIPT_DIR/data"

################################
# DON'T TOUCH BELOW !!!  ;)
################################
# Colors Custom
COLOR_GREEN="\033[32m"
COLOR_GREEN_b="\e[92m"
COLOR_RED="\033[91m"
COLOR_RED_FULL="\033[41;1m"
COLOR_ORANGE="\033[38;5;202m"
COLOR_YELLOW="\033[93m"
COLOR_CYAN="\033[36m"
COLOR_GREY="\e[90m"
COLOR_GRAY=" \e[100m"
WHITE_ON_GREEN="\033[30;48;5;83m"
CoR="\033[0m"

# load config file if exists
if [ -f "$CONFIG_FILE" ]; then
  # First set default values
  NGINX_IP="$DEFAULT_NGINX_IP"
  NGINX_PORT="$DEFAULT_NGINX_PORT"
  API_USER="$DEFAULT_API_USER"
  API_PASS="$DEFAULT_API_PASS"
  DATA_DIR="$DEFAULT_DATA_DIR"
  NGINX_PATH_DOCKER="$DEFAULT_NGINX_PATH_DOCKER"
  # Then load config file which will override defaults
  source "$CONFIG_FILE"
  # Finally set variables as read only
  declare -r NGINX_IP
  declare -r NGINX_PORT
  declare -r API_USER
  declare -r API_PASS
  #declare -r DATA_DIR
  # NGINX_PATH_DOCKER is optional, only make it readonly if it was set in config
  if [ -n "${NGINX_PATH_DOCKER+x}" ]; then
    declare -r NGINX_PATH_DOCKER
  fi
else
  # Use default values
  NGINX_IP="$DEFAULT_NGINX_IP"
  NGINX_PORT="$DEFAULT_NGINX_PORT"
  API_USER="$DEFAULT_API_USER"
  API_PASS="$DEFAULT_API_PASS"
  DATA_DIR="$DEFAULT_DATA_DIR"
  NGINX_PATH_DOCKER="$DEFAULT_NGINX_PATH_DOCKER"

  # Check if using default API user
  if [ "$API_USER" = "$DEFAULT_API_USER" ]; then
    echo -e "\n⚠️ ${COLOR_RED}Using default API credentials - Please configure the script!${CoR}"
    echo -e "\n📝 Create configuration file: $CONFIG_FILE with content:"
    echo -e "${COLOR_GREY}NGINX_IP=\"$NGINX_IP\"${CoR}     ${COLOR_YELLOW}(current default)${CoR}"
    echo -e "${COLOR_GREY}NGINX_PORT=\"$NGINX_PORT\"${CoR}  ${COLOR_YELLOW}(current default)${CoR}"
    echo -e "${COLOR_RED}API_USER=\"admin@example.com\"${CoR}  ${COLOR_RED}(required)${CoR}"
    echo -e "${COLOR_RED}API_PASS=\"your_password\"${CoR}     ${COLOR_RED}(required)${CoR}"
    echo -e "${COLOR_GREY}DATA_DIR=\"$DATA_DIR\"${CoR}    ${COLOR_YELLOW}(current default)${CoR}"
    echo -e "\n❌ ${COLOR_RED}Cannot continue with default API credentials${CoR}\n"
    exit 1
  fi
fi

# API Endpoints
BASE_URL="http://$NGINX_IP:$NGINX_PORT/api"
# Set Token duration validity.
#TOKEN_EXPIRY="365d"
#TOKEN_EXPIRY="31536000s"
TOKEN_EXPIRY="1y"

# Default variables for creating a new proxy host (adapt to your needs)
# Note: These variables must match the names used in argument parsing and JSON payload generation
CACHING_ENABLED=false
BLOCK_EXPLOITS=true
ALLOW_WEBSOCKET_UPGRADE=false # Fixed: was '1' instead of 'false' (Issue #23)
HTTP2_SUPPORT=false           # consistent true/false convention (Issue #23 class)
ADVANCED_CONFIG=""
LETS_ENCRYPT_AGREE=false
LETS_ENCRYPT_EMAIL=""
FORWARD_SCHEME="http"
FORCE_CERT_CREATION=false
SSL_FORCED=false
HSTS_ENABLED=false
HSTS_SUBDOMAINS=false
#DNS_PROVIDER=""
#DNS_API_KEY=""
# Don't touch below that line (or you know ...)
DEFAULT_EMAIL="$API_USER"
DOMAIN=""
DOMAIN_NAMES=""
FORWARD_HOST=""
FORWARD_PORT=""
CUSTOM_LOCATIONS=""
USERNAME=""
PASSWORD=""
EMAIL=""
HOST_ID=""
FIELD=""
VALUE=""
FIELD_VALUE=""

# Control variables
AUTO_YES=false
JSON_OUTPUT=false
LIST_JSON_COMMANDS=false
CHECK_TOKEN=false
CHECK_UPDATE=false
EXAMPLES=false
INFO=false
SHOW_HELP=false
SHOW_DEFAULT=false

USER_CREATE=false
USER_DELETE=false
USER_IS_ADMIN=false
USER_LIST=false

HOST_SHOW=false
HOST_LIST=false
HOST_LIST_FULL=false
HOST_SEARCH=false
HOST_UPDATE=false
HOST_ENABLE=false
HOST_SEARCHNAME=""
HOST_DISABLE=false
HOST_DELETE=false
HOST_ACL_ENABLE=false
HOST_ACL_DISABLE=false
HOST_CREATE=false

LIST_CERT_ALL=false
CERT_SHOW=false
CERT_GENERATE=false
CERT_DELETE=false
CERT_PURGE=false
CERT_DOWNLOAD=false
CERT_DOMAIN=""
CERT_EMAIL=""
# IDs / search term resolved by command parsers; initialized for set -u safety
CERT_ID=""
GENERATED_CERT_ID=""
USER_ID=""
search_term=""
# Cached API token (populated by check_token_notverbose) to avoid re-reading
# the token file on every curl. Curl headers use ${TOKEN:-$(cat "$TOKEN_FILE")}
# so an empty cache safely falls back to reading the file.
TOKEN=""
DNS_PROVIDER=""
CERT_DNS_PROVIDER=""
CERT_DNS_CREDENTIALS=""
DOMAIN_EXISTS=""
HOST_SSL_ENABLE=false
HOST_SSL_DISABLE=false
SSL_RESTORE=false

ACCESS_LIST=false
ACCESS_LIST_CREATE=false
ACCESS_LIST_UPDATE=false
ACCESS_LIST_DELETE=false
ACCESS_LIST_SHOW=false
ACCESS_LIST_ID=""
ACCESS_LIST_UPDATE_ARGS=()
ACCESS_LIST_CREATE_ARGS=()

BACKUP=false
BACKUP_LIST=false
### in progress
BACKUP_HOST=false
CLEAN_HOSTS=false

REDIRECT_HOST_LIST=false
REDIRECT_HOST_CREATE=false
REDIRECT_HOST_DELETE=false
REDIRECT_HOST_ENABLE=false
REDIRECT_HOST_DISABLE=false
REDIRECT_HOST_ID=""
FORWARD_DOMAIN=""
FORWARD_HTTP_CODE="301"
PRESERVE_PATH=false

STREAM_HOST_LIST=false
STREAM_HOST_CREATE=false
STREAM_HOST_DELETE=false
STREAM_HOST_ENABLE=false
STREAM_HOST_DISABLE=false
STREAM_HOST_ID=""
INCOMING_PORT=""
TCP_FORWARDING=false
UDP_FORWARDING=false

DEAD_HOST_LIST=false
DEAD_HOST_CREATE=false
DEAD_HOST_DELETE=false
DEAD_HOST_ENABLE=false
DEAD_HOST_DISABLE=false
DEAD_HOST_ID=""

if [ $# -eq 0 ]; then
  INFO=true
  #SHOW_HELP=true
fi
###############################################
# Check if necessary dependencies are installed
################################
# Function to check and create required directories
# Usage: check_dependencies
# Returns: 0 if successful, exits with 1 if error
################################

check_dependencies() {

  #echo -e "\n  🔍 ${COLOR_CYAN}Checking system dependencies and directories...${CoR}"
  ################################
  # 1. Check System Dependencies #
  ################################
  local dependencies=("curl" "jq")
  local missing=()
  for dep in "${dependencies[@]}"; do
    if ! command -v "$dep" &>/dev/null; then
      missing+=("$dep")
    fi
  done
  if [ ${#missing[@]} -gt 0 ]; then
    echo -e " ⛔ ${COLOR_RED}Missing dependencies. Please install:${CoR}"
    printf "   - %s\n" "${missing[@]}"
    exit 1
  fi

  #return 0
}
#check_dependencies

# Check if the Nginx Proxy Manager API is accessible
check_nginx_access() {
  local max_retries=3
  local retry_count=0
  local timeout=5
  #echo -e "\n🔍 Checking NPM availability..."
  #echo -e " • Attempting to connect to: ${COLOR_YELLOW}$BASE_URL${CoR}"
  #echo -e "\n ✅ Loading variables from file $CONFIG_FILE"
  while [ $retry_count -lt $max_retries ]; do
    # Try to connect with timeout
    if curl --output /dev/null --silent --head --fail --connect-timeout $timeout --max-redirs 0 "$BASE_URL"; then
      #echo -e " ✅ NPM is accessible at: ${COLOR_GREEN}$BASE_URL${CoR}"
      local version_info=$(curl -s --max-redirs 0 "${BASE_URL%/api}/version")
      return 0
    fi
    retry_count=$((retry_count + 1))
    # Show retry message if not last attempt
    if [ $retry_count -lt $max_retries ]; then
      echo -e " ⏳ Attempt $retry_count/$max_retries - Retrying in ${timeout}s..."
      sleep $timeout
    fi
  done
  # If we get here, all attempts failed
  echo -e "\n❌ ${COLOR_RED}ERROR: Cannot connect to NPM${CoR}"
  echo -e "🔍 Details:"
  echo -e " • URL: ${COLOR_YELLOW}$BASE_URL${CoR}"
  echo -e " • Host: ${COLOR_YELLOW}$NGINX_IP${CoR}"
  echo -e " • Port: ${COLOR_YELLOW}${NGINX_PORT}${CoR}"
  echo -e "\n📋 Troubleshooting:"
  echo -e " 1. Check if NPM is running"
  echo -e " 2. Verify network connectivity"
  echo -e " 3. Confirm NPM IP and port settings"
  echo -e " 4. Check NPM logs for errors"
  echo -e "\n💡 Command to check NPM status:"
  echo -e " $ docker ps | grep nginx-proxy-manager"
  echo -e " $ docker logs nginx-proxy-manager\n"
  exit 1
}

################################
# Generate and/or validate token
# $1: boolean - true to display messages, false for silent mode
check_token() {
  local verbose=${1:-false}
  # PATH
  ###############################
  [ "$verbose" = true ] && echo -e "\n 🔍 ${COLOR_CYAN}Checking system dependencies and directories...${CoR}"
  check_dependencies

  local ip_port_dir="${NGINX_IP//[.:]/_}_${NGINX_PORT}"
  DATA_DIR_ID="$DATA_DIR/$ip_port_dir"
  BACKUP_DIR="$DATA_DIR_ID/backups"
  TOKEN_DIR="$DATA_DIR_ID/token"
  TOKEN_FILE="$TOKEN_DIR/token.txt"
  EXPIRY_FILE="$TOKEN_DIR/expiry.txt"

  ################################
  # Create directories if they don't exist
  ################################
  for dir in "$DATA_DIR_ID" "$TOKEN_DIR" "$BACKUP_DIR"; do
    if [ ! -d "$dir" ]; then
      [ "$verbose" = true ] && echo -e "  📢 ${COLOR_YELLOW}Creating directory: $dir${CoR}"
      if ! mkdir -p "$dir" 2>/dev/null; then
        echo -e "\n  ${COLOR_RED}Error: Failed to create directory $dir${CoR}"
        exit 1
      fi
      # Set proper permissions
      chmod 755 "$dir" 2>/dev/null
    fi
  done

  [ "$verbose" = true ] && echo -e " ✅ ${COLOR_GREEN}All dependencies and directories are properly set up${CoR}"
  [ "$verbose" = true ] && echo -e "    ${COLOR_GREY}├── System tools: OK${CoR}"
  [ "$verbose" = true ] && echo -e "    ${COLOR_GREY}├── Directories : OK${CoR}"
  [ "$verbose" = true ] && echo -e "    ${COLOR_GREY}└── Permissions : OK${CoR}"

  [ "$verbose" = true ] && echo -e "\n 🔑 Checking token validity..."

  # Check if token files exist and are readable
  if [ ! -f "$TOKEN_FILE" ] || [ ! -f "$EXPIRY_FILE" ] ||
    [ ! -r "$TOKEN_FILE" ] || [ ! -r "$EXPIRY_FILE" ] ||
    [ ! -s "$TOKEN_FILE" ] || [ ! -s "$EXPIRY_FILE" ]; then
    [ "$verbose" = true ] && echo -e " ⛔ ${COLOR_RED}Token files missing or unreadable. Generating new token...${CoR}"
    generate_new_token
    # Ensure files were created and are readable
    if [ ! -f "$TOKEN_FILE" ] || [ ! -f "$EXPIRY_FILE" ] ||
      [ ! -r "$TOKEN_FILE" ] || [ ! -r "$EXPIRY_FILE" ]; then
      echo -e "\n  ${COLOR_RED}Error: Failed to create or read token files${CoR}"
      exit 1
    fi
    return
  fi

  # Read token and expiry
  token=$(cat "$TOKEN_FILE" 2>/dev/null)
  expires=$(cat "$EXPIRY_FILE" 2>/dev/null)
  current_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

  # Validate expiry date format
  if ! date -d "$expires" >/dev/null 2>&1; then
    [ "$verbose" = true ] && echo -e " ⛔ ${COLOR_RED}Invalid expiry date. Generating new token...${CoR}"
    generate_new_token
    return
  fi

  # Check if token is expired or will expire soon (1 hour)
  local expiry_timestamp=$(date -d "$expires" +%s)
  local current_timestamp=$(date -d "$current_time" +%s)
  local time_diff=$((expiry_timestamp - current_timestamp))
  if [ $time_diff -lt 3600 ]; then
    [ "$verbose" = true ] && echo -e " ⚠️ ${COLOR_YELLOW}Token expires soon. Generating new token...${CoR}"
    generate_new_token
    return
  fi

  # Test token with API call
  local test_response
  test_response=$(curl -s -w "HTTPSTATUS:%{http_code}" \
    -H "Authorization: Bearer $token" \
    --connect-timeout 5 \
    "$BASE_URL/tokens")

  local http_status=$(echo "$test_response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')

  if [ "${http_status:-0}" -eq 200 ]; then
    [ "$verbose" = true ] && echo -e " ✅ ${COLOR_GREEN}Token is valid${CoR}"
    [ "$verbose" = true ] && echo -e " 📅 Expires: ${COLOR_YELLOW}$expires${CoR}\n"
  else
    [ "$verbose" = true ] && echo -e " ⛔ ${COLOR_RED}Token is invalid. Generating new token...${CoR}\n"
    generate_new_token
  fi
  return 0
}

# validate_token not verbose
check_token_notverbose() {
  check_token false
  # Cache the validated token once so subsequent curls reuse it (see $TOKEN)
  TOKEN=$(cat "$TOKEN_FILE" 2>/dev/null)
}

################################
# Generate a new API token
generate_new_token() {
  echo -e "\n 🔄 ${COLOR_YELLOW}Generating a new API token...${CoR}"

  # check if API credentials are missing
  if [ -z "$API_USER" ] || [ -z "$API_PASS" ]; then
    echo -e " ❌ ${COLOR_RED}Error: API credentials are missing.${CoR}"
    exit 1
  fi

  # check if NPM is accessible
  if ! curl --output /dev/null --silent --head --fail --connect-timeout 5 "$BASE_URL"; then
    echo -e "\n❌ ${COLOR_RED}ERROR: Cannot connect to NPM to generate token${CoR}"
    echo -e "🔍 Please check if NPM is running and accessible at ${COLOR_YELLOW}$BASE_URL${CoR}\n"
    exit 1
  fi

  # First get a temporary token
  local temp_response=$(curl -s -w "\nHTTPSTATUS:%{http_code}" -X POST "$BASE_URL/tokens" \
    -H "Content-Type: application/json" \
    --data-raw "{\"identity\":\"$API_USER\",\"secret\":\"$API_PASS\"}")

  local temp_body=$(echo "$temp_response" | sed -e 's/HTTPSTATUS\:.*//g')
  local temp_status=$(echo "$temp_response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')

  if [ "${temp_status:-0}" -ne 200 ]; then
    echo -e " ❌ ${COLOR_RED}Failed to generate temporary token. Status: $temp_status${CoR}"
    echo -e " 📝 Response: $temp_body"
    exit 1
  fi

  # Extract the temporary token
  local temp_token=$(echo "$temp_body" | jq -r '.token')

  # Now get a long-term token using the temporary one
  local response=$(curl -s -w "\nHTTPSTATUS:%{http_code}" -X GET "$BASE_URL/tokens?expiry=$TOKEN_EXPIRY" \
    -H "Authorization: Bearer $temp_token" \
    -H "Accept: application/json")

  local body=$(echo "$response" | sed -e 's/HTTPSTATUS\:.*//g')
  local status=$(echo "$response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')

  if [ "${status:-0}" -ne 200 ]; then
    echo -e " ❌ ${COLOR_RED}Failed to generate long-term token. Status: $status${CoR}"
    echo -e " 📝 Response: $body"
    exit 1
  fi

  # Extract token and expiry
  local token=$(echo "$body" | jq -r '.token')
  local expiry=$(echo "$body" | jq -r '.expires')

  # Ensure token directory exists with proper permissions
  if [ ! -d "$TOKEN_DIR" ]; then
    mkdir -p "$TOKEN_DIR" 2>/dev/null
    chmod 755 "$TOKEN_DIR" 2>/dev/null
  fi

  # Save token and expiry with proper permissions
  echo "$token" >"$TOKEN_FILE"
  echo "$expiry" >"$EXPIRY_FILE"
  chmod 644 "$TOKEN_FILE" "$EXPIRY_FILE" 2>/dev/null

  # Verify files were created successfully
  if [ ! -f "$TOKEN_FILE" ] || [ ! -f "$EXPIRY_FILE" ] ||
    [ ! -r "$TOKEN_FILE" ] || [ ! -r "$EXPIRY_FILE" ]; then
    echo -e " ❌ ${COLOR_RED}Failed to save token files${CoR}"
    exit 1
  fi

  echo -e " ✅ ${COLOR_GREEN}New token successfully generated and stored.${CoR}"
  echo -e " 📅 Token expiry date: ${COLOR_YELLOW}$expiry${CoR}"
}

# Function to pad strings to a certain length
pad() {
  local str="$1"
  local len="$2"
  local str_len=${#str}
  local pad_len=$((len - str_len))
  local padding=$(printf '%*s' "$pad_len" "")
  echo "$str$padding"
}

################################
# Like pad() but truncates with an ellipsis when the string is longer than
# the requested width, so columns stay aligned even with long names.
# Always returns a string of exactly $len visible characters.
truncate_pad() {
  local str="$1"
  local len="$2"
  if [ "${#str}" -gt "$len" ]; then
    str="${str:0:$((len - 1))}…"
  fi
  local pad_len=$((len - ${#str}))
  [ "$pad_len" -lt 0 ] && pad_len=0
  printf '%s%*s' "$str" "$pad_len" ""
}

################################
# Colorize boolean values for display
colorize_boolean() {
  local value="$1"
  if [ "$value" = "true" ]; then
    echo "${COLOR_GREEN}true${CoR}"
  elif [ "$value" = "false" ]; then
    echo "${COLOR_RED}false${CoR}"
  else
    # If value is neither true nor false, convert to boolean
    if [ "$value" = "1" ] || [ "$value" = "yes" ] || [ "$value" = "on" ]; then
      echo "${COLOR_GREEN}true${CoR}"
    else
      echo "${COLOR_RED}false${CoR}"
    fi
  fi
}

################################
# Colorize other boolean values for display
colorize_booleanh() {
  local value=$1
  if [ "$value" = https ]; then
    echo -e "${COLOR_GREEN}https${CoR}"
  else
    echo -e "${COLOR_YELLOW}http${CoR}"
  fi
}

# Function to sanitize names for directory
sanitize_name() {
  local name=$1
  echo "${name//[^a-zA-Z0-9]/_}"
}

################################
# Function to validate JSON files
validate_json() {
  local file=$1
  if ! jq empty "$file" 2>/dev/null; then
    echo -e "\n ⛔ Invalid JSON detected in file: $file"
    cat "$file" # Show file content for debug
    return 1
  fi
  return 0
}

################################
# Display help
# Print one help line with its description aligned to a fixed column.
# Visible width ignores literal ANSI color sequences (\033[..m / \e[..m) and
# counts wide emoji (1 code point but 2 terminal cells) as 2.
HELP_DESC_COL=42
help_row() {
  local left="$1" desc="$2"
  local plain width pad g tmp
  plain=$(printf '%s' "$left" | sed -E 's/\\(033|e)\[[0-9;]*m//g')
  width=${#plain}
  for g in 🆔 💾 🔖 🌍 🔗 🔒 🔄 ✨ 📥 📦 📜; do
    tmp=${plain//"$g"/}
    width=$((width + ${#plain} - ${#tmp}))
  done
  pad=$((HELP_DESC_COL - width))
  if [ "$pad" -lt 1 ]; then
    # Left part is wider than the description column: wrap the description onto
    # the next line, aligned under the same column so everything stays tidy.
    echo -e "${left}"
    echo -e "$(printf '%*s' "$HELP_DESC_COL" '')${desc}"
  else
    echo -e "${left}$(printf '%*s' "$pad" '')${desc}"
  fi
}

show_help() {
  echo -e "\n Options available:                       ${COLOR_GREY}(see --examples for more details)${CoR}"
  help_row "   -y" "Automatic ${COLOR_YELLOW}yes${CoR} prompts!"
  help_row "  --json" "${COLOR_GREEN}🤖 ${CoR}Modifier: force ${COLOR_GREY}pure JSON output${CoR} on read commands (list/show), for scripts"
  help_row "  --json --list" "${COLOR_GREEN}🤖 ${CoR}List ${COLOR_GREY}the commands compatible with --json${CoR}"
  help_row "  --info" "Display ${COLOR_GREY}Script Variables Information${CoR}"
  help_row "  --show-default" "Show ${COLOR_GREY}Default settings for host creation${CoR}"
  help_row "  --check-token" "Check ${COLOR_GREY}current token info${CoR}"
  help_row "  --check-update" "${COLOR_GREEN}🆕 ${CoR}Check ${COLOR_GREY}GitHub for a newer script version${CoR}"
  help_row "  --backup" "${COLOR_GREEN}💾 ${CoR}Backup ${COLOR_GREY}All configurations to a different files in \$DATA_DIR${CoR}"
  #echo -e "  --clean-hosts                          ${COLOR_GREEN}📥 ${CoR}Reimport${CoR} ${COLOR_GREY}Clean Proxy ID and SSL ID in sqlite database ;)${CoR}"
  help_row "  --backup-host ${COLOR_CYAN}[id]${CoR}" "${COLOR_GREEN}📦 ${CoR}Backup  ${COLOR_GREY}One proxy host (with SSL cert), or all if no id${CoR}"
  help_row "  --backup-host-list" "${COLOR_GREEN}📋 ${CoR}List    ${COLOR_GREY}Available per-host proxy backups${CoR}"
  #echo -e "  --host-list-full > backup.txt          💾 ${COLOR_YELLOW}Export${CoR}   Full host configuration to file"
  echo ""
  echo -e " Proxy Host Management:"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  help_row "  --host-search ${COLOR_CYAN}domain${CoR}" "Search ${COLOR_GREY}Proxy host by ${COLOR_YELLOW}domain name${CoR}"
  help_row "  --host-list" "List ${COLOR_GREY}All Proxy hosts (to find ID)${CoR}"
  help_row "  --host-list-full" "List ${COLOR_GREY}All Proxy hosts with full details (${COLOR_YELLOW}JSON${COLOR_GREY})${CoR}"
  help_row "  --host-show ${COLOR_CYAN}🆔${CoR}" "Show ${COLOR_GREY}Full details for a specific host by ${COLOR_YELLOW}ID${CoR}"
  echo ""

  echo -e "  --host-create ${COLOR_ORANGE}domain${CoR} ${COLOR_CYAN}-i ${COLOR_ORANGE}forward_host${CoR} ${COLOR_CYAN}-p ${COLOR_ORANGE}forward_port${CoR} [options]\n"
  echo -e "     ${COLOR_RED}Required:${CoR}"
  help_row "            domain" "Domain name (${COLOR_RED}required${CoR})"
  help_row "       ${COLOR_CYAN}-i${CoR}   forward-host" "IP address or domain name of the target server (${COLOR_RED}required${CoR})"
  help_row "       ${COLOR_CYAN}-p${CoR}   forward-port" "Port of the target server (${COLOR_RED}required${CoR})"
  echo ""
  echo -e "     optional: ${COLOR_GREY}(Check default settings,no argument needed if already set!)${CoR}"
  help_row "       ${COLOR_CYAN}-f ${COLOR_GREY}FORWARD_SCHEME${CoR}" "Scheme for forwarding (http/https, default: $(colorize_booleanh "$FORWARD_SCHEME"))"
  help_row "       ${COLOR_CYAN}-c ${COLOR_GREY}CACHING_ENABLED${CoR}" "Enable caching (true/false, default: $(colorize_boolean "$CACHING_ENABLED"))"
  help_row "       ${COLOR_CYAN}-b ${COLOR_GREY}BLOCK_EXPLOITS${CoR}" "Block exploits (true/false, default: $(colorize_boolean "$BLOCK_EXPLOITS"))"
  help_row "       ${COLOR_CYAN}-w ${COLOR_GREY}ALLOW_WEBSOCKET_UPGRADE${CoR}" "Allow WebSocket upgrade (true/false, default: $(colorize_boolean "$ALLOW_WEBSOCKET_UPGRADE"))"
  help_row "       ${COLOR_CYAN}-l ${COLOR_GREY}CUSTOM_LOCATIONS${CoR}" "Custom locations (${COLOR_YELLOW}JSON array${CoR} of location objects)"
  help_row "       ${COLOR_CYAN}-a ${COLOR_GREY}ADVANCED_CONFIG${CoR}" "Advanced configuration (${COLOR_YELLOW}string${CoR})"
  #echo -e "       ${COLOR_CYAN}-h ${COLOR_GREY}HTTP2_SUPPORT${CoR}                   HTTP2 (true/false, default: $(colorize_boolean "$HTTP2_SUPPORT"))"

  echo ""
  help_row "  --host-enable  ${COLOR_CYAN}🆔${CoR}" "Enable Proxy host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --host-disable ${COLOR_CYAN}🆔${CoR}" "Disable Proxy host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --host-delete  ${COLOR_CYAN}🆔${CoR}" "Delete Proxy host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --host-update  ${COLOR_CYAN}🆔${CoR} ${COLOR_CYAN}[field]=value${CoR}" "Update One specific field of an existing proxy host by ${COLOR_YELLOW}ID${CoR}"
  echo -e "                                          (eg., --host-update 42 forward_host=foobar.local)${CoR}"
  echo ""
  help_row "  --host-acl-enable  ${COLOR_CYAN}🆔${CoR} ${COLOR_CYAN}access_list_id${CoR}" "Enable ACL for Proxy host by ${COLOR_YELLOW}ID${CoR} with Access List ID"
  help_row "  --host-acl-disable ${COLOR_CYAN}🆔${CoR}" "Disable ACL for Proxy host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --host-ssl-enable  ${COLOR_CYAN}🆔${CoR} ${COLOR_CYAN}[cert_id]${CoR}" "Enable SSL for host ID optionally using specific certificate ID"
  help_row "  --host-ssl-disable ${COLOR_CYAN}🆔${CoR}" "Disable SSL, HTTP/2, and HSTS for a proxy host"
  echo ""
  help_row "  --cert-list" "List ALL SSL certificates"
  help_row "  --cert-show     ${COLOR_CYAN}domain${CoR} Or ${COLOR_CYAN}🆔${CoR}" "List SSL certificates filtered by [domain name] (add ${COLOR_YELLOW}--json${CoR} for raw JSON)"
  help_row "  --cert-delete   ${COLOR_CYAN}domain${CoR} Or ${COLOR_CYAN}🆔${CoR} ${COLOR_CYAN}[--purge]${CoR}" "Delete Certificate for the given '${COLOR_YELLOW}domain${CoR}' (${COLOR_GREY}--purge${CoR} also removes on-disk files)"
  help_row "  --cert-download ${COLOR_CYAN}🆔${CoR} ${COLOR_CYAN}[output_dir]${CoR} ${COLOR_CYAN}[cert_name]${CoR}" "Download certificate as ZIP with fallback support"

  help_row "  --cert-generate ${COLOR_CYAN}domain${CoR} ${COLOR_CYAN}[email]${CoR}" "Generate Let's Encrypt Certificate or others Providers."
  echo -e "                                           • ${COLOR_YELLOW}Email:${CoR} positional [email] or ${COLOR_CYAN}--cert-email${CoR} email (default: \$DEFAULT_EMAIL), NPM < 2.13 only"
  echo -e "                                             - NPM >= 2.13 uses the email of the NPM user account"
  echo -e "                                           • ${COLOR_YELLOW}Standard domains:${CoR} example.com, sub.example.com"
  echo -e "                                           • ${COLOR_YELLOW}Wildcard domains:${CoR} *.example.com (requires DNS challenge)${CoR}"
  echo -e "                                           • DNS Challenge:${CoR} Required for wildcard certificates"
  echo -e "                                             - ${COLOR_YELLOW}Format:${CoR} --dns-provider PROVIDER --dns-credentials 'JSON' (or certbot INI text)"
  echo -e "                                             - ${COLOR_YELLOW}Providers:${CoR} dynu, cloudflare, digitalocean, godaddy, namecheap, route53, ovh, gcloud, hostinger, rcodezero, hoster.by, lws, tencentcloud-edgeone, ..."
  echo -e "                                             - ${COLOR_YELLOW}Cloudflare:${CoR} '{\"dns_cloudflare_api_token\":\"TOKEN\"}' (recommended, Zone:DNS:Edit)"
  echo -e "                                               or '{\"dns_cloudflare_email\":\"EMAIL\",\"dns_cloudflare_api_key\":\"GLOBAL_KEY\"}'"
  echo -e "                                           • ${COLOR_YELLOW}Reuse:${CoR} one wildcard cert for many hosts: --host-ssl-enable HOST_ID CERT_ID"
  echo ""
  echo ""
  echo -e " Redirection Host Management:"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  help_row "  --redirect-host-list" "List all Redirection Hosts"
  echo -e "  --redirect-host-create ${COLOR_ORANGE}domain${CoR} --forward-domain ${COLOR_ORANGE}target${CoR} [options]"
  echo -e "     Required:"
  help_row "            domain" "Source domain name"
  help_row "       --forward-domain ${COLOR_ORANGE}target${CoR}" "Target domain to redirect to"
  echo -e "     Optional:"
  help_row "       --forward-scheme ${COLOR_GREY}http|https${CoR}" "Scheme (default: http)"
  help_row "       --http-code      ${COLOR_GREY}301|302|307...${CoR}" "HTTP redirect code (default: 301)"
  help_row "       --preserve-path  ${COLOR_GREY}true|false${CoR}" "Keep URI path (default: false)"
  help_row "  --redirect-host-enable  ${COLOR_CYAN}🆔${CoR}" "Enable Redirection Host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --redirect-host-disable ${COLOR_CYAN}🆔${CoR}" "Disable Redirection Host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --redirect-host-delete  ${COLOR_CYAN}🆔${CoR}" "Delete Redirection Host by ${COLOR_YELLOW}ID${CoR}"
  echo ""
  echo ""
  echo -e " Stream Host Management (TCP/UDP forwarding):"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  help_row "  --stream-host-list" "List all Stream Hosts"
  echo -e "  --stream-host-create ${COLOR_ORANGE}incoming_port${CoR} --forward-host ${COLOR_ORANGE}host${CoR} --forward-port ${COLOR_ORANGE}port${CoR} [options]"
  echo -e "     Required:"
  help_row "            incoming_port" "Port to listen on"
  help_row "       --forward-host ${COLOR_ORANGE}host${CoR}" "Target host or IP"
  help_row "       --forward-port ${COLOR_ORANGE}port${CoR}" "Target port"
  echo -e "     Optional:"
  help_row "       --tcp" "Enable TCP forwarding"
  help_row "       --udp" "Enable UDP forwarding"
  help_row "       --cert-id ${COLOR_GREY}id${CoR}" "Certificate ID (default: 0)"
  help_row "  --stream-host-enable  ${COLOR_CYAN}🆔${CoR}" "Enable Stream Host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --stream-host-disable ${COLOR_CYAN}🆔${CoR}" "Disable Stream Host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --stream-host-delete  ${COLOR_CYAN}🆔${CoR}" "Delete Stream Host by ${COLOR_YELLOW}ID${CoR}"
  echo ""
  echo ""
  echo -e " Dead Host (404) Management:"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  help_row "  --dead-host-list" "List all Dead Hosts (404)"
  echo -e "  --dead-host-create ${COLOR_ORANGE}domain${CoR} [options]"
  echo -e "     Required:"
  help_row "            domain" "Domain name to serve 404 for"
  echo -e "     Optional:"
  help_row "       --cert-id ${COLOR_GREY}id${CoR}" "Certificate ID (default: 0)"
  help_row "       --ssl-forced ${COLOR_GREY}true|false${CoR}" "Force SSL (default: false)"
  help_row "       --http2 ${COLOR_GREY}true|false${CoR}" "Enable HTTP/2 (default: false)"
  help_row "       --hsts ${COLOR_GREY}true|false${CoR}" "Enable HSTS (default: false)"
  help_row "       --hsts-subdomains ${COLOR_GREY}true|false${CoR}" "HSTS subdomains (default: false)"
  help_row "       --advanced-config ${COLOR_GREY}string${CoR}" "Custom nginx config"
  help_row "  --dead-host-enable  ${COLOR_CYAN}🆔${CoR}" "Enable Dead Host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --dead-host-disable ${COLOR_CYAN}🆔${CoR}" "Disable Dead Host by ${COLOR_YELLOW}ID${CoR}"
  help_row "  --dead-host-delete  ${COLOR_CYAN}🆔${CoR}" "Delete Dead Host by ${COLOR_YELLOW}ID${CoR}"
  echo ""
  help_row "  --user-list" "List All Users"
  help_row "  --user-create ${COLOR_CYAN}username${CoR} ${COLOR_CYAN}password${CoR} ${COLOR_CYAN}email${CoR} ${COLOR_CYAN}[--admin]${CoR}" "Create User (${COLOR_GREY}--admin${CoR} grants admin role; default standard)"
  help_row "  --user-delete ${COLOR_CYAN}🆔${CoR}" "Delete User by ${COLOR_YELLOW}username${CoR}"
  echo ""
  help_row "  --access-list" "List All available Access Lists (ID and Name)"
  help_row "  --access-list-show ${COLOR_CYAN}🆔${CoR}" "Show detailed information for specific access list"
  help_row "  --access-list-create" "Create Access Lists with options:"
  echo -e "                                           • ${COLOR_YELLOW}--satisfy [any|all]${CoR}          Set access list satisfaction mode"
  echo -e "                                           • ${COLOR_YELLOW}--pass-auth [true|false]${CoR}     Enable/disable password authentication"
  echo -e "                                           • ${COLOR_YELLOW}--users \"user1,user2\"${CoR}        List of users (comma-separated)"
  echo -e "                                           • ${COLOR_YELLOW}--allow \"ip1,ip2\"${CoR}            List of allowed IPs/ranges"
  echo -e "                                           • ${COLOR_YELLOW}--deny \"ip1,ip2\"${CoR}             List of denied IPs/ranges"
  help_row "  --access-list-delete ${COLOR_CYAN}🆔${CoR}" "Delete Access List by access ID"
  help_row "  --access-list-update ${COLOR_CYAN}🆔${CoR}" "Update Access List by access ID with options:"
  echo -e "                                           • ${COLOR_YELLOW}--name \"new_name\"${CoR}            New name for the access list"
  echo -e "                                           • ${COLOR_YELLOW}--satisfy [any|all]${CoR}          Update satisfaction mode"
  echo -e "                                           • ${COLOR_YELLOW}--pass-auth [true|false]${CoR}     Update password authentication"
  echo -e "                                           • ${COLOR_YELLOW}--users \"user1,user2\"${CoR}        Update list of users"
  echo -e "                                           • ${COLOR_YELLOW}--allow \"ip1,ip2\"${CoR}            Update allowed IPs/ranges"
  echo -e "                                           • ${COLOR_YELLOW}--deny \"ip1,ip2\"${CoR}             Update denied IPs/ranges\n"
  #echo -e "\n    ${COLOR_CYAN}🆔${CoR} = ID Host Proxy"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  help_row "  --examples" "${COLOR_ORANGE}🔖 ${CoR}Examples ${COLOR_GREY}commands, more explicits${CoR}"
  echo -e "  --help                                 ${COLOR_YELLOW} 👉 ${COLOR_GREY}It's me${CoR}"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  exit 0
}

# List read commands compatible with the global --json modifier.
# Combine with --json (e.g. "--json --list") to get this list as raw JSON.
list_json_commands() {
  local cmds=(
    "--host-list|List all proxy hosts|./npm-api.sh --host-list --json"
    "--host-list-full|List all proxy hosts with full details (always pure JSON)|./npm-api.sh --host-list-full"
    "--host-show <id>|Show one proxy host|./npm-api.sh --host-show 42 --json"
    "--cert-list|List all SSL certificates|./npm-api.sh --cert-list --json"
    "--cert-show <domain_or_id>|Show certificate(s) filtered by domain or id|./npm-api.sh --cert-show example.com --json"
    "--redirect-host-list|List all redirection hosts|./npm-api.sh --redirect-host-list --json"
    "--stream-host-list|List all stream hosts|./npm-api.sh --stream-host-list --json"
    "--dead-host-list|List all dead hosts|./npm-api.sh --dead-host-list --json"
    "--access-list|List all access lists|./npm-api.sh --access-list --json"
    "--access-list-show <id>|Show one access list|./npm-api.sh --access-list-show 5 --json"
  )

  if [ "$JSON_OUTPUT" = true ]; then
    printf '%s\n' "${cmds[@]}" | jq -R -c 'split("|") | {command: .[0], description: .[1], example: .[2]}' | jq -s '.'
  else
    echo -e "\n${COLOR_ORANGE} 🤖 Commands compatible with --json:${CoR}\n"
    local c flag desc example
    for c in "${cmds[@]}"; do
      IFS='|' read -r flag desc example <<<"$c"
      help_row "  $flag" "$desc ${COLOR_GREY}, e.g. $example${CoR}"
    done
    echo ""
  fi
  exit 0
}

################################
# Examples CLI Commands
examples_cli() {
  echo -e "\n${COLOR_YELLOW}💡 Tips:${CoR}"
  echo -e "  • Use -y flag to skip confirmation prompts"
  echo -e "  • Check --help for complete command list"
  echo -e "  • Always backup before making major changes"
  echo -e "  • Use --host-list OR --host-search to find host IDs\n"

  echo -e "\n${COLOR_YELLOW}🔰 Common Usage Examples:${CoR}"
  # Basic commands
  echo -e "\n${COLOR_GREEN}📋 Basic Commands:${CoR}"
  echo -e "${COLOR_GREY}  # List all hosts in table format${CoR}"
  echo -e "  $0 --host-list"
  echo -e "${COLOR_GREY}  # Show detailed information about a specific host${CoR}"
  echo -e "  $0 --host-show 42"
  echo -e "${COLOR_GREY}  # Display default settings${CoR}"
  echo -e "  $0 --show-default"

  # Host Management
  echo -e "\n${COLOR_GREEN}🌐 Host Management:${CoR}"
  echo -e "${COLOR_GREY}  # Create new proxy host (basic)${CoR}"
  echo -e "  $0 --host-create example.com -i 192.168.1.10 -p 8080"
  echo -e "${COLOR_GREY}  # Create host with SSL and advanced config${CoR}"
  echo -e "  $0 --host-create example.com -i 127.0.0.1 -p 6666 -f https -b true -c true --cert-generate example.com --host-ssl-enable -y"
  echo -e "${COLOR_GREY}  # Create host with custom locations${CoR}"
  echo -e "  $0 --host-create example.com -i 192.168.1.10 -p 8080 -l '[{\"path\":\"/api\",\"forward_host\":\"192.168.1.11\",\"forward_port\":8081}]'"

  # SSL Management
  echo -e "\n${COLOR_GREEN}🔒 SSL Certificate Management:${CoR}"
  echo -e "${COLOR_GREY}  # Generate new SSL certificate${CoR}"
  echo -e "  $0 --cert-generate example.com admin@example.com"
  echo -e "${COLOR_GREY}  # Enable SSL for existing host${CoR}"
  echo -e "  $0 --host-ssl-enable 42"
  echo -e "${COLOR_GREY}  # List all SSL certificates${CoR}"
  echo -e "  $0 --cert-show"

  echo -e "${COLOR_GREY}  # List all certificates${CoR}"
  echo -e "  $0 --cert-list"
  echo -e "${COLOR_GREY}  # Download certificate as ZIP${CoR}"
  echo -e "  $0 --cert-download 123"
  echo -e "${COLOR_GREY}  # Generate SSL certificate${CoR}"
  echo -e "  $0 --cert-generate example.com --cert-email admin@example.com"

  # Add new section for Wildcard certificates
  echo -e "\n ${COLOR_GREEN}🌟 Wildcard SSL Certificates with DNS Providers:${CoR}"
  echo -e "${COLOR_GREY}  # Generate wildcard certificate with ${COLOR_CYAN}Cloudflare${COLOR_GREY} API token (recommended, permission Zone:DNS:Edit)${CoR}"
  echo -e "  $0 --cert-generate \"*.example.com\" \\"
  echo -e "    --dns-provider cloudflare \\"
  echo -e "    --dns-credentials '{\"dns_cloudflare_api_token\":\"your_token\"}'"
  echo -e "${COLOR_GREY}  # Same with the Cloudflare Global API Key (37 hex chars)${CoR}"
  echo -e "  $0 --cert-generate \"*.example.com\" \\"
  echo -e "    --dns-provider cloudflare \\"
  echo -e "    --dns-credentials '{\"dns_cloudflare_email\":\"your@email.com\",\"dns_cloudflare_api_key\":\"your_global_api_key\"}'"

  echo -e "\n${COLOR_GREY}  # Generate wildcard certificate with ${COLOR_CYAN}DigitalOcean${CoR}"
  echo -e "  $0 --cert-generate \"*.example.com\" \\"
  echo -e "    --dns-provider digitalocean \\"
  echo -e "    --dns-credentials '{\"dns_digitalocean_token\":\"your_token\"}'"

  echo -e "${COLOR_GREY}  # Generate wildcard certificate with ${COLOR_CYAN}GoDaddy${CoR}"
  echo -e "  $0 --cert-generate \"*.example.com\" \\"
  echo -e "    --dns-provider godaddy \\"
  echo -e "    --dns-credentials '{\"dns_godaddy_key\":\"your_key\",\"dns_godaddy_secret\":\"your_secret\"}'"

  echo -e "${COLOR_GREY}  # Generate wildcard certificate with ${COLOR_CYAN}OVH${CoR}"
  echo -e "  $0 --cert-generate \"*.example.com\" \\"
  echo -e "    --dns-provider ovh \\"
  echo -e "    --dns-credentials '{\"dns_ovh_endpoint\":\"ovh-eu\",\"dns_ovh_application_key\":\"key\",\"dns_ovh_application_secret\":\"secret\",\"dns_ovh_consumer_key\":\"consumer_key\"}'"

  echo -e "${COLOR_GREY}  # Generate wildcard certificate with ${COLOR_CYAN}Dynu${CoR}"
  echo -e "  $0 --cert-generate \"*.example.com\" \\"
  echo -e "    --dns-provider dynu \\"
  echo -e "    --dns-credentials '{\"dns_dynu_auth_token\":\"your_token\"}'"

  echo -e "\n${COLOR_GREY}  # Reuse an existing wildcard certificate for a new host (no DNS credentials needed)${CoR}"
  echo -e "  $0 --cert-show example.com                        ${COLOR_GREY}# get the certificate ID${CoR}"
  echo -e "  $0 --host-create app.example.com -i 192.168.1.10 -p 8080 -y"
  echo -e "  $0 --host-ssl-enable <host_id> <cert_id>"
  echo -e "${COLOR_GREY}  # Note: NPM >= 2.13 registers Let's Encrypt with the email of the NPM user account (--cert-email is ignored)${CoR}"

  # Redirection Host Management
  echo -e "\n${COLOR_GREEN}🔀 Redirection Host Management:${CoR}"
  echo -e "${COLOR_GREY}  # List all redirection hosts${CoR}"
  echo -e "  $0 --redirect-host-list"
  echo -e "${COLOR_GREY}  # Create a simple 301 redirect${CoR}"
  echo -e "  $0 --redirect-host-create old.example.com --forward-domain new.example.com"
  echo -e "${COLOR_GREY}  # Create a 302 redirect preserving path${CoR}"
  echo -e "  $0 --redirect-host-create old.example.com --forward-domain new.example.com --http-code 302 --preserve-path true"
  echo -e "${COLOR_GREY}  # Delete a redirection host (with auto-confirm)${CoR}"
  echo -e "  $0 --redirect-host-delete 5 -y"
  echo -e "${COLOR_GREY}  # Enable / disable a redirection host${CoR}"
  echo -e "  $0 --redirect-host-enable 5"
  echo -e "  $0 --redirect-host-disable 5"
  echo

  # Stream Host Management
  echo -e "\n${COLOR_GREEN}🔌 Stream Hosts:${CoR}"
  echo -e "${COLOR_GREY}  # List all stream hosts${CoR}"
  echo -e "  $0 --stream-host-list"
  echo -e "${COLOR_GREY}  # Forward DNS (TCP+UDP) port 53 to a Pi-hole container${CoR}"
  echo -e "  $0 --stream-host-create 53 --forward-host pihole --forward-port 53 --tcp --udp"
  echo -e "${COLOR_GREY}  # TCP-only forward${CoR}"
  echo -e "  $0 --stream-host-create 2222 --forward-host 192.168.1.10 --forward-port 22 --tcp"
  echo -e "${COLOR_GREY}  # Delete a stream host (with auto-confirm)${CoR}"
  echo -e "  $0 --stream-host-delete 5 -y"
  echo -e "${COLOR_GREY}  # Enable / disable a stream host${CoR}"
  echo -e "  $0 --stream-host-enable 5"
  echo -e "  $0 --stream-host-disable 5"
  echo

  # Dead Host (404) Management
  echo -e "\n${COLOR_GREEN}🚫 Dead Hosts (404):${CoR}"
  echo -e "${COLOR_GREY}  # List all dead hosts${CoR}"
  echo -e "  $0 --dead-host-list"
  echo -e "${COLOR_GREY}  # Create a 404 host for a decommissioned domain${CoR}"
  echo -e "  $0 --dead-host-create old.example.com"
  echo -e "${COLOR_GREY}  # Create with SSL forced and a certificate${CoR}"
  echo -e "  $0 --dead-host-create old.example.com --cert-id 3 --ssl-forced true --http2 true"
  echo -e "${COLOR_GREY}  # Delete a dead host (with auto-confirm)${CoR}"
  echo -e "  $0 --dead-host-delete 5 -y"
  echo -e "${COLOR_GREY}  # Enable / disable a dead host${CoR}"
  echo -e "  $0 --dead-host-enable 5"
  echo -e "  $0 --dead-host-disable 5"
  echo

  # User Management
  echo -e "\n${COLOR_GREEN}👤 User Management:${CoR}"
  echo -e "${COLOR_GREY}  # Create new user${CoR}"
  echo -e "  $0 --user-create john.doe secretpass john.doe@example.com"
  echo -e "${COLOR_GREY}  # List all users${CoR}"
  echo -e "  $0 --user-list"

  # Access Control
  echo -e "\n${COLOR_GREEN}🛡️ Access List Management Examples:${CoR}"
  echo -e "${COLOR_GREY}  # List all access lists${CoR}"
  echo -e "  $0 --access-list"
  echo
  echo -e "${COLOR_GREY}  # Show detailed information for specific access list${CoR}"
  echo -e "  $0 --access-list-show 123"
  echo
  echo -e "${COLOR_GREY}  # Create a basic access list${CoR}"
  echo -e "  $0 --access-list-create \"office\" --satisfy any"
  echo
  echo -e "${COLOR_GREY}  # Create access list with authentication${CoR}"
  echo -e "  $0 --access-list-create \"secure_area\" --satisfy all --pass-auth true"
  echo
  echo -e "${COLOR_GREY}  # Create access list with users${CoR}"
  echo -e "  $0 --access-list-create \"dev_team\" --users \"john,jane,bob\" --pass-auth true"
  echo
  echo -e "${COLOR_GREY}  # Create access list with IP rules${CoR}"
  echo -e "  $0 --access-list-create \"internal\" --allow \"192.168.1.0/24\" --deny \"192.168.1.100\""
  echo
  echo -e "${COLOR_GREY}  # Create comprehensive access list${CoR}"
  echo -e "  $0 --access-list-create \"full_config\" \\"
  echo -e "     --satisfy all \\"
  echo -e "     --pass-auth true \\"
  echo -e "     --users \"admin1,admin2\" \\"
  echo -e "     --allow \"10.0.0.0/8,172.16.0.0/12\" \\"
  echo -e "     --deny \"10.0.0.50,172.16.1.100\""
  echo
  echo -e "${COLOR_GREY}  # Update existing access list${CoR}"
  echo -e "  $0 --access-list-update 123 --name \"new_name\" --satisfy any"
  echo
  echo -e "${COLOR_GREY}  # Update access list with new allow rules${CoR}"
  echo -e "  $0 --access-list-update 123 --allow \"172.0.0.0/8,10.0.0.0/8\""
  echo
  echo -e "${COLOR_GREY}  # Delete access list${CoR}"
  echo -e "  $0 --access-list-delete 123"

  echo -e "${COLOR_GREY}  # Enable ACL for a host${CoR}"
  echo -e "  $0 --host-acl-enable 42 2"

  # Advanced Configuration
  echo -e "${COLOR_GREY}  # Create host with custom headers${CoR}"
  echo -e "  $0 --host-create example.com -i 192.168.1.10 -p 8080 -a 'proxy_set_header X-Real-IP \$remote_addr;'"
  echo -e "${COLOR_GREY}  # Update specific field of existing host${CoR}"
  echo -e "  $0 --host-update 42 forward_host=new.example.com"

  echo -e "\n${COLOR_GREEN}⚙️ Advanced Configuration:${CoR}"
  echo -e "${COLOR_GREY}  # Create host with all options${CoR}"
  echo -e "  $0 --host-create example.com -i 192.168.1.10 -p 8080 \\"
  echo -e "     -f https \\"
  echo -e "     -c true \\"
  echo -e "     -b true \\"
  echo -e "     -w true \\"
  echo -e "     -h true \\"
  echo -e "     -s true \\"
  echo -e "     -a 'proxy_set_header X-Real-IP \$remote_addr;' \\"
  echo -e "     -l '[{\"path\":\"/api\",\"forward_host\":\"api.local\",\"forward_port\":3000}]'"

  echo -e "\n${COLOR_YELLOW}📝 Command Parameters:${CoR}"
  echo -e "  domain                : Domain name for the proxy host"
  echo -e "  -i, --forward-host    : Target server (IP/hostname)"
  echo -e "  -p, --forward-port    : Target port"
  echo -e "  -f, --forward-scheme  : http/https"
  echo -e "  -c, --cache           : Enable cache"
  echo -e "  -b, --block-exploits  : Protection against exploits"
  echo -e "  -w, --websocket       : WebSocket support"
  echo -e "  -h, --http2           : HTTP/2 support"
  echo -e "  -s, --ssl-force       : Force SSL"
  echo -e "  -a, --advanced-config : Custom Nginx configuration"
  echo -e "  -l, --locations       : Custom location rules (JSON)\n"
  exit 0
}
################################
# Display script variables info
display_info() {
  check_token true
  echo -e "${COLOR_YELLOW}\n Script Info:  ${COLOR_GREEN}${VERSION}${CoR}"
  echo -e " ${COLOR_YELLOW}Script Variables Information:${CoR}"
  #echo -e "\n ${COLOR_GREEN}DATA_DIR${CoR} ${DATA_DIR}"
  echo -e " ${COLOR_GREEN}Config${CoR}      : ${SCRIPT_DIR}/npm-api.conf"
  echo -e " ${COLOR_GREEN}BASE  URL${CoR}   : ${BASE_URL}"
  echo -e " ${COLOR_GREEN}NGINX  IP${CoR}   : ${NGINX_IP}"
  echo -e " ${COLOR_GREEN}USER NPM${CoR}    : ${API_USER}"
  echo -e " ${COLOR_GREEN}BACKUP DIR ${CoR} : ${DATA_DIR_ID}"
  #echo -e " ${COLOR_GREEN}DOCKER Path${CoR} : ${NGINX_PATH_DOCKER}"

  display_dashboard

  DATE=$(date +"_%Y_%m_%d__%H_%M_%S")
  BACKUP_PATH="$BACKUP_DIR"

  # Check if directory exists and contains files
  if [ -d "$BACKUP_PATH" ] && [ -n "$(find "$BACKUP_PATH" -mindepth 1 -print -quit 2>/dev/null)" ]; then
    # Count backup files by type
    local total_files=$(find "$BACKUP_PATH" -type f \( \
      -name "*.json" -o \
      -name "*.conf" -o \
      -name "*.log" -o \
      -name "*.pem" -o \
      -name "*.key" \
      \) 2>/dev/null | wc -l)

    if [ "$total_files" -gt 0 ]; then
      echo -e "\n ${COLOR_CYAN}💾 Backup Statistics 📦${CoR}"
      echo -e " ${COLOR_GREY}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CoR}"
      local config_files=$(find "$BACKUP_PATH" -maxdepth 1 -type f -name "full_config*.json" 2>/dev/null | wc -l)
      local proxy_files=$(find "$BACKUP_PATH/.Proxy_Hosts" -type f -name "proxy_config.json" 2>/dev/null | wc -l)
      local redirect_files=$(find "$BACKUP_PATH/.Redirection_Hosts" -type f -name "*.json" 2>/dev/null | wc -l)
      local stream_files=$(find "$BACKUP_PATH/.Stream_Hosts" -type f -name "*.json" 2>/dev/null | wc -l)
      local dead_files=$(find "$BACKUP_PATH/.Dead_Hosts" -type f -name "*.json" 2>/dev/null | wc -l)
      local ssl_files=$(find "$BACKUP_PATH" -type f \( \
        -name "certificate*.json" -o \
        -name "*.pem" -o \
        -name "*.key" \
        \) 2>/dev/null | wc -l)
      local access_files=$(find "$BACKUP_PATH/.access_lists" -type f -name "*.json" 2>/dev/null | wc -l)
      local settings_files=$(find "$BACKUP_PATH/.settings" -type f -name "*.json" 2>/dev/null | wc -l)
      local user_files=$(find "$BACKUP_PATH/.user" -type f -name "*.json" 2>/dev/null | wc -l)

      # Show statistics only if there are files
      [ "$config_files" -gt 0 ] && echo -e " • Full Config Files : ${COLOR_CYAN}$config_files${CoR}"
      [ "$proxy_files" -gt 0 ] && echo -e " • Proxy Host Files  : ${COLOR_CYAN}$proxy_files${CoR}"
      [ "$redirect_files" -gt 0 ] && echo -e " • Redirection Files : ${COLOR_CYAN}$redirect_files${CoR}"
      [ "$stream_files" -gt 0 ] && echo -e " • Stream Host Files : ${COLOR_CYAN}$stream_files${CoR}"
      [ "$dead_files" -gt 0 ] && echo -e " • 404 Host Files    : ${COLOR_CYAN}$dead_files${CoR}"
      [ "$ssl_files" -gt 0 ] && echo -e " • SSL Files         : ${COLOR_CYAN}$ssl_files${CoR}"
      [ "$access_files" -gt 0 ] && echo -e " • Access Lists      : ${COLOR_CYAN}$access_files${CoR}"
      [ "$settings_files" -gt 0 ] && echo -e " • Settings Files    : ${COLOR_CYAN}$settings_files${CoR}"
      [ "$user_files" -gt 0 ] && echo -e " • User Files        : ${COLOR_CYAN}$user_files${CoR}"
      echo -e " • Total Files       : ${COLOR_CYAN}$total_files${CoR}"
    fi
  fi

  # Display backup locations
  echo -e "\n 📂 ${COLOR_YELLOW}Backup Locations:${CoR}"
  echo -e "  • Backup: ${COLOR_GREY}$BACKUP_PATH${CoR}"
  echo -e "  • Token: ${COLOR_GREY}$BACKUP_PATH/token/${CoR}"

  echo -e "\n ${COLOR_YELLOW}💡 Use --help to see available commands${CoR}"
  echo -e "   ${COLOR_GREY} Check --examples for more help examples${CoR}\n"
}

################################
# Check GitHub for a newer release of this script
# Usage: check_update
################################
check_update() {
  check_dependencies
  local repo="Erreur32/nginx-proxy-manager-Bash-API"
  echo -e "\n 🔍 ${COLOR_CYAN}Checking for script updates...${CoR}"

  local latest_json
  latest_json=$(curl -s --max-time 5 "https://api.github.com/repos/$repo/releases/latest" 2>/dev/null || true)
  local latest_version
  latest_version=$(echo "$latest_json" | jq -r '.tag_name // empty' 2>/dev/null)
  latest_version="${latest_version#v}"

  if [ -z "$latest_version" ]; then
    echo -e " ⛔ ${COLOR_RED}Unable to check for updates (no network or GitHub API unavailable).${CoR}\n"
    return 1
  fi

  echo -e " • Current version : ${COLOR_YELLOW}${VERSION}${CoR}"
  echo -e " • Latest  version : ${COLOR_YELLOW}${latest_version}${CoR}"

  if [ "$latest_version" = "$VERSION" ]; then
    echo -e "\n ✅ ${COLOR_GREEN}You are running the latest version!${CoR}\n"
  else
    local html_url
    html_url=$(echo "$latest_json" | jq -r '.html_url // empty' 2>/dev/null)
    echo -e "\n 🆕 ${COLOR_ORANGE}A new version is available: ${COLOR_GREEN}${latest_version}${CoR}"
    [ -n "$html_url" ] && echo -e " 🔗 ${COLOR_CYAN}${html_url}${CoR}"
    echo -e " 💡 ${COLOR_GREY}Update: git -C \"$SCRIPT_DIR\" pull${CoR} ${COLOR_GREY}(or download the release manually)${CoR}\n"
  fi
}

# Function to display dashboard
display_dashboard() {
  #check_token_notverbose

  echo -e "\n ${COLOR_CYAN}📊 NGINX - Proxy Manager - Dashboard 🔧 ${CoR}"
  echo -e " ${COLOR_GREY}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CoR}"
  # Get all data first
  local proxy_hosts=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/proxy-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  local redirection_hosts=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/redirection-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  local stream_hosts=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/streams" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  local dead_hosts=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/dead-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  local access_lists=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/access-lists" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  local certificates=$(curl -s --max-redirs 0 -X GET "$BASE_URL/nginx/certificates" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  local users=$(curl -s --max-redirs 0 -X GET "$BASE_URL/users" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  # Calculate counts with error checking
  local proxy_count=0
  local enabled_proxy_count=0
  local redirect_count=0
  local enabled_redirect_count=0
  local stream_count=0
  local enabled_stream_count=0
  local dead_count=0
  local enabled_dead_count=0
  local cert_count=0
  local expired_cert_count=0
  local user_count=0
  local access_list_count=0

  # Check and calculate proxy hosts
  if [ "$(echo "$proxy_hosts" | jq -r 'type')" == "array" ]; then
    proxy_count=$(echo "$proxy_hosts" | jq '. | length')
    enabled_proxy_count=$(echo "$proxy_hosts" | jq '[.[] | select(.enabled == true)] | length')
  fi
  local disabled_proxy_count=$((proxy_count - enabled_proxy_count))

  # Check and calculate redirection hosts
  if [ "$(echo "$redirection_hosts" | jq -r 'type')" == "array" ]; then
    redirect_count=$(echo "$redirection_hosts" | jq '. | length')
    enabled_redirect_count=$(echo "$redirection_hosts" | jq '[.[] | select(.enabled == true)] | length')
  fi
  local disabled_redirect_count=$((redirect_count - enabled_redirect_count))

  # Check and calculate stream hosts
  if [ "$(echo "$stream_hosts" | jq -r 'type')" == "array" ]; then
    stream_count=$(echo "$stream_hosts" | jq '. | length')
    enabled_stream_count=$(echo "$stream_hosts" | jq '[.[] | select(.enabled == true)] | length')
  fi
  local disabled_stream_count=$((stream_count - enabled_stream_count))

  # Check and calculate 404 hosts (dead hosts)
  if [ "$(echo "$dead_hosts" | jq -r 'type')" == "array" ]; then
    dead_count=$(echo "$dead_hosts" | jq '. | length')
    enabled_dead_count=$(echo "$dead_hosts" | jq '[.[] | select(.enabled == true)] | length')
  fi
  local disabled_dead_count=$((dead_count - enabled_dead_count))

  # Check and calculate access lists
  if [ "$(echo "$access_lists" | jq -r 'type')" == "array" ]; then
    access_list_count=$(echo "$access_lists" | jq '. | length')
  fi

  # Check and calculate certificates
  if [ "$(echo "$certificates" | jq -r 'type')" == "array" ]; then
    cert_count=$(echo "$certificates" | jq '. | length')
    expired_cert_count=$(echo "$certificates" | jq "$CERT_JQ_EXPIRED"' [.[] | select(is_expired)] | length')
  fi
  local valid_cert_count=$((cert_count - expired_cert_count))

  # Check and calculate users
  if [ "$(echo "$users" | jq -r 'type')" == "array" ]; then
    user_count=$(echo "$users" | jq '. | length')
  fi

  # Get version and uptime
  local uptime=$(uptime | sed 's/.*up \([^,]*\),.*/\1/')
  local version_info=$(curl -s --max-redirs 0 -X GET "$BASE_URL/")
  local npm_version="Unknown"
  if echo "$version_info" | jq -e '.version' >/dev/null 2>&1; then
    npm_version=$(echo "$version_info" | jq -r '"\(.version.major).\(.version.minor).\(.version.revision)"')
  fi

  print_row() {
    local component="$1"
    local status="$2"
    local force_color="${3:-}" # Initialize with empty value by default
    local status_color=""
    # If a color is forced, use it
    if [ -n "$force_color" ]; then
      status_color="$force_color"
    # Otherwise, apply automatic coloring logic
    else
      # Components that should not be colored green
      case "$component" in
      *"Disabled"* | *"Expired"* | *"Uptime"* | *"Version"*)
        status_color=""
        ;;
      *)
        # For others, color green if > 0
        if [[ "$status" =~ ^[0-9]+$ ]] && [ "$status" -gt 0 ]; then
          status_color="$COLOR_GREEN"
        fi
        ;;
      esac
    fi

    # Calculate padding needed (20 is the max width of status column)
    local status_length=${#status}
    local padding=$((8 - status_length))
    local spaces=$(printf '%*s' "$padding" '')
    echo -e " ${COLOR_GREY}│${CoR} $component ${COLOR_GREY}│${CoR} ${status_color}$status${spaces}${CoR}${COLOR_GREY}│${CoR}"
  }
  echo -e " ${COLOR_GREY}┌─────────────────┬─────────┐${CoR}"
  echo -e " ${COLOR_GREY}│${CoR}  COMPONENT      ${COLOR_GREY}│${CoR} STATUS  ${COLOR_GREY}│${CoR}"
  echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
  # --- Hosts (same order as the NPM web UI: Proxy / Redirection / Streams / 404) ---
  # Proxy Hosts
  print_row "🌐 Proxy Hosts " "$proxy_count" "$COLOR_YELLOW"
  print_row "├─ Enabled     " "$enabled_proxy_count"
  print_row "└─ Disabled    " "$disabled_proxy_count" "$COLOR_RED"
  echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
  # Redirection Hosts
  print_row "🔄 Redirections" "$redirect_count" "$COLOR_YELLOW"
  print_row "├─ Enabled     " "$enabled_redirect_count"
  print_row "└─ Disabled    " "$disabled_redirect_count" "$COLOR_RED"
  echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
  # Stream Hosts
  print_row "🔌 Stream Hosts" "$stream_count" "$COLOR_YELLOW"
  print_row "├─ Enabled     " "$enabled_stream_count"
  print_row "└─ Disabled    " "$disabled_stream_count" "$COLOR_RED"
  echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
  # 404 Hosts (Dead Hosts)
  print_row "🚫 404 Hosts   " "$dead_count" "$COLOR_YELLOW"
  print_row "├─ Enabled     " "$enabled_dead_count"
  print_row "└─ Disabled    " "$disabled_dead_count" "$COLOR_RED"
  echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
  # Access Lists
  print_row "🔒 Access Lists" "$access_list_count"
  echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
  # SSL Certificates
  print_row "🔒 Certificates" "$cert_count" "$COLOR_YELLOW"
  print_row "├─ Valid       " "$valid_cert_count"
  print_row "└─ Expired     " "$expired_cert_count" "$COLOR_RED"
  echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
  # Users
  print_row "👥 Users       " "$user_count"
  echo -e " ${COLOR_GREY}├─────────────────┼─────────┤${CoR}"
  # System
  print_row "⏱️  Uptime      " "$uptime" "$COLOR_YELLOW"
  print_row "📦 NPM Version " "$npm_version" "$COLOR_YELLOW"
  echo -e " ${COLOR_GREY}└─────────────────┴─────────┘${CoR}"
}

################################
# show_default
# Display default settings for creating hosts
show_default() {
  check_token_notverbose
  echo -e "\n📝 ${COLOR_YELLOW}Default Settings for Creating Hosts:${CoR}"
  echo -e "\n ${COLOR_GREEN}Basic Settings:${CoR}"
  echo -e "  Forward Scheme:           $(colorize_booleanh "$FORWARD_SCHEME")"
  echo -e "  Caching Enabled:          $(colorize_boolean "$CACHING_ENABLED")"
  echo -e "  Block Exploits:           $(colorize_boolean "$BLOCK_EXPLOITS")"
  echo -e "  Allow Websocket Upgrade:  $(colorize_boolean "$ALLOW_WEBSOCKET_UPGRADE")"

  echo -e "\n ${COLOR_GREEN}SSL Settings:${CoR}"
  echo -e "  HTTP/2 Support:           $(colorize_boolean "$HTTP2_SUPPORT")"
  echo -e "  SSL Forced:               $(colorize_boolean "$SSL_FORCED")"
  echo -e "  HSTS Enabled:             $(colorize_boolean "$HSTS_ENABLED")"
  echo -e "  HSTS Subdomains:          $(colorize_boolean "$HSTS_SUBDOMAINS")"

  echo -e "\n ${COLOR_GREEN}Advanced Settings:${CoR}"
  if [ -n "$ADVANCED_CONFIG" ]; then
    echo -e "  Advanced Config:          ${COLOR_YELLOW}$ADVANCED_CONFIG${CoR}"
  else
    echo -e "  Advanced Config:          ${COLOR_GREY}Not configured${CoR}"
  fi

  if [ -n "$CUSTOM_LOCATIONS" ]; then
    echo -e "  Custom Locations:         ${COLOR_YELLOW}$CUSTOM_LOCATIONS${CoR}"
  else
    echo -e "  Custom Locations:         ${COLOR_GREY}Not configured${CoR}"
  fi

  echo -e "\n ${COLOR_GREEN}System Settings:${CoR}"
  echo -e "  Base URL:                 $BASE_URL"
  echo -e "  Base Directory:           $DATA_DIR"
  echo -e "  Token Directory:          $TOKEN_DIR"
  echo -e "  Backup Directory:         $BACKUP_DIR"
  echo -e "  Token Expiry:             $TOKEN_EXPIRY\n"

  exit 0
}
#######################################################################################

################################
# List all users
user_list() {
  check_token_notverbose
  echo -e "\n 👉 List of users..."
  RESPONSE=$(curl -s -X GET "$BASE_URL/users" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  echo -e "\n $RESPONSE" | jq
  exit 0
}

################################
# Create a new user
user_create() {
  check_token_notverbose
  if [ -z "$USERNAME" ] || [ -z "$PASSWORD" ] || [ -z "$EMAIL" ]; then
    echo -e "\n 👤 ${COLOR_RED}The --user-create option requires username, password, and email.${CoR}"
    echo -e " Usage: ${COLOR_ORANGE}$0 --user-create username password email [--admin]${CoR}"
    echo -e " Example:"
    echo -e "   ${COLOR_GREEN}$0 --user-create john secretpass john@domain.com${CoR}\n"
    return 1
  fi
  # check if user already exists
  EXISTING_USERS=$(curl -s -X GET "$BASE_URL/users" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  # check if email already exists
  if echo "$EXISTING_USERS" | jq -e --arg email "$EMAIL" '.[] | select(.email == $email)' >/dev/null; then
    echo -e "\n ⛔ ${COLOR_RED}Error: A user with email $EMAIL already exists.${CoR}"
    return 1
  fi
  # check if username already exists
  if echo "$EXISTING_USERS" | jq -e --arg name "$USERNAME" '.[] | select(.name == $name)' >/dev/null; then
    echo -e "\n ⛔ ${COLOR_RED}Error: A user with name $USERNAME already exists.${CoR}"
    return 1
  fi
  # create user
  # Standard user by default; admin only when --admin was passed
  if [ "$USER_IS_ADMIN" = true ]; then
    ROLES_JSON='["admin"]'
    echo -e "\n 👤 Creating ${COLOR_YELLOW}admin${CoR} user ${COLOR_GREEN}$USERNAME${CoR}..."
  else
    ROLES_JSON='[]'
    echo -e "\n 👤 Creating user ${COLOR_GREEN}$USERNAME${CoR}..."
  fi
  DATA=$(jq -n \
    --arg username "$USERNAME" \
    --arg password "$PASSWORD" \
    --arg email "$EMAIL" \
    --arg name "$USERNAME" \
    --arg nickname "$USERNAME" \
    --arg secret "$PASSWORD" \
    --argjson roles "$ROLES_JSON" \
    '{
      name: $name,
      nickname: $nickname,
      email: $email,
      roles: $roles,
      is_disabled: false,
      auth: {
        type: "password",
        secret: $secret
      }
    }')
  # send data to API
  RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X POST "$BASE_URL/users" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$DATA")

  HTTP_BODY=${RESPONSE//HTTPSTATUS:*/}
  HTTP_STATUS=${RESPONSE##*HTTPSTATUS:}

  if [ "${HTTP_STATUS:-0}" -eq 201 ]; then
    # get user id
    USERS_RESPONSE=$(curl -s -X GET "$BASE_URL/users" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

    USER_ID=$(echo "$USERS_RESPONSE" | jq -r --arg email "$EMAIL" --arg name "$USERNAME" \
      '.[] | select(.email == $email and .name == $name) | .id')

    if [ -n "$USER_ID" ]; then
      echo -e " ✅ ${COLOR_GREEN}User $USERNAME created successfully!${CoR}"
      echo -e " 📧 Email: ${COLOR_YELLOW}$EMAIL${CoR}"
      echo -e " 🆔 User ID: ${COLOR_YELLOW}$USER_ID${CoR}\n"
    else
      echo -e " ⚠️ ${COLOR_GREEN}User created but couldn't fetch ID${CoR}"
      echo -e " 📧 Email: ${COLOR_YELLOW}$EMAIL${CoR}\n"
    fi
    return 0
  else
    echo -e " ⛔ ${COLOR_RED}Failed to create user. Status: $HTTP_STATUS${CoR}"
    echo -e " Error: ${COLOR_RED}$HTTP_BODY${CoR}\n"
    return 1
  fi
}

################################
# Delete a user
# $1: user_id - ID of the user to delete
user_delete() {
  local USER_ID="$1"

  if [ -z "$USER_ID" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: User ID is required${CoR}"
    echo -e " Usage  : ${COLOR_ORANGE}$0 --user-delete <user_id> [-y]${CoR}"
    echo -e " Example: ${COLOR_GREEN}$0 --user-delete 42${CoR}"
    exit 1
  fi

  # Check if USER_ID is a number
  if ! [[ "$USER_ID" =~ ^[0-9]+$ ]]; then
    echo -e " ⛔ ${COLOR_RED}ERROR: Invalid user ID '$USER_ID' - must be a number${CoR}"
    echo -e " Usage  : ${COLOR_ORANGE}$0 --user-delete <user_id> [-y]${CoR}"
    echo -e " Example: ${COLOR_GREEN}$0 --user-delete 42${CoR}"
    exit 1
  fi
  check_token_notverbose

  # Get user details first
  local RESPONSE=$(curl -s -X GET "$BASE_URL/users/$USER_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$(echo "$RESPONSE" | jq -r '.error.code // empty')" = "404" ]; then
    echo -e " ⛔ ${COLOR_RED}User ID $USER_ID not found${CoR}"
    exit 1
  fi

  local USERNAME=$(echo "$RESPONSE" | jq -r '.name')
  local EMAIL=$(echo "$RESPONSE" | jq -r '.email')

  if [ "$AUTO_YES" = true ]; then
    echo -e " 🔔 Auto-confirming deletion of user '$USERNAME' (ID: $USER_ID)..."
  else
    echo -e " ┌───────────────────────────────────────────"
    echo -e " │ ID: ${COLOR_YELLOW}$USER_ID${CoR}"
    echo -e " │ Name: ${COLOR_GREEN}$USERNAME${CoR}"
    echo -e " │ Email: ${COLOR_CYAN}$EMAIL${CoR}"
    echo -e " └───────────────────────────────────────────"
    echo -e " ⚠️  ${COLOR_RED}WARNING: This action cannot be undone!${CoR}"
    read -n 1 -r -p " 🔔 Confirm deletion? (y/n): " CONFIRM
    echo
    if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
      echo -e " ❌ ${COLOR_RED}Operation cancelled${CoR}"
      exit 1
    fi
  fi

  # Delete user
  RESPONSE=$(curl -s -X DELETE "$BASE_URL/users/$USER_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$RESPONSE" = "true" ]; then
    echo -e " ✅ ${COLOR_GREEN}User '$USERNAME' (ID: $USER_ID) deleted successfully!${CoR}"
  else
    echo -e " ⛔ ${COLOR_RED}Failed to delete user.${CoR}"
    if [ -n "$RESPONSE" ]; then
      echo -e "    Error: $RESPONSE"
    fi
    exit 1
  fi
}

################################
# Check if a certificate exists and is valid
check_certificate_exists() {
  local DOMAIN="$1"
  local RESPONSE
  local CERT_ID

  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [[ "$DOMAIN" == \** ]]; then
    CERT_ID=$(echo "$RESPONSE" | jq -r --arg domain "$DOMAIN" \
      '.[] | select(.domain_names[] == $domain) | .id' | sort -n | tail -n1)
  else
    local BASE_DOMAIN="${DOMAIN#\*\.}"
    CERT_ID=$(echo "$RESPONSE" | jq -r --arg domain "$BASE_DOMAIN" \
      '.[] | select(
                (.domain_names[] == $domain) or
                (.domain_names[] | startswith("*.") and ($domain | endswith(.[2:]))) or
                ($domain | startswith("*.") and (.domain_names[] | endswith(.[2:])))
            ) | .id' | sort -n | tail -n1)
  fi

  if [ -n "$CERT_ID" ]; then
    return 0
  else
    return 1
  fi
}

##############################################################
# Function to delete all existing proxy hosts  # DEBUG
##############################################################
# Delete all existing proxy hosts
delete_all_proxy_hosts() {
  check_token_notverbose
  echo -e "\n 🗑️ ${COLOR_ORANGE}Deleting all existing proxy hosts...${CoR}"

  # Get all host IDs
  local existing_hosts=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" | jq -r '.[].id')

  local count=0
  for host_id in $existing_hosts; do
    echo -e " •  Deleting host ID ${COLOR_CYAN}$host_id${CoR}...${COLOR_GREEN}✓${CoR}"
    local response=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE "$BASE_URL/nginx/proxy-hosts/$host_id" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

    local http_body=$(echo "$response" | sed -e 's/HTTPSTATUS\:.*//g')
    local http_status=$(echo "$response" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')

    if [ "${http_status:-0}" -ne 200 ]; then
      echo -e " ⛔ ${COLOR_RED}Failed to delete host ID $host_id. HTTP status: $http_status. Response: $http_body${CoR}"
      return 1
    fi
    count=$((count + 1))
  done

  echo -e " ✅ ${COLOR_GREEN}Successfully deleted $count proxy hosts!${CoR}"
  return 0
}

################################
# --clean_hosts from_backup_file
# Function to reimport hosts from backup file
# Create a safety backup before major operations
create_safety_backup() {
  check_token_notverbose
  TIMESTAMP=$(date +%Y%m%d_%H%M%S)
  SAFETY_BACKUP="$BACKUP_DIR/pre_reimport_SAFETY_BACKUP_${TIMESTAMP}.json"
  echo -e "📦 Creating safety backup..."
  # Get the list of IDs
  local host_ids=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" | jq -r '.[].id')
  # Create a table to store the complete configurations
  echo "[" >"$SAFETY_BACKUP"
  local first=true
  # Get the detailed configuration of each host
  for id in $host_ids; do
    if [ "$first" = true ]; then
      first=false
    else
      echo "," >>"$SAFETY_BACKUP"
    fi

    curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$id" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" >>"$SAFETY_BACKUP"
  done

  echo "]" >>"$SAFETY_BACKUP"
  # Verify that the backup is valid
  if ! jq empty "$SAFETY_BACKUP" 2>/dev/null; then
    echo -e " ❌ ${COLOR_RED}Failed to create valid safety backup${CoR}"
    exit 1
  fi
  echo -e " ✅ ${COLOR_GREEN}Safety backup created: ${COLOR_CYAN}$SAFETY_BACKUP${CoR}"
  return 0
}

################################
# Function to display import summary
display_import_summary() {
  echo -e "\n📊 ${COLOR_YELLOW}Import Summary:${CoR}"
  echo -e " • Total hosts processed: ${COLOR_CYAN}$total${CoR}"
  echo -e " • Successfully imported: ${COLOR_GREEN}$success${CoR}"
  echo -e " • Failed imports: ${COLOR_RED}$failed${CoR}"
  echo -e "\n🔒 SSL Certificates:"
  echo -e " • Successfully configured: ${COLOR_GREEN}$ssl_success${CoR}"
  echo -e " • Failed configurations: ${COLOR_RED}$ssl_failed${CoR}"

  if [ ${#failed_ssl_domains[@]} -gt 0 ]; then
    echo -e "\n⚠️ ${COLOR_YELLOW}Domains with failed SSL setup:${CoR}"
    for domain in "${failed_ssl_domains[@]}"; do
      echo -e " • $domain"
    done
  fi

  echo -e "\n✨ ${COLOR_GREEN}Import process completed${CoR}"
}

################################
# jq helper: the NPM API has no `expired` field, derive it from expires_on
# ("YYYY-MM-DD HH:MM:SS" on SQLite, ISO 8601 on MySQL/Postgres)
CERT_JQ_EXPIRED='def is_expired: if has("expired") then .expired == true else ((.expires_on // "")[0:19] | sub(" "; "T") + "Z" | try fromdateiso8601 catch null) as $t | ($t != null and $t < now) end;'

################################
# Shared jq format + colorizer for certificate listings (used by cert_show and
# list_cert_all). CERT_JQ_FMT formats one certificate object; cert_colorize
# reads that output on stdin and colors the Status line.
CERT_JQ_FMT='" 🔒 ID: \(.id)\n    • Domain(s): \(.domain_names | join(", "))\n    • Provider: \(.provider)\n    • Created on: \(.created_on // "N/A")\n    • Expires on: \(.expires_on // "N/A")\n    • Status: \(if is_expired then "❌ EXPIRED" else if .expires_on then "✅ VALID" else "⚠️ PENDING" end end)"'

cert_colorize() {
  while IFS= read -r line; do
    if [[ $line == *"❌ EXPIRED"* ]]; then
      echo -e "${line/❌ EXPIRED/${COLOR_RED}❌ EXPIRED${CoR}}"
    elif [[ $line == *"✅ VALID"* ]]; then
      echo -e "${line/✅ VALID/${COLOR_GREEN}✅ VALID${CoR}}"
    elif [[ $line == *"⚠️ PENDING"* ]]; then
      echo -e "${line/⚠️ PENDING/${COLOR_YELLOW}⚠️ PENDING${CoR}}"
    else
      echo -e "$line"
    fi
  done
}

################################
# Function to list SSL certificates by ID or domain
cert_show() {
  local search_term="$1"
  check_token_notverbose

  # If no search term is provided, show usage
  if [ -z "$search_term" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: Missing argument${CoR}"
    echo -e "    Usage: "
    echo -e "      ${COLOR_ORANGE}$0 --cert-show <domain>${CoR}     🔍 Search by domain name"
    echo -e "      ${COLOR_ORANGE}$0 --cert-show <id>${CoR}         🔢 Search by ID"
    echo -e "      ${COLOR_ORANGE}$0 --cert-show-all${CoR}          📜 List all certificates\n"
    exit 1
  fi

  # Get all certificates
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ -z "$RESPONSE" ] || [ "$RESPONSE" == "null" ]; then
    echo -e " ⛔ ${COLOR_RED}Error: Unable to retrieve certificates${CoR}"
    exit 1
  fi

  # Search by ID if numeric
  if [[ "$search_term" =~ ^[0-9]+$ ]]; then
    [ "$JSON_OUTPUT" = true ] || echo -e "\n 🔍 Searching for certificate with ID: ${COLOR_YELLOW}$search_term${CoR}"

    # Get specific certificate by ID
    CERT_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates/$search_term" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

    if echo "$CERT_RESPONSE" | jq -e '.error' >/dev/null; then
      if [ "$JSON_OUTPUT" = true ]; then
        echo '{"error": "Certificate not found with ID: '"$search_term"'"}'
        exit 1
      fi
      echo -e " ⛔ ${COLOR_RED}Certificate not found with ID: $search_term${CoR}"
    else
      if [ "$JSON_OUTPUT" = true ]; then
        echo "$CERT_RESPONSE" | jq .
        exit 0
      fi
      echo "$CERT_RESPONSE" | jq -r "$CERT_JQ_EXPIRED $CERT_JQ_FMT" | cert_colorize
    fi
    echo ""
    return 0
  fi

  # Search by domain name (partial match)
  if [ "$JSON_OUTPUT" = true ]; then
    echo "$RESPONSE" | jq --arg domain "$search_term" '[.[] | select(.domain_names[] | contains($domain))]'
    exit 0
  fi

  echo -e "\n 🔍 Searching certificates for domain: ${COLOR_YELLOW}$search_term${CoR}"
  DOMAIN_CERTS=$(echo "$RESPONSE" | jq -r --arg domain "$search_term" \
    '.[] | select(.domain_names[] | contains($domain))')

  if [ -z "$DOMAIN_CERTS" ]; then
    echo -e " ℹ️ ${COLOR_YELLOW}No certificates found for domain: $search_term${CoR}"
  else
    echo "$DOMAIN_CERTS" | jq -r "$CERT_JQ_EXPIRED $CERT_JQ_FMT" | cert_colorize
    echo ""
  fi
}

################################
# Function to list all SSL certificates
list_cert_all() {
  check_token_notverbose

  # Get all certificates
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ -z "$RESPONSE" ] || [ "$RESPONSE" == "null" ]; then
    echo -e " ⛔ ${COLOR_RED}Error: Unable to retrieve certificates${CoR}"
    exit 1
  fi

  if [ "$JSON_OUTPUT" = true ]; then
    echo "$RESPONSE" | jq .
    exit 0
  fi

  echo -e "\n 📜 SSL Certificates List:"

  # Check if there are any certificates
  if [ "$RESPONSE" = "[]" ]; then
    echo -e " ℹ️ ${COLOR_YELLOW}No certificates found${CoR}"
    return 0
  fi

  # Process and display all certificates
  echo "$RESPONSE" | jq -r "$CERT_JQ_EXPIRED .[] | $CERT_JQ_FMT" | cert_colorize
  # Display statistics
  TOTAL_CERTS=$(echo "$RESPONSE" | jq '. | length')
  EXPIRED_CERTS=$(echo "$RESPONSE" | jq "$CERT_JQ_EXPIRED"' [.[] | select(is_expired)] | length')
  VALID_CERTS=$((TOTAL_CERTS - EXPIRED_CERTS))

  echo -e "\n 📊 Statistics"
  echo -e "    Total certs: ${COLOR_YELLOW}$TOTAL_CERTS${CoR}"
  echo -e "    • ${COLOR_GREEN}Valid${CoR}    : ${COLOR_GREEN}$VALID_CERTS${CoR}"
  echo -e "    • ${COLOR_RED}Expired${CoR}  : ${COLOR_RED}$EXPIRED_CERTS${CoR}\n"
}

################################
# Function to download certificate as ZIP with fallback support
cert_download() {
  local cert_id="$1"
  local output_dir="${2:-./certificates}"
  local cert_name="${3:-certificate_$cert_id}"

  check_token_notverbose

  if [ -z "$cert_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: Certificate ID is required${CoR}"
    echo -e "    Usage: "
    echo -e "      ${COLOR_ORANGE}$0 --cert-download <cert_id> [output_dir] [cert_name]${CoR}"
    echo -e "      ${COLOR_ORANGE}$0 --cert-download 123 ./certs mydomain${CoR}\n"
    exit 1
  fi

  # Create output directory
  mkdir -p "$output_dir"

  echo -e "\n 🔒 Downloading certificate (ID: ${COLOR_YELLOW}$cert_id${CoR})"
  echo -e "    Output directory: ${COLOR_CYAN}$output_dir${CoR}"
  echo -e "    Certificate name: ${COLOR_CYAN}$cert_name${CoR}"

  # Get certificate metadata first
  local CERT_META
  CERT_META=$(curl -s -X GET "$BASE_URL/nginx/certificates/$cert_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ -z "$CERT_META" ] || ! echo "$CERT_META" | jq empty 2>/dev/null; then
    echo -e " ⛔ ${COLOR_RED}Error: Unable to retrieve certificate metadata${CoR}"
    exit 1
  fi

  # Check if certificate exists
  if echo "$CERT_META" | jq -e '.error' >/dev/null; then
    echo -e " ⛔ ${COLOR_RED}Certificate not found with ID: $cert_id${CoR}"
    exit 1
  fi

  # Extract certificate information
  local domain_names=$(echo "$CERT_META" | jq -r '.domain_names | join(", ")')
  local provider=$(echo "$CERT_META" | jq -r '.provider // "Unknown"')
  local expires_on=$(echo "$CERT_META" | jq -r '.expires_on // "N/A"')

  echo -e "    Domain(s): ${COLOR_YELLOW}$domain_names${CoR}"
  echo -e "    Provider: ${COLOR_YELLOW}$provider${CoR}"
  echo -e "    Expires: ${COLOR_YELLOW}$expires_on${CoR}"

  # Try new API first (JSON format)
  echo -e "\n 🔄 Trying new API format..."
  local CERT_CONTENT
  CERT_CONTENT=$(curl -s -X GET "$BASE_URL/nginx/certificates/$cert_id/certificates" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Accept: application/json")

  if [ -n "$CERT_CONTENT" ] && echo "$CERT_CONTENT" | jq empty 2>/dev/null; then
    # Check if we got valid certificate data
    local cert_data=$(echo "$CERT_CONTENT" | jq -r '.certificate // empty')
    local private_data=$(echo "$CERT_CONTENT" | jq -r '.private // empty')

    if [ -n "$cert_data" ] && [ -n "$private_data" ]; then
      echo -e " ✅ ${COLOR_GREEN}New API format successful${CoR}"

      # Save certificate files
      echo "$cert_data" >"$output_dir/${cert_name}.crt"
      echo "$private_data" >"$output_dir/${cert_name}.key"
      chmod 600 "$output_dir/${cert_name}.key"

      # Save intermediate certificate if available
      local intermediate_data=$(echo "$CERT_CONTENT" | jq -r '.intermediate // empty')
      if [ -n "$intermediate_data" ]; then
        echo "$intermediate_data" >"$output_dir/${cert_name}.chain.crt"
      fi

      # Save metadata
      echo "$CERT_META" | jq '.' >"$output_dir/${cert_name}_metadata.json"

      # Create ZIP file
      local zip_file="$output_dir/${cert_name}_certificate.zip"
      cd "$output_dir" || exit 1
      zip -q "$zip_file" "${cert_name}.crt" "${cert_name}.key" "${cert_name}_metadata.json"
      [ -f "${cert_name}.chain.crt" ] && zip -q "$zip_file" "${cert_name}.chain.crt"
      cd - >/dev/null || exit 1

      echo -e " ✅ ${COLOR_GREEN}Certificate downloaded successfully${CoR}"
      echo -e "    Files created:"
      echo -e "      • ${COLOR_CYAN}${cert_name}.crt${CoR} (Certificate)"
      echo -e "      • ${COLOR_CYAN}${cert_name}.key${CoR} (Private Key)"
      [ -f "$output_dir/${cert_name}.chain.crt" ] && echo -e "      • ${COLOR_CYAN}${cert_name}.chain.crt${CoR} (Chain)"
      echo -e "      • ${COLOR_CYAN}${cert_name}_metadata.json${CoR} (Metadata)"
      echo -e "      • ${COLOR_CYAN}${cert_name}_certificate.zip${CoR} (ZIP Archive)"

      return 0
    fi
  fi

  # Fallback to old API (ZIP download)
  echo -e " ⚠️ ${COLOR_YELLOW}New API failed, trying legacy ZIP download...${CoR}"

  local TMP_DIR=$(mktemp -d)
  local zip_file="$TMP_DIR/certificate.zip"

  # Download ZIP file
  local download_response
  download_response=$(curl -s -w "%{http_code}" -X GET "$BASE_URL/nginx/certificates/$cert_id/download" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -o "$zip_file")

  local http_code="${download_response: -3}"

  if [ "$http_code" = "200" ] && [ -f "$zip_file" ] && [ -s "$zip_file" ]; then
    echo -e " ✅ ${COLOR_GREEN}Legacy ZIP download successful${CoR}"

    # Extract ZIP file
    if command -v unzip >/dev/null 2>&1; then
      unzip -q "$zip_file" -d "$TMP_DIR"

      # Find certificate files with wildcards (supporting cert8.pem, cert9.pem, etc.)
      local cert_file=$(find "$TMP_DIR" -name "cert*.pem" | head -1)
      local key_file=$(find "$TMP_DIR" -name "privkey*.pem" | head -1)
      local chain_file=$(find "$TMP_DIR" -name "chain*.pem" | head -1)
      local fullchain_file=$(find "$TMP_DIR" -name "fullchain*.pem" | head -1)

      if [ -n "$cert_file" ] && [ -n "$key_file" ]; then
        # Copy files to output directory
        cp "$cert_file" "$output_dir/${cert_name}.crt"
        cp "$key_file" "$output_dir/${cert_name}.key"
        chmod 600 "$output_dir/${cert_name}.key"

        # Copy chain file if available
        if [ -n "$chain_file" ]; then
          cp "$chain_file" "$output_dir/${cert_name}.chain.crt"
        fi

        # Copy fullchain if available
        if [ -n "$fullchain_file" ]; then
          cp "$fullchain_file" "$output_dir/${cert_name}.fullchain.crt"
        fi

        # Save metadata
        echo "$CERT_META" | jq '.' >"$output_dir/${cert_name}_metadata.json"

        # Create new ZIP file with standardized names
        local final_zip="$output_dir/${cert_name}_certificate.zip"
        cd "$output_dir" || exit 1
        zip -q "$final_zip" "${cert_name}.crt" "${cert_name}.key" "${cert_name}_metadata.json"
        [ -f "${cert_name}.chain.crt" ] && zip -q "$final_zip" "${cert_name}.chain.crt"
        [ -f "${cert_name}.fullchain.crt" ] && zip -q "$final_zip" "${cert_name}.fullchain.crt"
        cd - >/dev/null || exit 1

        echo -e " ✅ ${COLOR_GREEN}Certificate downloaded successfully (legacy method)${CoR}"
        echo -e "    Files created:"
        echo -e "      • ${COLOR_CYAN}${cert_name}.crt${CoR} (Certificate)"
        echo -e "      • ${COLOR_CYAN}${cert_name}.key${CoR} (Private Key)"
        [ -f "$output_dir/${cert_name}.chain.crt" ] && echo -e "      • ${COLOR_CYAN}${cert_name}.chain.crt${CoR} (Chain)"
        [ -f "$output_dir/${cert_name}.fullchain.crt" ] && echo -e "      • ${COLOR_CYAN}${cert_name}.fullchain.crt${CoR} (Full Chain)"
        echo -e "      • ${COLOR_CYAN}${cert_name}_metadata.json${CoR} (Metadata)"
        echo -e "      • ${COLOR_CYAN}${cert_name}_certificate.zip${CoR} (ZIP Archive)"

        # Cleanup
        rm -rf "$TMP_DIR"
        return 0
      else
        echo -e " ⛔ ${COLOR_RED}Error: Could not find certificate files in ZIP${CoR}"
      fi
    else
      echo -e " ⛔ ${COLOR_RED}Error: unzip command not found${CoR}"
    fi
  else
    echo -e " ⛔ ${COLOR_RED}Error: Failed to download certificate ZIP (HTTP $http_code)${CoR}"
  fi

  # Cleanup on failure
  rm -rf "$TMP_DIR"
  echo -e " ⛔ ${COLOR_RED}Certificate download failed${CoR}"
  exit 1
}

# Verify Cloudflare API Key validity
verify_cloudflare_api_key() {
  local api_key="$1"
  local email="$2"

  echo -e " 🔍 Verifying Cloudflare API Key..."

  # Test API call to Cloudflare
  local response=$(curl -s -X GET "https://api.cloudflare.com/client/v4/user" \
    -H "X-Auth-Email: $email" \
    -H "X-Auth-Key: $api_key" \
    -H "Content-Type: application/json")

  # Check if the API call was successful
  if [ "$(echo "$response" | jq -r '.success')" = "true" ]; then
    local username=$(echo "$response" | jq -r '.result.username')
    echo -e " ✅ ${COLOR_GREEN}Cloudflare API Key is valid${CoR}"
    echo -e " 👤 Connected as: ${COLOR_CYAN}$username${CoR}"
    return 0
  else
    local error_msg=$(echo "$response" | jq -r '.errors[0].message')
    echo -e " ❌ ${COLOR_RED}Invalid Cloudflare API Key${CoR}"
    echo -e " ⛔ Error: $error_msg"
    return 1
  fi
}

###############################
# Create or update a proxy host based on the existence of the domain
create_or_update_proxy_host() {
  # Add static variable to track execution
  if [ "${FUNCTION_CALLED:-0}" -eq 1 ]; then
    return 0
  fi
  FUNCTION_CALLED=1

  # Check for wildcard domains in host creation
  if [[ "$DOMAIN_NAMES" == \** ]]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: Wildcard domains (*.domain.com) are not allowed for host creation${CoR}"
    echo -e " Wildcards are only supported for SSL certificates"
    exit 1
  fi

  check_token_notverbose
  # Check if the host already exists
  #echo -e "\n 🔎 Checking if the host ${COLOR_RED}$DOMAIN_NAMES${CoR} already exists..."
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  EXISTING_HOST=$(echo "$RESPONSE" | jq -r --arg DOMAIN "$DOMAIN_NAMES" '.[] | select(.domain_names[] == $DOMAIN)')
  HOST_ID=$(echo "$EXISTING_HOST" | jq -r '.id // empty')

  # Prepare JSON data for API
  if [[ -z "$CUSTOM_LOCATIONS" || "$CUSTOM_LOCATIONS" == "null" ]]; then
    CUSTOM_LOCATIONS_ESCAPED="[]"
  else
    CUSTOM_LOCATIONS_ESCAPED=$(echo "$CUSTOM_LOCATIONS" | jq -c . 2>/dev/null || echo '[]')
  fi

  # Convert boolean to JSON
  CACHING_ENABLED_JSON=$([ "$CACHING_ENABLED" == "true" ] && echo true || echo false)
  BLOCK_EXPLOITS_JSON=$([ "$BLOCK_EXPLOITS" == "true" ] && echo true || echo false)
  ALLOW_WEBSOCKET_UPGRADE_JSON=$([ "$ALLOW_WEBSOCKET_UPGRADE" == "true" ] && echo true || echo false)
  HTTP2_SUPPORT_JSON=$([ "$HTTP2_SUPPORT" == "true" ] && echo true || echo false)

  # Generate JSON
  DATA=$(jq -n \
    --arg domain "$DOMAIN_NAMES" \
    --arg host "$FORWARD_HOST" \
    --arg port "$FORWARD_PORT" \
    --arg scheme "$FORWARD_SCHEME" \
    --argjson caching "$CACHING_ENABLED_JSON" \
    --argjson block_exploits "$BLOCK_EXPLOITS_JSON" \
    --arg advanced_config "$ADVANCED_CONFIG" \
    --argjson websocket_upgrade "$ALLOW_WEBSOCKET_UPGRADE_JSON" \
    --argjson http2_support "$HTTP2_SUPPORT_JSON" \
    --argjson enabled true \
    --argjson locations "$CUSTOM_LOCATIONS_ESCAPED" \
    '{
            domain_names: [$domain],
            forward_host: $host,
            forward_port: ($port | tonumber),
            access_list_id: null,
            certificate_id: null,
            ssl_forced: false,
            caching_enabled: $caching,
            block_exploits: $block_exploits,
            advanced_config: $advanced_config,
            meta: { dns_challenge: null },
            allow_websocket_upgrade: $websocket_upgrade,
            http2_support: $http2_support,
            forward_scheme: $scheme,
            enabled: $enabled,
            locations: $locations
        }')

  # Check if the JSON is valid
  if ! echo "$DATA" | jq empty >/dev/null 2>&1; then
    echo -e " ${COLOR_RED}⛔ ERROR: Invalid JSON generated:\n$DATA${CoR}"
    exit 1
  fi

  if [ -n "$HOST_ID" ]; then
    # Update existing HOST
    #echo -e "\n ${COLOR_CYAN}🔄${CoR} Updating the proxy host for ${COLOR_GREEN}$DOMAIN_NAMES${CoR}"
    if [ "$AUTO_YES" != "true" ]; then
      echo -e " ${COLOR_YELLOW}👉 Do you want to update this host ${CoR} $DOMAIN_NAMES ${COLOR_YELLOW}?${CoR}"
      read -n 1 -r -p "   (y/n):  " answer
      echo
      if [[ ! $answer =~ ^[Yy]$ ]]; then
        echo -e " ${COLOR_YELLOW}🚫 No changes made.${CoR}\n"
        return 0
      fi
    fi
    echo -e "${CoR}"
    METHOD="PUT"
    URL="$BASE_URL/nginx/proxy-hosts/$HOST_ID"
  else
    # Create NEW HOST
    echo -e "\n ${COLOR_CYAN}🌍${CoR} Creating a new proxy host: ${COLOR_GREEN}$DOMAIN_NAMES${CoR}"
    METHOD="POST"
    URL="$BASE_URL/nginx/proxy-hosts"
  fi

  # Send API request
  RESPONSE=$(curl -s -X "$METHOD" "$URL" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$DATA")

  # Check API response
  ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
  if [ -z "$ERROR_MSG" ]; then
    PROXY_ID=$(echo "$RESPONSE" | jq -r '.id // "unknown"')

    # If certificate generation is requested
    if [ "$CERT_GENERATE" = true ]; then
      #echo -e " ${COLOR_YELLOW}🔐 Generate SSL certificate CREATE_OR_${CoR}"

      # Check if it's a wildcard certificate (the host itself can't be a wildcard)
      if [[ "$CERT_DOMAIN" == \** ]]; then
        # Use --dns-provider / --dns-credentials, prompt only when missing
        if [ -z "$CERT_DNS_PROVIDER" ] || [ -z "$CERT_DNS_CREDENTIALS" ]; then
          echo -e " ⚠️ ${COLOR_YELLOW}Wildcard certificate requires DNS challenge${CoR}"
          if [ "$AUTO_YES" = true ]; then
            echo -e " ⛔ ${COLOR_RED}Missing --dns-provider / --dns-credentials${CoR}\n"
            exit 1
          fi
          echo -e " 👉 Please provide DNS provider and credentials:"
          [ -z "$CERT_DNS_PROVIDER" ] && read -r -p "    DNS Provider (cloudflare, dynu, etc.): " CERT_DNS_PROVIDER
          [ -z "$CERT_DNS_CREDENTIALS" ] && read -r -p "    DNS Credentials (JSON): " CERT_DNS_CREDENTIALS
        fi

        # Verify Cloudflare Global API key if provided (API tokens are not checked)
        local cf_key cf_email
        cf_key=$(echo "$CERT_DNS_CREDENTIALS" | jq -r '.dns_cloudflare_api_key // empty' 2>/dev/null || true)
        cf_email=$(echo "$CERT_DNS_CREDENTIALS" | jq -r '.dns_cloudflare_email // empty' 2>/dev/null || true)
        cf_email=${cf_email:-$CERT_EMAIL}
        if [[ "${CERT_DNS_PROVIDER,,}" == "cloudflare" ]] && [[ "$cf_key" =~ ^[0-9a-fA-F]{37}$ ]]; then
          if ! verify_cloudflare_api_key "$cf_key" "$cf_email"; then
            echo -e " ⛔ ${COLOR_RED}Cannot proceed with invalid Cloudflare API Key${CoR}"
            return 1
          fi

          # Verify domain is managed by Cloudflare
          local domain=${CERT_DOMAIN#\*.}
          local zone_check=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=$domain" \
            -H "X-Auth-Email: $cf_email" \
            -H "X-Auth-Key: $cf_key" \
            -H "Content-Type: application/json")

          if [ "$(echo "$zone_check" | jq -r '.result | length')" -eq 0 ]; then
            echo -e " ⛔ ${COLOR_RED}Domain $domain is not managed by Cloudflare${CoR}"
            echo -e " 👉 Please make sure your domain is added to your Cloudflare account"
            return 1
          fi

          echo -e " ✅ ${COLOR_GREEN}Domain verification successful${CoR}"
        fi
      fi
      # Generate the certificate
      cert_generate "$CERT_DOMAIN" "$CERT_EMAIL" "$CERT_DNS_PROVIDER" "$CERT_DNS_CREDENTIALS"

      # Check SSL creation
      CERT_CHECK=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

      CERT_ID=$(echo "$CERT_CHECK" | jq -r --arg domain "$CERT_DOMAIN" \
        '.[] | select(.domain_names[] == $domain) | .id' | sort -n | tail -n1)

      if [ -n "$CERT_ID" ]; then
        #echo -e "\n ${COLOR_YELLOW}✨ Automatic SSL Activation${CoR} $CERT_DOMAIN "

        # update certificat with HOST ID
        UPDATE_DATA=$(jq -n \
          --arg cert_id "$CERT_ID" \
          '{
                        certificate_id: $cert_id,
                        ssl_forced: true,
                        http2_support: true,
                        hsts_enabled: false,
                        hsts_subdomains: false,
                        enabled: true
                    }')

        UPDATE_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X PUT \
          "$BASE_URL/nginx/proxy-hosts/$PROXY_ID" \
          -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
          -H "Content-Type: application/json" \
          --data "$UPDATE_DATA")

        UPDATE_STATUS=${UPDATE_RESPONSE##*HTTPSTATUS:}

        # Check if successfull
        if [ "$UPDATE_STATUS" -eq 200 ]; then
          echo -e "\n ✅ ${COLOR_GREEN}SSL Configuration Complete ${CoR}🎉"
          echo -e " 📋 CHECK  SSL Status for ${COLOR_GREEN}$DOMAIN_NAMES${CoR}:"
          echo -e "    ├─ 🔒 SSL: ${COLOR_GREEN}Enabled${CoR}"
          echo -e "    ├─ 📜 Certificate ID: $CERT_ID"
          echo -e "    ├─ 🚀 HTTP/2: ${COLOR_GREEN}Active${CoR}"
          echo -e "    ├─ 🛡️ HSTS: ${COLOR_RED}Disabled${CoR}"
          echo -e "    └─ 🌐 HSTS Subdomains: ${COLOR_RED}Disabled${CoR}\n"
          exit 0
        else
          echo -e " ⛔ ${COLOR_RED}Failed to enable SSL. Status code: $UPDATE_STATUS${CoR}\n"
          exit 1
        fi
      else
        echo -e " ⛔ ${COLOR_RED}Certificate not found after generation${CoR}\n"
        exit 1
      fi
    fi

    if [ "$METHOD" = "PUT" ]; then
      echo -e " ✅ ${COLOR_GREEN}Proxy host 🔗$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$PROXY_ID${COLOR_GREEN}) OK${CoR}\n"
    else
      echo -e " ✅ ${COLOR_GREEN}Proxy host 🔗$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$PROXY_ID${COLOR_GREEN}) created successfully! 🎉${CoR}\n"
    fi
  else
    echo -e " ⛔ ${COLOR_RED}Operation failed. Error: $ERROR_MSG${CoR}\n"
    exit 1
  fi
}

# List all proxy hosts with basic details, including SSL certificate status and associated domain
host_list() {
  check_token_notverbose
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$JSON_OUTPUT" = true ]; then
    echo "$RESPONSE" | jq .
    exit 0
  fi

  echo -e "\n${COLOR_ORANGE} 👉 List of proxy hosts ${CoR}\n"
  printf "  %4s %-36s %-9s %-6s %-30s %-36s\n" "ID" " DOMAIN" " STATUS" " SSL" " TARGET" " CERT DOMAIN"

  # Clean the response to remove control characters
  CLEANED_RESPONSE=$(echo "$RESPONSE" | tr -d '\000-\031')

  # Fetch all certificates once and build an "id -> domain1, domain2" map, so we
  # don't make one API call per proxy host to resolve the CERT DOMAIN column.
  ALL_CERTS=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  declare -A CERT_DOMAINS=()
  while IFS=$'\t' read -r _cid _cdoms; do
    [ -n "$_cid" ] && CERT_DOMAINS["$_cid"]="$_cdoms"
  done < <(echo "$ALL_CERTS" | jq -r '.[]? | select(.domain_names != null) | "\(.id)\t\(.domain_names | join(", "))"')

  # Fix PR #28: Use tab delimiter to safely handle multiple domain names
  # Fix PR #29: Extract forward_host, forward_port, forward_scheme for TARGET column
  echo "$CLEANED_RESPONSE" | jq -r '.[] | "\(.id)\t\(.domain_names | join(", "))\t\(.enabled)\t\(.certificate_id)\t\(.forward_scheme)\t\(.forward_host)\t\(.forward_port)"' | while IFS=$'\t' read -r id domain enabled certificate_id forward_scheme forward_host forward_port; do
    if [ "$enabled" = "true" ]; then
      status="$(echo -e "${WHITE_ON_GREEN} enabled ${CoR}")"
    else
      status="$(echo -e "${COLOR_RED} disable ${CoR}")"
    fi
    # Default SSL status
    ssl_status="$(pad "✘" 6)"
    ssl_color="${COLOR_RED}"
    cert_domain=""
    # Resolve the certificate domain from the prefetched map (no per-host call)
    if [ "$certificate_id" != "null" ] && [ -n "$certificate_id" ]; then
      cert_domain="${CERT_DOMAINS[$certificate_id]:-}"
      if [ -n "$cert_domain" ]; then
        ssl_status="$(pad "$certificate_id" 6)"
        ssl_color="${COLOR_CYAN}"
      fi
    fi

    # Build TARGET column (PR #29): scheme://host:port
    if [ -n "$forward_host" ] && [ "$forward_host" != "null" ] && [ -n "$forward_port" ] && [ "$forward_port" != "null" ]; then
      target="${forward_scheme:-http}://${forward_host}:${forward_port}"
    else
      target="N/A"
    fi

    # Split the domain list: the first domain goes on the main row, any extra
    # domains are printed below, indented under the DOMAIN column. This keeps
    # all columns aligned even with long or multiple domain names.
    IFS=', ' read -ra domain_arr <<<"$domain"
    primary_domain="${domain_arr[0]}"

    # Print the row with colors, TARGET column, and certificate domain (if available)
    printf "  ${COLOR_YELLOW}%4s${CoR}  ${COLOR_GREEN}%s${CoR} %-9s ${ssl_color}%-6s${CoR} ${COLOR_CYAN}%s${CoR} ${COLOR_CYAN}%s${CoR}\n" \
      "$id" "$(truncate_pad "$primary_domain" 36)" "$status" "$ssl_status" "$(truncate_pad "$target" 30)" "$cert_domain"

    # Continuation lines for the remaining domains (indented under DOMAIN, col 8)
    for ((i = 1; i < ${#domain_arr[@]}; i++)); do
      printf "        ${COLOR_GREEN}%s${CoR}\n" "$(truncate_pad "${domain_arr[i]}" 36)"
    done
  done
  echo ""
  exit 0
}

################################
# List all proxy hosts with full details
host_list_full() {
  check_token_notverbose
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  echo "$RESPONSE" | jq -c '.[]' | while read -r proxy; do
    echo "$proxy" | jq .
  done
  echo ""
  exit 0
}

################################
# List all redirection hosts
redirect_host_list() {
  check_token_notverbose
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/redirection-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$JSON_OUTPUT" = true ]; then
    echo "$RESPONSE" | jq .
    exit 0
  fi

  echo -e "\n${COLOR_ORANGE} 👉 List of Redirection hosts ${CoR}\n"
  printf "  %4s %-36s %-9s %-7s %-7s %-36s\n" "ID" " DOMAIN" " STATUS" " CODE" " SSL" " FORWARD DOMAIN"

  CLEANED_RESPONSE=$(echo "$RESPONSE" | tr -d '\000-\031')

  echo "$CLEANED_RESPONSE" | jq -r '.[] | "\(.id)\t\(.domain_names | join(", "))\t\(.enabled)\t\(.forward_http_code)\t\(.certificate_id)\t\(.forward_domain_name)"' |
    while IFS=$'\t' read -r id domain enabled http_code certificate_id forward_domain; do
      if [ "$enabled" = "true" ]; then
        status="$(echo -e "${WHITE_ON_GREEN} enabled ${CoR}")"
      else
        status="$(echo -e "${COLOR_RED} disable ${CoR}")"
      fi
      ssl_status="$(pad "✘" 7)"
      ssl_color="${COLOR_RED}"
      if [ "$certificate_id" != "null" ] && [ -n "$certificate_id" ]; then
        ssl_status="$(pad "$certificate_id" 7)"
        ssl_color="${COLOR_CYAN}"
      fi

      # Split the domain list: the first domain goes on the main row, any extra
      # domains are printed below, indented under the DOMAIN column. Keeps all
      # columns aligned even with long or multiple domains (same as host_list).
      IFS=', ' read -ra domain_arr <<<"$domain"
      primary_domain="${domain_arr[0]}"

      printf "  ${COLOR_YELLOW}%4s${CoR}  ${COLOR_GREEN}%s${CoR} %-9s ${COLOR_CYAN}%-7s${CoR} ${ssl_color}%-7s${CoR} ${COLOR_CYAN}%s${CoR}\n" \
        "$id" "$(truncate_pad "$primary_domain" 36)" "$status" "$http_code" "$ssl_status" "$(truncate_pad "$forward_domain" 36)"

      # Continuation lines for the remaining domains (indented under DOMAIN, col 8)
      for ((i = 1; i < ${#domain_arr[@]}; i++)); do
        printf "        ${COLOR_GREEN}%s${CoR}\n" "$(truncate_pad "${domain_arr[i]}" 36)"
      done
    done
  echo ""
  exit 0
}

################################
# Create or Update a redirection host
# Reads globals: DOMAIN_NAMES, FORWARD_DOMAIN, FORWARD_SCHEME, FORWARD_HTTP_CODE,
#                PRESERVE_PATH, BLOCK_EXPLOITS, ADVANCED_CONFIG, AUTO_YES
create_or_update_redirect_host() {
  if [ "${REDIRECT_FUNCTION_CALLED:-0}" -eq 1 ]; then
    return 0
  fi
  REDIRECT_FUNCTION_CALLED=1

  if [ -z "$DOMAIN_NAMES" ] || [ -z "$FORWARD_DOMAIN" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: Missing required parameters (domain, forward domain).${CoR}"
    echo -e "   Usage: ${COLOR_ORANGE}$0 --redirect-host-create domain.com --forward-domain target.com${CoR}"
    exit 1
  fi

  # Validate HTTP code
  if ! [[ "$FORWARD_HTTP_CODE" =~ ^(301|302|303|307|308)$ ]]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: Invalid HTTP code '$FORWARD_HTTP_CODE'. Must be 301, 302, 303, 307, or 308.${CoR}"
    exit 1
  fi

  # Validate forward scheme
  if ! [[ "$FORWARD_SCHEME" =~ ^(http|https)$ ]]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: Invalid forward scheme '$FORWARD_SCHEME'. Must be 'http' or 'https'.${CoR}"
    exit 1
  fi

  check_token_notverbose

  # Check if a redirect host for this domain already exists
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/redirection-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  EXISTING=$(echo "$RESPONSE" | jq -r --arg DOMAIN "$DOMAIN_NAMES" '.[] | select(.domain_names[] == $DOMAIN)')
  REDIRECT_ID=$(echo "$EXISTING" | jq -r '.id // empty')

  # Convert booleans to JSON
  PRESERVE_PATH_JSON=$([ "$PRESERVE_PATH" == "true" ] && echo true || echo false)
  BLOCK_EXPLOITS_JSON=$([ "$BLOCK_EXPLOITS" == "true" ] && echo true || echo false)

  DATA=$(jq -n \
    --arg domain "$DOMAIN_NAMES" \
    --arg forward_scheme "$FORWARD_SCHEME" \
    --argjson forward_http_code "$FORWARD_HTTP_CODE" \
    --arg forward_domain_name "$FORWARD_DOMAIN" \
    --argjson preserve_path "$PRESERVE_PATH_JSON" \
    --argjson block_exploits "$BLOCK_EXPLOITS_JSON" \
    --arg advanced_config "$ADVANCED_CONFIG" \
    '{
            domain_names: [$domain],
            forward_scheme: $forward_scheme,
            forward_http_code: $forward_http_code,
            forward_domain_name: $forward_domain_name,
            preserve_path: $preserve_path,
            block_exploits: $block_exploits,
            advanced_config: $advanced_config,
            meta: {}
        }')

  if ! echo "$DATA" | jq empty >/dev/null 2>&1; then
    echo -e " ${COLOR_RED}⛔ ERROR: Invalid JSON generated:\n$DATA${CoR}"
    exit 1
  fi

  if [ -n "$REDIRECT_ID" ]; then
    if [ "$AUTO_YES" != "true" ]; then
      echo -e " ${COLOR_YELLOW}👉 Do you want to update this redirect host ${CoR} $DOMAIN_NAMES ${COLOR_YELLOW}?${CoR}"
      read -n 1 -r -p "   (y/n):  " answer
      echo
      if [[ ! $answer =~ ^[Yy]$ ]]; then
        echo -e " ${COLOR_YELLOW}🚫 No changes made.${CoR}\n"
        return 0
      fi
    fi
    echo -e "\n ${COLOR_CYAN}🔄${CoR} Updating redirect host: ${COLOR_GREEN}$DOMAIN_NAMES${CoR}"
    METHOD="PUT"
    URL="$BASE_URL/nginx/redirection-hosts/$REDIRECT_ID"
  else
    echo -e "\n ${COLOR_CYAN}🔀${CoR} Creating redirect host: ${COLOR_GREEN}$DOMAIN_NAMES${CoR} → ${COLOR_YELLOW}$FORWARD_DOMAIN${CoR}"
    METHOD="POST"
    URL="$BASE_URL/nginx/redirection-hosts"
  fi

  RESPONSE=$(curl -s -X "$METHOD" "$URL" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$DATA")

  ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
  if [ -z "$ERROR_MSG" ]; then
    RID=$(echo "$RESPONSE" | jq -r '.id // "unknown"')
    if [ "$METHOD" = "PUT" ]; then
      echo -e " ✅ ${COLOR_GREEN}Redirect host 🔗$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$RID${COLOR_GREEN}) updated successfully! 🎉${CoR}\n"
    else
      echo -e " ✅ ${COLOR_GREEN}Redirect host 🔗$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$RID${COLOR_GREEN}) created successfully! 🎉${CoR}\n"
    fi
  else
    echo -e " ⛔ ${COLOR_RED}Operation failed. Error: $ERROR_MSG${CoR}\n"
    exit 1
  fi
}

################################
# Delete a redirection host by ID
redirect_host_delete() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --redirect-host-delete option requires a host 🆔.${CoR}"
    echo -e "   Usage  : ${COLOR_ORANGE}$0 --redirect-host-delete <id>${CoR}"
    echo -e "   Example: ${COLOR_GREEN}$0 --redirect-host-delete 5${CoR}"
    exit 1
  fi

  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" \
    "$BASE_URL/nginx/redirection-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" 2>/dev/null)

  CHECK_BODY=${CHECK_RESPONSE//HTTPSTATUS:*/}
  CHECK_STATUS=${CHECK_RESPONSE##*HTTPSTATUS:}

  if [ "$CHECK_STATUS" -eq 404 ]; then
    echo -e " ⛔ ${COLOR_RED}ERROR: Redirect host ID ${COLOR_YELLOW}$host_id${COLOR_RED} not found!${CoR}"
    exit 1
  elif [ "$CHECK_STATUS" -ne 200 ]; then
    echo -e " ⛔ ${COLOR_RED}ERROR: Failed to check redirect host. Status: $CHECK_STATUS${CoR}"
    exit 1
  fi

  DOMAIN_NAME=$(echo "$CHECK_BODY" | jq -r '.domain_names[0] // "unknown"')

  if [ "$AUTO_YES" != true ]; then
    echo -e " ┌───────────────────────────────────────────"
    echo -e " │ ID: ${COLOR_YELLOW}$host_id${CoR}"
    echo -e " │ Domain: ${COLOR_GREEN}$DOMAIN_NAME${CoR}"
    echo -e " └───────────────────────────────────────────"
    echo -e " ⚠️  ${COLOR_RED}WARNING: This action cannot be undone!${CoR}"
    read -n 1 -r -p " 🔔 Confirm deletion? (y/n): " CONFIRM
    echo
    if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
      echo -e " ❌ ${COLOR_RED}Operation cancelled${CoR}"
      exit 1
    fi
  else
    echo -e "\n ${COLOR_YELLOW}🔔 -y Auto-confirming deletion${CoR}"
  fi

  echo -e " 🗑️ Deleting redirect host ${COLOR_GREEN}$DOMAIN_NAME${CoR} (ID: ${COLOR_GREEN}$host_id${CoR})..."

  RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE \
    "$BASE_URL/nginx/redirection-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" 2>/dev/null)

  HTTP_STATUS=${RESPONSE##*HTTPSTATUS:}

  if [ "${HTTP_STATUS:-0}" -eq 200 ]; then
    echo -e " ✅ ${COLOR_GREEN}Redirect host ${COLOR_YELLOW}$DOMAIN_NAME${CoR} (ID: $host_id) deleted successfully!${CoR}\n"
    exit 0
  else
    echo -e " ⛔ ${COLOR_RED}Failed to delete redirect host. Status: $HTTP_STATUS${CoR}"
    exit 1
  fi
}

################################
# Enable a redirection host by ID
redirect_host_enable() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --redirect-host-enable option requires a host 🆔.${CoR}"
    echo -e "   Usage  : ${COLOR_ORANGE}$0 --redirect-host-enable <id>${CoR}"
    echo -e "   Example: ${COLOR_GREEN}$0 --redirect-host-enable 5${CoR}"
    return 1
  fi

  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/redirection-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if echo "$CHECK_RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ⛔ ${COLOR_RED}Redirect host with ID $host_id does not exist${CoR}"
    return 1
  fi

  DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')
  echo -e "\n ${COLOR_YELLOW}🔄 Enabling redirect host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"

  RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/redirection-hosts/$host_id/enable" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8")

  if ! echo "$RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ✅ ${COLOR_GREEN}Successfully enabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
  else
    ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
    echo -e " ⛔ ${COLOR_RED}Failed to enable redirect host: $ERROR_MSG${CoR}"
    return 1
  fi
}

################################
# Disable a redirection host by ID
redirect_host_disable() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --redirect-host-disable option requires a host 🆔.${CoR}"
    echo -e "   Usage  : ${COLOR_ORANGE}$0 --redirect-host-disable <id>${CoR}"
    echo -e "   Example: ${COLOR_GREEN}$0 --redirect-host-disable 5${CoR}"
    return 1
  fi

  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/redirection-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if echo "$CHECK_RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ⛔ ${COLOR_RED}Redirect host with ID $host_id does not exist${CoR}"
    return 1
  fi

  DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')
  echo -e "\n ${COLOR_YELLOW}🔄 Disabling redirect host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"

  RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/redirection-hosts/$host_id/disable" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8")

  if ! echo "$RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ✅ ${COLOR_GREEN}Successfully disabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
  else
    ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
    echo -e " ⛔ ${COLOR_RED}Failed to disable redirect host: $ERROR_MSG${CoR}"
    return 1
  fi
}

################################
# List all stream hosts (TCP/UDP forwarding)
stream_host_list() {
  check_token_notverbose
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/streams" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$JSON_OUTPUT" = true ]; then
    echo "$RESPONSE" | jq .
    exit 0
  fi

  echo -e "\n${COLOR_ORANGE} 👉 List of Stream hosts ${CoR}\n"
  printf "  %4s %-8s %-9s %-4s %-4s %-36s\n" "ID" " PORT" " STATUS" " TCP" " UDP" " FORWARD HOST:PORT"

  CLEANED_RESPONSE=$(echo "$RESPONSE" | tr -d '\000-\031')

  echo "$CLEANED_RESPONSE" | jq -r '.[] | "\(.id)\t\(.incoming_port)\t\(.enabled)\t\(.tcp_forwarding)\t\(.udp_forwarding)\t\(.forwarding_host):\(.forwarding_port)"' |
    while IFS=$'\t' read -r id port enabled tcp udp forward; do
      if [ "$enabled" = "true" ]; then
        status="$(echo -e "${WHITE_ON_GREEN} enabled ${CoR}")"
      else
        status="$(echo -e "${COLOR_RED} disable ${CoR}")"
      fi
      tcp_flag="✘"
      [ "$tcp" = "true" ] && tcp_flag="✔"
      udp_flag="✘"
      [ "$udp" = "true" ] && udp_flag="✔"

      printf "  ${COLOR_YELLOW}%4s${CoR}  ${COLOR_GREEN}%-7s${CoR} %-9s ${COLOR_CYAN}%-4s${CoR} ${COLOR_CYAN}%-4s${CoR} ${COLOR_CYAN}%s${CoR}\n" \
        "$id" "$port" "$status" "$tcp_flag" "$udp_flag" "$(truncate_pad "$forward" 36)"
    done
  echo ""
  exit 0
}

################################
# Create or Update a stream host
# Reads globals: INCOMING_PORT, FORWARD_HOST, FORWARD_PORT, TCP_FORWARDING,
#                UDP_FORWARDING, CERT_ID, AUTO_YES
create_or_update_stream_host() {
  if [ -z "$INCOMING_PORT" ] || [ -z "$FORWARD_HOST" ] || [ -z "$FORWARD_PORT" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: Missing required parameters (incoming port, forward host, forward port).${CoR}"
    echo -e "   Usage: ${COLOR_ORANGE}$0 --stream-host-create <incoming_port> --forward-host <host> --forward-port <port> [--tcp] [--udp]${CoR}"
    exit 1
  fi

  if [ "$TCP_FORWARDING" != "true" ] && [ "$UDP_FORWARDING" != "true" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: At least one of --tcp or --udp must be enabled.${CoR}"
    exit 1
  fi

  check_token_notverbose

  # Check if a stream host for this incoming port already exists
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/streams" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  EXISTING=$(echo "$RESPONSE" | jq -r --argjson PORT "$INCOMING_PORT" '.[] | select(.incoming_port == $PORT)')
  STREAM_ID=$(echo "$EXISTING" | jq -r '.id // empty')

  DATA=$(jq -n \
    --argjson incoming_port "$INCOMING_PORT" \
    --arg forwarding_host "$FORWARD_HOST" \
    --argjson forwarding_port "$FORWARD_PORT" \
    --argjson tcp_forwarding "$TCP_FORWARDING" \
    --argjson udp_forwarding "$UDP_FORWARDING" \
    --argjson certificate_id "${CERT_ID:-0}" \
    '{
            incoming_port: $incoming_port,
            forwarding_host: $forwarding_host,
            forwarding_port: $forwarding_port,
            tcp_forwarding: $tcp_forwarding,
            udp_forwarding: $udp_forwarding,
            certificate_id: $certificate_id,
            meta: {}
        }')

  if ! echo "$DATA" | jq empty >/dev/null 2>&1; then
    echo -e " ${COLOR_RED}⛔ ERROR: Invalid JSON generated:\n$DATA${CoR}"
    exit 1
  fi

  if [ -n "$STREAM_ID" ]; then
    if [ "$AUTO_YES" != "true" ]; then
      echo -e " ${COLOR_YELLOW}👉 Do you want to update this stream host ${CoR} port $INCOMING_PORT ${COLOR_YELLOW}?${CoR}"
      read -n 1 -r -p "   (y/n):  " answer
      echo
      if [[ ! $answer =~ ^[Yy]$ ]]; then
        echo -e " ${COLOR_YELLOW}🚫 No changes made.${CoR}\n"
        return 0
      fi
    fi
    echo -e "\n ${COLOR_CYAN}🔄${CoR} Updating stream host: ${COLOR_GREEN}port $INCOMING_PORT${CoR}"
    METHOD="PUT"
    URL="$BASE_URL/nginx/streams/$STREAM_ID"
  else
    echo -e "\n ${COLOR_CYAN}🔌${CoR} Creating stream host: ${COLOR_GREEN}port $INCOMING_PORT${CoR} → ${COLOR_YELLOW}$FORWARD_HOST:$FORWARD_PORT${CoR}"
    METHOD="POST"
    URL="$BASE_URL/nginx/streams"
  fi

  RESPONSE=$(curl -s -X "$METHOD" "$URL" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$DATA")

  ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
  if [ -z "$ERROR_MSG" ]; then
    RID=$(echo "$RESPONSE" | jq -r '.id // "unknown"')
    if [ "$METHOD" = "PUT" ]; then
      echo -e " ✅ ${COLOR_GREEN}Stream host 🔌port $INCOMING_PORT (ID: ${COLOR_YELLOW}$RID${COLOR_GREEN}) updated successfully! 🎉${CoR}\n"
    else
      echo -e " ✅ ${COLOR_GREEN}Stream host 🔌port $INCOMING_PORT (ID: ${COLOR_YELLOW}$RID${COLOR_GREEN}) created successfully! 🎉${CoR}\n"
    fi
  else
    echo -e " ⛔ ${COLOR_RED}Operation failed. Error: $ERROR_MSG${CoR}\n"
    exit 1
  fi
}

################################
# Delete a stream host by ID
stream_host_delete() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --stream-host-delete option requires a host 🆔.${CoR}"
    echo -e "   Usage  : ${COLOR_ORANGE}$0 --stream-host-delete <id>${CoR}"
    echo -e "   Example: ${COLOR_GREEN}$0 --stream-host-delete 5${CoR}"
    exit 1
  fi

  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" \
    "$BASE_URL/nginx/streams/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" 2>/dev/null)

  CHECK_BODY=${CHECK_RESPONSE//HTTPSTATUS:*/}
  CHECK_STATUS=${CHECK_RESPONSE##*HTTPSTATUS:}

  if [ "$CHECK_STATUS" -eq 404 ]; then
    echo -e " ⛔ ${COLOR_RED}ERROR: Stream host ID ${COLOR_YELLOW}$host_id${COLOR_RED} not found!${CoR}"
    exit 1
  elif [ "$CHECK_STATUS" -ne 200 ]; then
    echo -e " ⛔ ${COLOR_RED}ERROR: Failed to check stream host. Status: $CHECK_STATUS${CoR}"
    exit 1
  fi

  STREAM_PORT=$(echo "$CHECK_BODY" | jq -r '.incoming_port // "unknown"')

  if [ "$AUTO_YES" != true ]; then
    echo -e " ┌───────────────────────────────────────────"
    echo -e " │ ID: ${COLOR_YELLOW}$host_id${CoR}"
    echo -e " │ Port: ${COLOR_GREEN}$STREAM_PORT${CoR}"
    echo -e " └───────────────────────────────────────────"
    echo -e " ⚠️  ${COLOR_RED}WARNING: This action cannot be undone!${CoR}"
    read -n 1 -r -p " 🔔 Confirm deletion? (y/n): " CONFIRM
    echo
    if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
      echo -e " ❌ ${COLOR_RED}Operation cancelled${CoR}"
      exit 1
    fi
  else
    echo -e "\n ${COLOR_YELLOW}🔔 -y Auto-confirming deletion${CoR}"
  fi

  echo -e " 🗑️ Deleting stream host ${COLOR_GREEN}port $STREAM_PORT${CoR} (ID: ${COLOR_GREEN}$host_id${CoR})..."

  RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE \
    "$BASE_URL/nginx/streams/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" 2>/dev/null)

  HTTP_STATUS=${RESPONSE##*HTTPSTATUS:}

  if [ "${HTTP_STATUS:-0}" -eq 200 ]; then
    echo -e " ✅ ${COLOR_GREEN}Stream host ${COLOR_YELLOW}port $STREAM_PORT${CoR} (ID: $host_id) deleted successfully!${CoR}\n"
    exit 0
  else
    echo -e " ⛔ ${COLOR_RED}Failed to delete stream host. Status: $HTTP_STATUS${CoR}"
    exit 1
  fi
}

################################
# Enable a stream host by ID
stream_host_enable() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --stream-host-enable option requires a host 🆔.${CoR}"
    echo -e "   Usage  : ${COLOR_ORANGE}$0 --stream-host-enable <id>${CoR}"
    echo -e "   Example: ${COLOR_GREEN}$0 --stream-host-enable 5${CoR}"
    return 1
  fi

  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/streams/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if echo "$CHECK_RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ⛔ ${COLOR_RED}Stream host with ID $host_id does not exist${CoR}"
    return 1
  fi

  STREAM_PORT=$(echo "$CHECK_RESPONSE" | jq -r '.incoming_port')
  echo -e "\n ${COLOR_YELLOW}🔄 Enabling stream host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🔌Port: ${COLOR_CYAN}$STREAM_PORT${CoR}"

  RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/streams/$host_id/enable" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8")

  if ! echo "$RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ✅ ${COLOR_GREEN}Successfully enabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🔌Port: ${COLOR_CYAN}$STREAM_PORT${CoR}"
  else
    ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
    echo -e " ⛔ ${COLOR_RED}Failed to enable stream host: $ERROR_MSG${CoR}"
    return 1
  fi
}

################################
# Disable a stream host by ID
stream_host_disable() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --stream-host-disable option requires a host 🆔.${CoR}"
    echo -e "   Usage  : ${COLOR_ORANGE}$0 --stream-host-disable <id>${CoR}"
    echo -e "   Example: ${COLOR_GREEN}$0 --stream-host-disable 5${CoR}"
    return 1
  fi

  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/streams/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if echo "$CHECK_RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ⛔ ${COLOR_RED}Stream host with ID $host_id does not exist${CoR}"
    return 1
  fi

  STREAM_PORT=$(echo "$CHECK_RESPONSE" | jq -r '.incoming_port')
  echo -e "\n ${COLOR_YELLOW}🔄 Disabling stream host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🔌Port: ${COLOR_CYAN}$STREAM_PORT${CoR}"

  RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/streams/$host_id/disable" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8")

  if ! echo "$RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ✅ ${COLOR_GREEN}Successfully disabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🔌Port: ${COLOR_CYAN}$STREAM_PORT${CoR}"
  else
    ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
    echo -e " ⛔ ${COLOR_RED}Failed to disable stream host: $ERROR_MSG${CoR}"
    return 1
  fi
}

################################
# List all dead hosts (404 Hosts)
dead_host_list() {
  check_token_notverbose
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/dead-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$JSON_OUTPUT" = true ]; then
    echo "$RESPONSE" | jq .
    exit 0
  fi

  echo -e "\n${COLOR_ORANGE} 👉 List of Dead hosts (404) ${CoR}\n"
  printf "  %4s %-36s %-9s %-7s\n" "ID" " DOMAIN" " STATUS" " SSL"

  CLEANED_RESPONSE=$(echo "$RESPONSE" | tr -d '\000-\031')

  echo "$CLEANED_RESPONSE" | jq -r '.[] | "\(.id)\t\(.domain_names | join(", "))\t\(.enabled)\t\(.certificate_id)"' |
    while IFS=$'\t' read -r id domain enabled certificate_id; do
      if [ "$enabled" = "true" ]; then
        status="$(echo -e "${WHITE_ON_GREEN} enabled ${CoR}")"
      else
        status="$(echo -e "${COLOR_RED} disable ${CoR}")"
      fi
      ssl_status="$(pad "✘" 7)"
      ssl_color="${COLOR_RED}"
      if [ "$certificate_id" != "null" ] && [ -n "$certificate_id" ] && [ "$certificate_id" != "0" ]; then
        ssl_status="$(pad "$certificate_id" 7)"
        ssl_color="${COLOR_CYAN}"
      fi

      IFS=', ' read -ra domain_arr <<<"$domain"
      primary_domain="${domain_arr[0]}"

      printf "  ${COLOR_YELLOW}%4s${CoR}  ${COLOR_GREEN}%s${CoR} %-9s ${ssl_color}%-7s${CoR}\n" \
        "$id" "$(truncate_pad "$primary_domain" 36)" "$status" "$ssl_status"

      for ((i = 1; i < ${#domain_arr[@]}; i++)); do
        printf "        ${COLOR_GREEN}%s${CoR}\n" "$(truncate_pad "${domain_arr[i]}" 36)"
      done
    done
  echo ""
  exit 0
}

################################
# Create or Update a dead host (404 host)
# Reads globals: DOMAIN_NAMES, CERT_ID, SSL_FORCED, HSTS_ENABLED, HSTS_SUBDOMAINS,
#                HTTP2_SUPPORT, ADVANCED_CONFIG, AUTO_YES
create_or_update_dead_host() {
  if [ -z "$DOMAIN_NAMES" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: Missing required parameter (domain).${CoR}"
    echo -e "   Usage: ${COLOR_ORANGE}$0 --dead-host-create domain.com [options]${CoR}"
    exit 1
  fi

  check_token_notverbose

  # Check if a dead host for this domain already exists
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/dead-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  EXISTING=$(echo "$RESPONSE" | jq -r --arg DOMAIN "$DOMAIN_NAMES" '.[] | select(.domain_names[] == $DOMAIN)')
  DEAD_ID=$(echo "$EXISTING" | jq -r '.id // empty')

  SSL_FORCED_JSON=$([ "$SSL_FORCED" == "true" ] && echo true || echo false)
  HSTS_ENABLED_JSON=$([ "$HSTS_ENABLED" == "true" ] && echo true || echo false)
  HSTS_SUBDOMAINS_JSON=$([ "$HSTS_SUBDOMAINS" == "true" ] && echo true || echo false)
  HTTP2_SUPPORT_JSON=$([ "$HTTP2_SUPPORT" == "true" ] && echo true || echo false)

  DATA=$(jq -n \
    --arg domain "$DOMAIN_NAMES" \
    --argjson certificate_id "${CERT_ID:-0}" \
    --argjson ssl_forced "$SSL_FORCED_JSON" \
    --argjson hsts_enabled "$HSTS_ENABLED_JSON" \
    --argjson hsts_subdomains "$HSTS_SUBDOMAINS_JSON" \
    --argjson http2_support "$HTTP2_SUPPORT_JSON" \
    --arg advanced_config "$ADVANCED_CONFIG" \
    '{
            domain_names: [$domain],
            certificate_id: $certificate_id,
            ssl_forced: $ssl_forced,
            hsts_enabled: $hsts_enabled,
            hsts_subdomains: $hsts_subdomains,
            http2_support: $http2_support,
            advanced_config: $advanced_config,
            meta: {}
        }')

  if ! echo "$DATA" | jq empty >/dev/null 2>&1; then
    echo -e " ${COLOR_RED}⛔ ERROR: Invalid JSON generated:\n$DATA${CoR}"
    exit 1
  fi

  if [ -n "$DEAD_ID" ]; then
    if [ "$AUTO_YES" != "true" ]; then
      echo -e " ${COLOR_YELLOW}👉 Do you want to update this dead host ${CoR} $DOMAIN_NAMES ${COLOR_YELLOW}?${CoR}"
      read -n 1 -r -p "   (y/n):  " answer
      echo
      if [[ ! $answer =~ ^[Yy]$ ]]; then
        echo -e " ${COLOR_YELLOW}🚫 No changes made.${CoR}\n"
        return 0
      fi
    fi
    echo -e "\n ${COLOR_CYAN}🔄${CoR} Updating dead host: ${COLOR_GREEN}$DOMAIN_NAMES${CoR}"
    METHOD="PUT"
    URL="$BASE_URL/nginx/dead-hosts/$DEAD_ID"
  else
    echo -e "\n ${COLOR_CYAN}🚫${CoR} Creating dead host (404): ${COLOR_GREEN}$DOMAIN_NAMES${CoR}"
    METHOD="POST"
    URL="$BASE_URL/nginx/dead-hosts"
  fi

  RESPONSE=$(curl -s -X "$METHOD" "$URL" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$DATA")

  ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
  if [ -z "$ERROR_MSG" ]; then
    RID=$(echo "$RESPONSE" | jq -r '.id // "unknown"')
    if [ "$METHOD" = "PUT" ]; then
      echo -e " ✅ ${COLOR_GREEN}Dead host 🚫$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$RID${COLOR_GREEN}) updated successfully! 🎉${CoR}\n"
    else
      echo -e " ✅ ${COLOR_GREEN}Dead host 🚫$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$RID${COLOR_GREEN}) created successfully! 🎉${CoR}\n"
    fi
  else
    echo -e " ⛔ ${COLOR_RED}Operation failed. Error: $ERROR_MSG${CoR}\n"
    exit 1
  fi
}

################################
# Delete a dead host by ID
dead_host_delete() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --dead-host-delete option requires a host 🆔.${CoR}"
    echo -e "   Usage  : ${COLOR_ORANGE}$0 --dead-host-delete <id>${CoR}"
    echo -e "   Example: ${COLOR_GREEN}$0 --dead-host-delete 5${CoR}"
    exit 1
  fi

  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" \
    "$BASE_URL/nginx/dead-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" 2>/dev/null)

  CHECK_BODY=${CHECK_RESPONSE//HTTPSTATUS:*/}
  CHECK_STATUS=${CHECK_RESPONSE##*HTTPSTATUS:}

  if [ "$CHECK_STATUS" -eq 404 ]; then
    echo -e " ⛔ ${COLOR_RED}ERROR: Dead host ID ${COLOR_YELLOW}$host_id${COLOR_RED} not found!${CoR}"
    exit 1
  elif [ "$CHECK_STATUS" -ne 200 ]; then
    echo -e " ⛔ ${COLOR_RED}ERROR: Failed to check dead host. Status: $CHECK_STATUS${CoR}"
    exit 1
  fi

  DOMAIN_NAME=$(echo "$CHECK_BODY" | jq -r '.domain_names[0] // "unknown"')

  if [ "$AUTO_YES" != true ]; then
    echo -e " ┌───────────────────────────────────────────"
    echo -e " │ ID: ${COLOR_YELLOW}$host_id${CoR}"
    echo -e " │ Domain: ${COLOR_GREEN}$DOMAIN_NAME${CoR}"
    echo -e " └───────────────────────────────────────────"
    echo -e " ⚠️  ${COLOR_RED}WARNING: This action cannot be undone!${CoR}"
    read -n 1 -r -p " 🔔 Confirm deletion? (y/n): " CONFIRM
    echo
    if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
      echo -e " ❌ ${COLOR_RED}Operation cancelled${CoR}"
      exit 1
    fi
  else
    echo -e "\n ${COLOR_YELLOW}🔔 -y Auto-confirming deletion${CoR}"
  fi

  echo -e " 🗑️ Deleting dead host ${COLOR_GREEN}$DOMAIN_NAME${CoR} (ID: ${COLOR_GREEN}$host_id${CoR})..."

  RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE \
    "$BASE_URL/nginx/dead-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" 2>/dev/null)

  HTTP_STATUS=${RESPONSE##*HTTPSTATUS:}

  if [ "${HTTP_STATUS:-0}" -eq 200 ]; then
    echo -e " ✅ ${COLOR_GREEN}Dead host ${COLOR_YELLOW}$DOMAIN_NAME${CoR} (ID: $host_id) deleted successfully!${CoR}\n"
    exit 0
  else
    echo -e " ⛔ ${COLOR_RED}Failed to delete dead host. Status: $HTTP_STATUS${CoR}"
    exit 1
  fi
}

################################
# Enable a dead host by ID
dead_host_enable() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --dead-host-enable option requires a host 🆔.${CoR}"
    echo -e "   Usage  : ${COLOR_ORANGE}$0 --dead-host-enable <id>${CoR}"
    echo -e "   Example: ${COLOR_GREEN}$0 --dead-host-enable 5${CoR}"
    return 1
  fi

  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/dead-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if echo "$CHECK_RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ⛔ ${COLOR_RED}Dead host with ID $host_id does not exist${CoR}"
    return 1
  fi

  DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')
  echo -e "\n ${COLOR_YELLOW}🔄 Enabling dead host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"

  RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/dead-hosts/$host_id/enable" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8")

  if ! echo "$RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ✅ ${COLOR_GREEN}Successfully enabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
  else
    ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
    echo -e " ⛔ ${COLOR_RED}Failed to enable dead host: $ERROR_MSG${CoR}"
    return 1
  fi
}

################################
# Disable a dead host by ID
dead_host_disable() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --dead-host-disable option requires a host 🆔.${CoR}"
    echo -e "   Usage  : ${COLOR_ORANGE}$0 --dead-host-disable <id>${CoR}"
    echo -e "   Example: ${COLOR_GREEN}$0 --dead-host-disable 5${CoR}"
    return 1
  fi

  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/dead-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if echo "$CHECK_RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ⛔ ${COLOR_RED}Dead host with ID $host_id does not exist${CoR}"
    return 1
  fi

  DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')
  echo -e "\n ${COLOR_YELLOW}🔄 Disabling dead host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"

  RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/dead-hosts/$host_id/disable" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8")

  if ! echo "$RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
    echo -e " ✅ ${COLOR_GREEN}Successfully disabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
  else
    ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
    echo -e " ⛔ ${COLOR_RED}Failed to disable dead host: $ERROR_MSG${CoR}"
    return 1
  fi
}

################################
# Update an existing proxy host
update_proxy_host() {
  check_token_notverbose
  HOST_ID=$1
  echo -e "\n 🔄 Updating proxy host for $DOMAIN_NAMES..."

  # 🔥 check if the required parameters are set
  if [ -z "$DOMAIN_NAMES" ] || [ -z "$FORWARD_HOST" ] || [ -z "$FORWARD_PORT" ] || [ -z "$FORWARD_SCHEME" ]; then
    echo -e "  ⛔${COLOR_RED} ERROR: Missing required parameters (domain, forward host, forward port, forward scheme).${CoR}"
    exit 1
  fi

  # 🔥 check if the FORWARD_PORT is a number
  if ! [[ "$FORWARD_PORT" =~ ^[0-9]+$ ]]; then
    echo -e "  ⛔${COLOR_RED} ERROR: FORWARD_PORT is not a number! Value: '$FORWARD_PORT'${CoR}"
    exit 1
  fi

  # 🔥 Correct the CUSTOM_LOCATIONS
  if [[ -z "$CUSTOM_LOCATIONS" || "$CUSTOM_LOCATIONS" == "null" ]]; then
    CUSTOM_LOCATIONS_ESCAPED="[]"
  else
    CUSTOM_LOCATIONS_ESCAPED=$(echo "$CUSTOM_LOCATIONS" | jq -c . 2>/dev/null || echo '[]')
  fi

  # correct the boolean (true / false in JSON)
  CACHING_ENABLED_JSON=$([ "$CACHING_ENABLED" == "true" ] && echo true || echo false)
  BLOCK_EXPLOITS_JSON=$([ "$BLOCK_EXPLOITS" == "true" ] && echo true || echo false)
  ALLOW_WEBSOCKET_UPGRADE_JSON=$([ "$ALLOW_WEBSOCKET_UPGRADE" == "true" ] && echo true || echo false)
  HTTP2_SUPPORT_JSON=$([ "$HTTP2_SUPPORT" == "true" ] && echo true || echo false)

  # 🔍 Debugging variables before JSON update:
  debug_var

  # 🔥 generate the JSON properly
  DATA=$(
    jq -n \
      --arg domain "$DOMAIN_NAMES" \
      --arg host "$FORWARD_HOST" \
      --arg port "$FORWARD_PORT" \
      --arg scheme "$FORWARD_SCHEME" \
      --argjson caching "$CACHING_ENABLED_JSON" \
      --argjson block_exploits "$BLOCK_EXPLOITS_JSON" \
      --arg advanced_config "$ADVANCED_CONFIG" \
      --argjson websocket_upgrade "$ALLOW_WEBSOCKET_UPGRADE_JSON" \
      --argjson http2_support "$HTTP2_SUPPORT_JSON" \
      --argjson enabled true \
      --argjson locations "$CUSTOM_LOCATIONS_ESCAPED" \
      '{
      domain_names: [$domain],
      forward_host: $host,
      forward_port: ($port | tonumber),
      access_list_id: null,
      certificate_id: null,
      ssl_forced: false,
      caching_enabled: $caching,
      block_exploits: $block_exploits,
      advanced_config: $advanced_config,
      meta: { dns_challenge: null },
      allow_websocket_upgrade: $websocket_upgrade,
      http2_support: $http2_support,
      forward_scheme: $scheme,
      enabled: $enabled,
      locations: $locations
    }'
  )

  # 🔍 check if the JSON is valid
  if ! echo "$DATA" | jq empty >/dev/null 2>&1; then
    echo -e "  ⛔${COLOR_RED} ERROR: Invalid JSON generated:\n$DATA ${CoR}"
    exit 1
  fi

  # 🚀 send the API request for update
  RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$DATA")

  # 📢 check if the response is valid
  ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
  if [ -z "$ERROR_MSG" ]; then
    PROXY_ID=$(echo "$RESPONSE" | jq -r '.id // "unknown"')
    echo -e "\n ✅ ${COLOR_GREEN}SUCCESS: Proxy host 🔗$DOMAIN_NAMES (ID: ${COLOR_YELLOW}$PROXY_ID${COLOR_GREEN}) was created successfully! 🎉${CoR}\n"
  else
    echo -e " ⛔ ${COLOR_RED}Failed to create proxy host. Error: $ERROR_MSG ${CoR}"
    exit 1
  fi
}

################################
# Update field of existing proxy host
host_update() {
  check_token_notverbose
  HOST_ID="$1"
  FIELD="$2"
  NEW_VALUE="$3"

  #echo -e "\n 🔄 DEBUG: host-update() function has started"
  # echo -e "    🆔 HOST_ID: $HOST_ID"
  # echo -e "    🏷  FIELD: $FIELD"
  # echo -e "    ✏️  VALUE: $NEW_VALUE"

  #  1) Check that all required parameters are provided
  if [ -z "$HOST_ID" ] || [ -z "$FIELD" ] || [ -z "$NEW_VALUE" ]; then
    echo -e "\n ⛔ ${COLOR_RED}INVALID command: Missing required parameters.${CoR}"
    echo -e "    Usage: ${COLOR_ORANGE}$0 --host-update <host_id> <field=value>${CoR}"
    exit 1
  fi

  #  2) Fetch current configuration
  CURRENT_DATA=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  #echo -e "\n 🔄 DEBUG: API response (CURRENT_DATA):\n$CURRENT_DATA\n"

  if ! echo "$CURRENT_DATA" | jq empty >/dev/null 2>&1; then
    echo -e "  ⛔ ${COLOR_RED}ERROR:${CoR} Failed to fetch current proxy configuration."
    exit 1
  fi

  #  3) Check if the requested field is editable
  FILTERED_DATA=$(echo "$CURRENT_DATA" | jq '{
    domain_names,
    forward_host,
    forward_port,
    access_list_id,
    certificate_id,
    ssl_forced,
    caching_enabled,
    block_exploits,
    advanced_config,
    meta,
    allow_websocket_upgrade,
    http2_support,
    forward_scheme,
    enabled,
    locations,
    hsts_enabled,
    hsts_subdomains
  }')

  #echo -e "\n 🔄 DEBUG: Filtered JSON before update:\n$FILTERED_DATA\n"

  if ! echo "$FILTERED_DATA" | jq -e --arg field "$FIELD" 'has($field)' >/dev/null; then
    echo -e "  ⛔ ${COLOR_RED}ERROR:${CoR} The field '$FIELD' is not a valid field for update."
    exit 1
  fi

  #  4) Modifier la configuration
  if [ "$FIELD" = "forward_port" ]; then
    UPDATED_DATA=$(echo "$FILTERED_DATA" |
      jq --argjson newVal "$(echo "$NEW_VALUE" | jq -R 'tonumber? // 0')" \
        '.forward_port = $newVal')
  else
    UPDATED_DATA=$(echo "$FILTERED_DATA" |
      jq --arg newVal "$NEW_VALUE" \
        ".$FIELD = \$newVal")
  fi

  #echo -e "\n 🔄 DEBUG: JSON Sent to API:\n$UPDATED_DATA\n"

  if ! echo "$UPDATED_DATA" | jq empty >/dev/null 2>&1; then
    echo -e "  ⛔ ${COLOR_RED}ERROR: Invalid JSON generated.${CoR}\n$UPDATED_DATA"
    exit 1
  fi

  #  Sending update request to API..."
  RESPONSE=$(curl -s -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$UPDATED_DATA")

  #echo -e "\n 🔄 DEBUG: API Response:\n$RESPONSE\n"

  ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // empty')
  if [ -z "$ERROR_MSG" ]; then
    echo -e "\n ✅ ${COLOR_GREEN}SUCCESS:${CoR}  Proxy host 🆔 $HOST_ID updated successfully! 🎉"

    SUMMARY=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
    if echo "$SUMMARY" | jq empty >/dev/null 2>&1; then

      echo -e "    New Value Proxy host 🆔 $HOST_ID $FIELD : $(echo "$SUMMARY" | jq -r --arg field "$FIELD" '.[$field]')\n"
      echo -e " 🔄 ${COLOR_CYAN}Summary Proxy Host:${CoR}"
      echo -e "    Domaine(s)      : $(echo "$SUMMARY" | jq -r '.domain_names | join(", ")')"
      echo -e "    Forward Host    : $(echo "$SUMMARY" | jq -r '.forward_host')"
      echo -e "    Forward Port    : $(echo "$SUMMARY" | jq -r '.forward_port')"
      echo -e "    Forward Scheme  : $(echo "$SUMMARY" | jq -r '.forward_scheme')"
      echo -e "    SSL Forced      : $(echo "$SUMMARY" | jq -r '.ssl_forced')\n"

    else
      echo -e "\n ⚠️ ${COLOR_YELLOW}WARNING:${CoR} Error to get proxy host data."
    fi

  else
    echo -e "\n ⛔ ${COLOR_RED}Failed to update proxy host. Error:${CoR} $ERROR_MSG"
    exit 1
  fi

}

################################
# Search for a proxy host by domain name
host_search() {
  #check_token false
  check_token_notverbose
  if [ -z "$HOST_SEARCHNAME" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --host-search option requires a <host domain>.${CoR}"
    echo -e "     Usage  : ${COLOR_ORANGE}$0 --host-search domain_name${CoR}"
    echo -e "     Example: ${COLOR_GREEN}$0 --host-search example.com${CoR}\n"
    exit 1
  fi

  echo -e "\n ${COLOR_CYAN}🔍${CoR} Searching proxy hosts for: ${COLOR_YELLOW}$HOST_SEARCHNAME${CoR}"

  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ -z "$RESPONSE" ] || [ "$RESPONSE" == "null" ]; then
    echo -e " ⛔ ${COLOR_RED}Error: Unable to retrieve proxy host data.${CoR}"
    exit 1
  fi

  MATCHES=$(echo "$RESPONSE" | jq -c --arg search "$HOST_SEARCHNAME" '.[] | select(.domain_names[] | contains($search))')

  if [ -z "$MATCHES" ]; then
    echo -e " ❌ No proxy host found for: ${COLOR_YELLOW}$HOST_SEARCHNAME${CoR}"
  else
    echo "$MATCHES" | while IFS= read -r line; do
      id=$(echo "$line" | jq -r '.id')
      domain_names=$(echo "$line" | jq -r '.domain_names[]')
      printf "   ${COLOR_GREY}🆔${COLOR_YELLOW}%4s${CoR} ${COLOR_GREEN}%s${CoR}\n" "$id" "$domain_names"
    done
  fi
  echo ""
  exit 0
}

################################
################################
# Enable a proxy host by ID
#
# 💡 NPM-specific endpoint discovery (2025-05-30):
# ================================================
# Like host_disable(), this function uses NPM's dedicated endpoint:
#
# ✅ CORRECT approach:
#    POST /api/nginx/proxy-hosts/{id}/enable with empty body
#    → Actually enables the site and makes it accessible
#
# ❌ The generic PUT approach with JSON modification doesn't work reliably.
# Reference: Same discovery as host_disable() function above.
################################

# Enable a proxy host by ID
host_enable() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --host-enable option requires a host 🆔.${CoR}"
    echo -e "     Usage  : ${COLOR_ORANGE}$0 --host-enable <host_id>${CoR}"
    echo -e "     Example: ${COLOR_GREEN}$0 --host-enable 42${CoR}"
    return 1
  fi

  check_token_notverbose

  # Check if the proxy host exists first
  CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ $? -eq 0 ] && [ -n "$CHECK_RESPONSE" ]; then
    # Check if the host was found (not a 404 error)
    if echo "$CHECK_RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
      echo -e " ⛔ ${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}"
      return 1
    fi

    # Get domain name for display
    DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')

    echo -e "\n ${COLOR_YELLOW}🔄 Enabling proxy host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"

    # Use the CORRECT NPM endpoint: POST to /enable (like the web interface does)
    RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/proxy-hosts/$host_id/enable" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
      -H "Content-Type: application/json; charset=UTF-8")

    if [ $? -eq 0 ] && ! echo "$RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
      echo -e " ✅ ${COLOR_GREEN}Successfully enabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
    #    echo -e " 🎯 ${COLOR_GREEN}Using NPM's native enable endpoint${CoR}\n"
    else
      ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
      echo -e " ⛔ ${COLOR_RED}Failed to enable proxy host: $ERROR_MSG${CoR}"
      return 1
    fi
  else
    echo -e " ⛔ ${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}"
    return 1
  fi
}

################################
# Disable a proxy host by ID
#
# 🐛 IMPORTANT BUG DISCOVERY (2025-05-30):
# ==========================================
# The NPM web interface uses a DIFFERENT endpoint than expected!
#
# ❌ WRONG approach (what we tried before):
#    PUT /api/nginx/proxy-hosts/{id} with modified JSON (enabled: false)
#    → Shows "disabled" in interface but site remains ACCESSIBLE!
#
# ✅ CORRECT approach (what NPM web interface actually uses):
#    POST /api/nginx/proxy-hosts/{id}/disable with empty body
#    → Actually disables the site and makes it INACCESSIBLE!
#
# This was discovered by inspecting NPM web interface network traffic.
# NPM has dedicated /enable and /disable endpoints that work properly.
# Reference: GitHub issue #3 (nginx-proxy-manager-Bash-API)
################################
host_disable() {
  local host_id="$1"

  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --host-disable option requires a host 🆔.${CoR}"
    echo -e "     Usage  : ${COLOR_ORANGE}$0 --host-disable <host_id>${CoR}"
    echo -e "     Example: ${COLOR_GREEN}$0 --host-disable 42${CoR}"
    return 1
  fi

  check_token_notverbose

  # Check if the proxy host exists first
  CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ $? -eq 0 ] && [ -n "$CHECK_RESPONSE" ]; then
    # Check if the host was found (not a 404 error)
    if echo "$CHECK_RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
      echo -e " ⛔ ${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}"
      return 1
    fi

    # Get domain name for display
    DOMAIN_NAME=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')

    echo -e "\n ${COLOR_YELLOW}🔄 Disabling proxy host ${CoR} 🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"

    # Use the CORRECT NPM endpoint: POST to /disable (like the web interface does)
    RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/proxy-hosts/$host_id/disable" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
      -H "Content-Type: application/json; charset=UTF-8")

    if [ $? -eq 0 ] && ! echo "$RESPONSE" | jq -e '.error' >/dev/null 2>&1; then
      echo -e " ✅ ${COLOR_GREEN}Successfully disabled ${CoR}🆔${COLOR_CYAN}$host_id${CoR} 🌐Domain: ${COLOR_CYAN}$DOMAIN_NAME${CoR}"
    #    echo -e " 🎯 ${COLOR_GREEN}Using NPM's native disable endpoint${CoR}\n"
    else
      ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message // "Unknown error"')
      echo -e " ⛔ ${COLOR_RED}Failed to disable proxy host: $ERROR_MSG${CoR}"
      return 1
    fi
  else
    echo -e " ⛔ ${COLOR_RED}Proxy host with ID $host_id does not exist${CoR}"
    return 1
  fi
}

################################
# Delete a proxy host
# $1: host_id - ID of the host to delete
host_delete() {
  local host_id="$1"

  # Check if ID is provided
  if [ -z "$HOST_ID" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: The --host-delete option requires a host 🆔${CoR}"
    echo -e " Usage  : ${COLOR_ORANGE}$0 --host-delete <host_id>${CoR}"
    echo -e " Example: ${COLOR_GREEN}$0 --host-delete 42${CoR}"
    exit 1
  fi

  check_token_notverbose
  # Check if host exists before attempting deletion
  #echo -e "\n 🔎 Checking if host ID ${COLOR_GREEN}$HOST_ID${CoR} exists..."
  CHECK_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" \
    "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" 2>/dev/null)

  CHECK_BODY=${CHECK_RESPONSE//HTTPSTATUS:*/}
  CHECK_STATUS=${CHECK_RESPONSE##*HTTPSTATUS:}

  # Verify host existence
  if [ "$CHECK_STATUS" -eq 404 ]; then
    echo -e " ⛔ ${COLOR_RED}ERROR: Host ID ${COLOR_GREEN}$HOST_ID${COLOR_RED} not found!${CoR}"
    echo -e "\n ${COLOR_YELLOW}💡 Tip: Use --host-list to see all available hosts and their IDs${CoR}"
    exit 1
  elif [ "$CHECK_STATUS" -ne 200 ]; then
    echo -e " ⛔ ${COLOR_RED}ERROR: Failed to check host. Status: $CHECK_STATUS${CoR}"
    if [ -n "$CHECK_BODY" ]; then
      echo -e " 📝 Error details: $CHECK_BODY"
    fi
    exit 1
  fi

  # Extract domain name for confirmation
  DOMAIN_NAME=$(echo "$CHECK_BODY" | jq -r '.domain_names[0] // "unknown"')

  # Show confirmation prompt unless AUTO_YES is set
  if [ "$AUTO_YES" != true ]; then
    echo -e " ┌───────────────────────────────────────────"
    echo -e " │ ID: ${COLOR_YELLOW}$HOST_ID${CoR}"
    echo -e " │ Domain: ${COLOR_GREEN}$DOMAIN_NAME${CoR}"
    echo -e " └───────────────────────────────────────────"
    echo -e " ⚠️  ${COLOR_RED}WARNING: This action cannot be undone!${CoR}"
    read -n 1 -r -p " 🔔 Confirm deletion? (y/n): " CONFIRM
    echo
    if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
      echo -e " ❌ ${COLOR_RED}Operation cancelled${CoR}"
      exit 1
    fi
    echo -e " 🗑️ Deleting proxy host ${COLOR_GREEN}$DOMAIN_NAME${CoR} (ID: ${COLOR_GREEN}$HOST_ID${CoR})"
  else
    echo -e "\n ${COLOR_YELLOW}🔔 -y Auto-confirming deletion${CoR}"
    echo -e " 🗑️ Deleting proxy host ${COLOR_GREEN}$DOMAIN_NAME${CoR} (ID: ${COLOR_GREEN}$HOST_ID${CoR})..."
  fi

  # Perform deletion
  RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE \
    "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" 2>/dev/null)

  HTTP_BODY=${RESPONSE//HTTPSTATUS:*/}
  HTTP_STATUS=${RESPONSE##*HTTPSTATUS:}

  if [ "${HTTP_STATUS:-0}" -eq 200 ]; then
    echo -e " ✅ ${COLOR_GREEN}Proxy host ${COLOR_YELLOW}$DOMAIN_NAME${CoR} (ID: $HOST_ID) deleted successfully!${CoR}\n"
    exit 0
  else
    echo -e " ⛔ ${COLOR_RED}Failed to delete proxy host. Status: $HTTP_STATUS${CoR}"
    if [ -n "$HTTP_BODY" ]; then
      echo -e " 📝 Error details: $HTTP_BODY"
    fi
    exit 1
  fi
}

################################
# ACL  proxy host
host_acl_enable() {
  # Check that both arguments are provided
  if [ -z "$HOST_ID" ] || [ -z "$ACCESS_LIST_ID" ]; then
    echo -e "\n ⛔ ${COLOR_RED}Error: HOST_ID and ACCESS_LIST_ID are required to enable the ACL.${CoR}"
    echo -e " Usage: ${COLOR_ORANGE}$0 --host-acl-enable <host_id> <access_list_id>${CoR}"
    echo -e " Example: ${COLOR_GREEN}$0 --host-acl-enable 42 5${CoR}"
    exit 1
  fi

  check_token_notverbose
  echo -e "\n ${COLOR_YELLOW}🔓 Enabling ACL${CoR} host 🆔${COLOR_CYAN}$HOST_ID${CoR} with access list 🆔${COLOR_CYAN}$ACCESS_LIST_ID${CoR}"

  DATA=$(jq -n \
    --argjson access_list_id "$ACCESS_LIST_ID" \
    --argjson enabled true \
    '{
      access_list_id: $access_list_id,
      enabled: $enabled
    }')

  RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$DATA")
  HTTP_BODY=${RESPONSE//HTTPSTATUS:*/}
  HTTP_STATUS=${RESPONSE##*HTTPSTATUS:}

  if [ "$HTTP_STATUS" = "200" ]; then
    echo -e " ✅ ${COLOR_GREEN}ACL successfully enabled access list ${CoR}🆔${COLOR_CYAN}$ACCESS_LIST_ID${CoR} for host🆔${COLOR_CYAN}$HOST_ID${CoR}\n"
  else
    echo -e " ⛔ ${COLOR_RED}Failed to enable ACL (HTTP $HTTP_STATUS). Error: $(echo "$HTTP_BODY" | jq -r '.error.message // "Unknown error"')${CoR}\n"
    exit 1
  fi
}

################################
# Disable ACL for a given proxy host
host_acl_disable() {
  if [ -z "$HOST_ID" ]; then
    echo -e "\n ⛔ ${COLOR_RED}Error: HOST_ID is required to disable the ACL.${CoR}"
    echo -e "    Usage: $0 --host-acl-disable <host_id>\n"
    exit 1
  fi
  check_token_notverbose

  DATA=$(jq -n \
    --argjson access_list_id null \
    --argjson enabled false \
    '{
      access_list_id: $access_list_id,
      enabled: $enabled
    }')
  RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$DATA")
  HTTP_BODY=${RESPONSE//HTTPSTATUS:*/}
  HTTP_STATUS=${RESPONSE##*HTTPSTATUS:}

  if [ "$HTTP_STATUS" = "200" ]; then
    echo -e "\n 🔒 ${COLOR_ORANGE}Disabling ACL for host${CoR}🆔${COLOR_CYAN} $HOST_ID${CoR}"
    echo -e " ✅ ${COLOR_GREEN}ACL successfully disabled ACL for host ${CoR}🆔${COLOR_CYAN}$HOST_ID${CoR}\n"
  else
    echo -e "\n ⛔ ${COLOR_RED}Failed to disable ACL (HTTP $HTTP_STATUS). Error: $(echo "$HTTP_BODY" | jq -r '.error.message // "Unknown error"')${CoR}\n"
    exit 1
  fi
}

################################
# Show details of a specific proxy host
host_show() {
  #local host_id="$1"
  if [ -z "$host_id" ]; then
    echo -e "\n ⛔ ${COLOR_RED}The --host-show option requires a host ID.${CoR}"
    echo -e " Usage: ${COLOR_ORANGE}$0 --host-show <ID>${CoR}"
    echo -e " To find ID Check with ${COLOR_ORANGE}$0 --host-list${CoR}\n"
    return 1
  fi
  check_token_notverbose
  [ "$JSON_OUTPUT" = true ] || echo -e "\n 🔍 Fetching details for proxy host ID: ${COLOR_YELLOW}$host_id${CoR}..."
  # get host details
  local response=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  # Check if the response contains an error
  if echo "$response" | jq -e '.error' >/dev/null; then
    if [ "$JSON_OUTPUT" = true ]; then
      echo "$response" | jq '{error: (.error.message // "Unknown error")}'
      exit 1
    fi
    echo -e " ⛔ ${COLOR_RED}Error: $(echo "$response" | jq -r '.error.message')${CoR}\n"
    return 1
  fi
  if [ "$JSON_OUTPUT" = true ]; then
    echo "$response" | jq .
    exit 0
  fi
  # Format and display details
  echo -e "\n📋 ${COLOR_YELLOW}Host Details:${CoR}"
  echo -e "┌───────────────────────────────────"
  echo -e "│ 🆔 ID: ${COLOR_GREEN_b}$(echo "$response" | jq -r '.id')${CoR}"
  echo -e "│ 🌐 Domains: ${COLOR_GREEN_b}$(echo "$response" | jq -r '.domain_names[]' | tr '\n' ' ')${CoR}"
  echo -e "│ 🔄 Forward Configuration:"
  echo -e "│   • Host: ${COLOR_GREEN_b}$(echo "$response" | jq -r '.forward_host')${CoR}"
  echo -e "│   • Port: ${COLOR_GREEN_b}$(echo "$response" | jq -r '.forward_port')${CoR}"
  echo -e "│   • Scheme: ${COLOR_GREEN_b}$(echo "$response" | jq -r '.forward_scheme')${CoR}"
  echo -e "│ ✅ Status: $(colorize_boolean $(echo "$response" | jq -r '.enabled | if . then "Enabled" else "Disabled" end'))"
  echo -e "│ 🔒 SSL Configuration:"
  echo -e "│    • Certificate ID: ${COLOR_ORANGE}$(echo "$response" | jq -r '.certificate_id')${CoR}"
  echo -e "│    • SSL Forced: $(colorize_boolean $(echo "$response" | jq -r '.ssl_forced | if . then "true" else "false" end'))"
  echo -e "│    • HTTP/2: $(colorize_boolean $(echo "$response" | jq -r '.http2_support | if . then "true" else "false" end'))"
  echo -e "│    • HSTS: $(colorize_boolean $(echo "$response" | jq -r '.hsts_enabled | if . then "true" else "false" end'))"
  echo -e "│ 🛠️ Features:"
  echo -e "│    • Block Exploits: $(colorize_boolean $(echo "$response" | jq -r '.block_exploits | if . then "true" else "false" end'))"
  echo -e "│    • Caching: $(colorize_boolean $(echo "$response" | jq -r '.caching_enabled | if . then "true" else "false" end'))"
  echo -e "│    • Websocket Upgrade: $(colorize_boolean $(echo "$response" | jq -r '.allow_websocket_upgrade | if . then "true" else "false" end'))"
  echo -e "│ 🔑 Access List ID: ${COLOR_ORANGE}$(echo "$response" | jq -r '.access_list_id')${CoR}"

  # Check and display advanced configuration
  if [ "$(echo "$response" | jq -r '.advanced_config')" != "null" ]; then
    echo -e "│ ⚙️ Advanced Config: ${COLOR_GREEN}Yes${CoR}"
    echo -e "│"
    echo "$response" | jq -r '.advanced_config' | while IFS= read -r line; do
      if [ -n "$line" ]; then
        echo -e "│ ${COLOR_GRAY}$line${CoR}"
      else
        echo -e "│"
      fi
    done
  else
    echo -e "│ ⚙️ Advanced Config: ${COLOR_RED}No${CoR}"
  fi

  echo -e "└────────────────────────────────────"
  return 0
}

################################
# Delete a certificate in NPM
# NOTE: NPM's DELETE /nginx/certificates/:id is a SOFT delete (sets is_deleted=1):
# the cert leaves the list/UI but its on-disk files remain. The optional --purge
# flag (see cert_purge_files) removes those leftover files. The DB row is left
# untouched on purpose to avoid any referential-integrity risk.

################################
# Remove the on-disk certificate files left behind by NPM's soft-delete.
# Requires NGINX_PATH_DOCKER (set in npm-api.conf) to point at the NPM data
# directory that holds custom_ssl/ and letsencrypt/. No-op (with a clear
# message) when that path is not configured/accessible on this host.
cert_purge_files() {
  local id="$1"
  local base="${NGINX_PATH_DOCKER:-}"

  if [ -z "$base" ] || [ "$base" = "$DEFAULT_NGINX_PATH_DOCKER" ]; then
    echo -e "  ⚠️ ${COLOR_YELLOW}--purge skipped:${CoR} set ${COLOR_CYAN}NGINX_PATH_DOCKER${CoR} in npm-api.conf to the NPM data dir (holding ${COLOR_GREY}custom_ssl/${CoR} and ${COLOR_GREY}letsencrypt/${CoR}).\n"
    return 0
  fi
  if [ ! -d "$base" ]; then
    echo -e "  ⚠️ ${COLOR_YELLOW}--purge skipped:${CoR} NGINX_PATH_DOCKER (${COLOR_GREY}$base${CoR}) is not an accessible directory on this host.\n"
    return 0
  fi

  local targets=(
    "$base/custom_ssl/npm-$id"
    "$base/letsencrypt/live/npm-$id"
    "$base/letsencrypt/archive/npm-$id"
    "$base/letsencrypt/renewal/npm-$id.conf"
  )

  local removed=0 t
  for t in "${targets[@]}"; do
    if [ -e "$t" ]; then
      if rm -rf "$t" 2>/dev/null; then
        echo -e "    🧹 Removed ${COLOR_GREY}$t${CoR}"
        removed=$((removed + 1))
      else
        echo -e "    ⛔ ${COLOR_RED}Could not remove $t${CoR} ${COLOR_GREY}(permissions? try as root or inside the NPM container)${CoR}"
      fi
    fi
  done

  if [ "$removed" -eq 0 ]; then
    echo -e "  ℹ️ ${COLOR_GREY}--purge: no on-disk files found for npm-$id under $base${CoR}\n"
  else
    echo -e "  ✅ ${COLOR_GREEN}Purged $removed on-disk item(s) for cert npm-$id${CoR}\n"
  fi
}

################################
cert_delete() {
  local CERT_IDENTIFIER="$1"

  if [ -z "$CERT_IDENTIFIER" ]; then
    echo -e "\n ⛔ ${COLOR_RED}Error: Please specify a domain or certificate ID${CoR}"
    echo -e "Usage: --cert-delete <domain.com or ID>"
    exit 1
  fi

  check_token_notverbose

  # Get certificates list from API
  CERTIFICATES=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  # Check if input is a number (ID) or domain
  if [[ "$CERT_IDENTIFIER" =~ ^[0-9]+$ ]]; then
    # It's an ID
    CERT_ID="$CERT_IDENTIFIER"
    CERT_EXISTS=$(echo "$CERTIFICATES" | jq -r --arg id "$CERT_ID" '.[] | select(.id == ($id|tonumber)) | .id')

    # Add verification for CERT_EXISTS
    if [ -z "$CERT_EXISTS" ]; then
      echo -e "\n ⛔ ${COLOR_RED}No certificate found with ID: $CERT_ID${CoR}"
      exit 1
    fi
    #echo -e "  ✅ Certificate ID $CERT_ID found"
  else
    # It's a domain - Get all matching certificates
    MATCHING_CERTS=$(echo "$CERTIFICATES" | jq -r --arg domain "$CERT_IDENTIFIER" \
      '[.[] | select(.domain_names[] == $domain or .nice_name == $domain)]')

    CERT_COUNT=$(echo "$MATCHING_CERTS" | jq 'length')

    if [ "$CERT_COUNT" -eq 0 ]; then
      echo -e " ⛔ ${COLOR_RED}No certificates found for domain: $CERT_IDENTIFIER${CoR}"
      exit 1
    elif [ "$CERT_COUNT" -eq 1 ]; then
      CERT_ID=$(echo "$MATCHING_CERTS" | jq -r '.[0].id')
    else
      # Multiple certificates found, let user choose
      echo -e " 📜 Multiple certificates found for $CERT_IDENTIFIER:"
      echo "$MATCHING_CERTS" | jq -r '.[] | "ID: \(.id) - Provider: \(.provider) - Expires: \(.expires_on) - Domains: \(.domain_names|join(", "))"' |
        awk '{print NR ") " $0}'

      if [ "$AUTO_YES" = true ]; then
        echo -e " ⚠️ Multiple certificates found with -y option. Please specify certificate ID instead."
        exit 1
      fi

      read -r -p "Enter the number of the certificate to delete (1-$CERT_COUNT): " CHOICE
      if ! [[ "$CHOICE" =~ ^[0-9]+$ ]] || [ "$CHOICE" -lt 1 ] || [ "$CHOICE" -gt "$CERT_COUNT" ]; then
        echo -e " ⛔ ${COLOR_RED}Invalid selection${CoR}"
        exit 1
      fi

      CERT_ID=$(echo "$MATCHING_CERTS" | jq -r --arg idx "$((CHOICE - 1))" '.[$idx|tonumber].id')
    fi
  fi

  if [ -z "$CERT_ID" ]; then
    echo -e " ⛔ ${COLOR_RED}No valid certificate found${CoR}"
    exit 1
  fi

  # Warn if the certificate is still referenced by a proxy/redirection host.
  # NPM's delete is a soft-delete, so those hosts keep a dangling certificate_id
  # until their SSL is reconfigured; and --purge would remove files still in use.
  REFERENCING=$(
    {
      curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" |
        jq -r --argjson id "$CERT_ID" '.[]? | select(.certificate_id == $id) | "proxy host #\(.id) (\(.domain_names | join(", ")))"' 2>/dev/null
      curl -s -X GET "$BASE_URL/nginx/redirection-hosts" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" |
        jq -r --argjson id "$CERT_ID" '.[]? | select(.certificate_id == $id) | "redirection host #\(.id) (\(.domain_names | join(", ")))"' 2>/dev/null
      curl -s -X GET "$BASE_URL/nginx/streams" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" |
        jq -r --argjson id "$CERT_ID" '.[]? | select(.certificate_id == $id) | "stream #\(.id) (port \(.incoming_port))"' 2>/dev/null
      curl -s -X GET "$BASE_URL/nginx/dead-hosts" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" |
        jq -r --argjson id "$CERT_ID" '.[]? | select(.certificate_id == $id) | "dead host #\(.id) (\(.domain_names | join(", ")))"' 2>/dev/null
    } | grep -v '^$' || true
  )

  if [ -n "$REFERENCING" ]; then
    echo -e "\n  ⚠️ ${COLOR_YELLOW}Certificate ID $CERT_ID is still used by:${CoR}"
    echo "$REFERENCING" | while IFS= read -r ref; do
      echo -e "      • ${COLOR_GREY}$ref${CoR}"
    done
    echo -e "  ${COLOR_GREY}These hosts will keep a dangling certificate_id until you reconfigure their SSL.${CoR}"
    if [ "$CERT_PURGE" = true ]; then
      echo -e "  ⛔ ${COLOR_RED}--purge refused:${CoR} the on-disk files are still in use. Disable/re-assign SSL on those hosts first.\n"
      exit 1
    fi
  fi

  # Ask for confirmation unless AUTO_YES is set
  if [ "$AUTO_YES" = true ]; then
    #echo -e " 🔔 The -y option was provided. Skipping confirmation prompt..."
    CONFIRM="y"
  else
    echo -e "${COLOR_YELLOW}"
    read -n 1 -r -p "  ⚠️ Are you sure you want to delete certificate ID: $CERT_ID ? (y/n): " CONFIRM
    echo -e "${CoR}"
  fi

  if [[ "$CONFIRM" != "y" ]]; then
    echo -e "${COLOR_RED}  ❌ Certificate deletion aborted.${CoR}\n"
    exit 0
  fi

  echo -e "\n  🗑️ Deleting certificate ID: $CERT_ID..."

  # Delete certificate through API
  HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X DELETE \
    "$BASE_URL/nginx/certificates/$CERT_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  HTTP_BODY=${HTTP_RESPONSE//HTTPSTATUS:*/}
  HTTP_STATUS=${HTTP_RESPONSE##*HTTPSTATUS:}

  if [ "${HTTP_STATUS:-0}" -eq 200 ]; then
    echo -e "  ✅ ${COLOR_GREEN}Certificate successfully deleted!${CoR}\n"
    if [ "$CERT_PURGE" = true ]; then
      cert_purge_files "$CERT_ID"
    fi
  else
    echo -e "  ⛔ ${COLOR_RED}Deletion failed. Status: $HTTP_STATUS. Response: $HTTP_BODY${CoR}\n"
  fi
}

################################
# Generate Let's Encrypt certificate if not exists
cert_generate() {
  # 1. Local variables
  DOMAIN_NAMES="${1:-}"
  DOMAIN=$DOMAIN_NAMES
  EMAIL="${2:-}"
  DNS_PROVIDER="${3:-}"
  DNS_CREDENTIALS_JSON="${4:-}"
  EXISTING_CERT=""
  IS_WILDCARD=false

  # 2. Basic validation
  if [ -z "$DOMAIN_NAMES" ]; then
    echo -e "\n ${COLOR_RED}❌${CoR} Error: Domain is required $DOMAIN"
    echo -e "    Usage: $0 --cert-generate <domain> [email] [--cert-email <email>] [--dns-provider <provider>] [--dns-credentials <json>]\n"
    exit 1
  fi

  if [ -z "$EMAIL" ]; then
    EMAIL="$DEFAULT_EMAIL"
    echo -e "\n 📧 Using default email: ${COLOR_YELLOW}$EMAIL${CoR}"
  fi

  check_token_notverbose

  # 3. Check if wildcard and validate requirements
  if [[ "$DOMAIN" == \** ]]; then
    IS_WILDCARD=true
    if [ -z "$DNS_PROVIDER" ] || [ -z "$DNS_CREDENTIALS_JSON" ]; then
      echo -e " ⛔ ${COLOR_RED}DNS provider and credentials are required for wildcard certificates${CoR}\n"
      exit 1
    fi

    # Credentials: JSON object or raw certbot INI text ("key = value" lines)
    if [[ "$DNS_CREDENTIALS_JSON" == \{* ]] && ! echo "$DNS_CREDENTIALS_JSON" | jq -e 'type == "object"' >/dev/null 2>&1; then
      echo -e " ⛔ ${COLOR_RED}Invalid JSON format for DNS credentials${CoR}\n"
      exit 1
    fi
  fi

  # Proxy host using this domain (needed by --host-ssl-enable)
  PROXY_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  DOMAIN_EXISTS=$(echo "$PROXY_RESPONSE" | jq -r --arg DOMAIN "$DOMAIN" \
    'first(.[] | select(.domain_names | index($DOMAIN)) | .id) // empty')

  # Only require the host to exist in NPM if it is not a wildcard
  if [ "$IS_WILDCARD" = false ]; then
    if [ -z "$DOMAIN_EXISTS" ]; then
      echo -e "\n ${COLOR_RED}❌${CoR} Domain ${COLOR_YELLOW}$DOMAIN${CoR} is not configured in NPM."
      echo -e " ${COLOR_YELLOW}💡${CoR} First create a proxy host with:"
      echo -e "   ${COLOR_CYAN}$0 --host-create $DOMAIN -i <forward_host> -p <forward_port>${CoR}\n"
      exit 1
    fi
  fi

  # Then check existing certificates
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/certificates" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  EXISTING_CERT=$(echo "$RESPONSE" | jq -c --arg domain "$DOMAIN" \
    "$CERT_JQ_EXPIRED"' first(.[] | select(.domain_names | index($domain)) | select(is_expired | not)) // empty')

  if [ -n "$EXISTING_CERT" ]; then
    CERT_ID=$(echo "$EXISTING_CERT" | jq -r '.id')
    CERT_EXPIRES=$(echo "$EXISTING_CERT" | jq -r '.expires_on')
    echo -e " ${COLOR_GREEN}🔔${CoR} Valid certificate found for ${COLOR_YELLOW}$DOMAIN${CoR} (Certificate ID: ${COLOR_ORANGE}$CERT_ID${CoR}, expires in ${COLOR_YELLOW}$((($(date -d "$CERT_EXPIRES" +%s) - $(date +%s)) / 86400))${CoR} days)"
    # Reuse it for --host-ssl-enable
    GENERATED_CERT_ID="$CERT_ID"
    return 0
  fi

  # 5. Display parameters and confirmation
  echo -e "\n ${COLOR_CYAN}📝${CoR} Certificate generation parameters:"
  echo -e "    • Domain: ${COLOR_YELLOW}$DOMAIN${CoR}"
  echo -e "    • Email: ${COLOR_YELLOW}$EMAIL${CoR}"
  if [ -n "$DNS_PROVIDER" ]; then
    echo -e "  • DNS Provider: ${COLOR_YELLOW}$DNS_PROVIDER${CoR}"
  fi

  # 6. Confirmation
  if [ "$AUTO_YES" = true ]; then
    echo -e "\n ${COLOR_YELLOW}🔔 The -y option was provided.${CoR} AUTO Yes activate.${CoR}"
    CONFIRM="y"
  else
    echo -en " ${COLOR_RED}❓${CoR} No existing certificate found for ${COLOR_YELLOW}$DOMAIN${CoR}. Create new Let's Encrypt certificate? (y/n): "
    read -n 1 -r CONFIRM
    echo                                                    # New line after response
    CONFIRM=${CONFIRM:-y}                                   # Default to 'y' if empty
    CONFIRM=$(echo "$CONFIRM" | tr '[:upper:]' '[:lower:]') # Convert to lowercase
  fi

  if [[ "$CONFIRM" != "y" ]]; then
    echo -e "${COLOR_RED} ❌ Certificate creation aborted.${CoR}\n"
    exit 0
  fi

  # 7. Prepare request data
  echo -e " ${COLOR_YELLOW}🔔 Initiating certificate generation ${COLOR_GREEN}$DOMAIN${CoR}"
  echo -e " ${COLOR_CYAN}🚀 Sending certificate generation request${CoR}"
  echo -e " ${COLOR_ORANGE}⏳ This process may take a few minutes...${CoR}"

  # NPM >= 2.13 takes the Let's Encrypt email from the NPM user account and
  # rejects meta.letsencrypt_email / meta.letsencrypt_agree
  local npm_ver legacy_le=false
  npm_ver=$(curl -s --max-redirs 0 "$BASE_URL/" | jq -r '"\(.version.major // 0).\(.version.minor // 0)"' 2>/dev/null || echo "0.0")
  # Unknown version (0.0) is treated as current NPM
  if [ "$npm_ver" != "0.0" ] && [ $((${npm_ver%%.*} * 1000 + ${npm_ver#*.})) -lt 2013 ]; then
    legacy_le=true
  else
    echo -e " 📧 ${COLOR_GREY}NPM $npm_ver uses the email of the NPM user account for Let's Encrypt${CoR}"
  fi

  if [ "$IS_WILDCARD" = true ]; then
    echo -e " 🔑 Using DNS challenge with provider: $DNS_PROVIDER"
    # NPM writes the credentials as-is into a certbot INI file: convert JSON to "key = value" lines
    local dns_credentials_ini="$DNS_CREDENTIALS_JSON"
    if echo "$DNS_CREDENTIALS_JSON" | jq -e 'type == "object"' >/dev/null 2>&1; then
      # Cloudflare Global API Keys are 37 hex chars; anything else given as api_key
      # (e.g. "cfut_..." tokens) is an API token, which certbot expects as api_token
      if [[ "${DNS_PROVIDER,,}" == "cloudflare" ]] && echo "$DNS_CREDENTIALS_JSON" | jq -e \
        '(.dns_cloudflare_api_token == null) and ((.dns_cloudflare_api_key // "") | test("^[0-9a-fA-F]{37}$") | not) and (.dns_cloudflare_api_key != null)' >/dev/null 2>&1; then
        echo -e " ⚠️ ${COLOR_YELLOW}dns_cloudflare_api_key is not a Global API Key (37 hex chars): sending it as dns_cloudflare_api_token${CoR}"
        DNS_CREDENTIALS_JSON=$(echo "$DNS_CREDENTIALS_JSON" | jq -c '{dns_cloudflare_api_token: .dns_cloudflare_api_key}')
      fi
      dns_credentials_ini=$(echo "$DNS_CREDENTIALS_JSON" | jq -r 'to_entries[] | "\(.key) = \(.value)"')
    fi
    REQUEST_DATA=$(jq -n \
      --arg domain "$DOMAIN" \
      --arg dns_provider "$DNS_PROVIDER" \
      --arg credentials "$dns_credentials_ini" \
      '{
                provider: "letsencrypt",
                domain_names: [$domain],
                meta: {
                    dns_challenge: true,
                    dns_provider: $dns_provider,
                    dns_provider_credentials: $credentials,
                    propagation_seconds: 60
                }
            }')
  else
    REQUEST_DATA=$(jq -n \
      --arg domain "$DOMAIN" \
      '{
                provider: "letsencrypt",
                domain_names: [$domain],
                meta: {}
            }')
  fi
  if [ "$legacy_le" = true ]; then
    REQUEST_DATA=$(echo "$REQUEST_DATA" | jq --arg email "$EMAIL" \
      '.meta += {letsencrypt_agree: true, letsencrypt_email: $email}')
  fi

  # 8. Send request and handle response
  HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X POST "$BASE_URL/nginx/certificates" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json" \
    --data "$REQUEST_DATA")

  HTTP_BODY=${HTTP_RESPONSE//HTTPSTATUS:*/}
  HTTP_STATUS=${HTTP_RESPONSE##*HTTPSTATUS:}

  if [ "${HTTP_STATUS:-0}" -eq 201 ]; then
    CERT_ID=$(echo "$HTTP_BODY" | jq -r '.id')
    echo -e "\n ✅ ${COLOR_GREEN}Certificate generation initiated successfully!${CoR}"
    echo -e " 📋 Certificate Details:"
    echo -e "  • Certificate ID: ${COLOR_YELLOW}$CERT_ID${CoR}"
    echo -e "  • Status: ${COLOR_GREEN}Created${CoR}"
    echo -e "  • Domain: ${COLOR_YELLOW}$DOMAIN${CoR}"
    echo -e "  • Provider: ${COLOR_YELLOW}Let's Encrypt${CoR}\n"

    # Export variables for host_ssl_enable
    export GENERATED_CERT_ID="$CERT_ID"
    export DOMAIN_EXISTS

    if [ "$HOST_SSL_ENABLE" = true ]; then
      echo -e "\n ⏳ ${COLOR_YELLOW}Waiting for certificate propagation (30 seconds)...${CoR}"
      sleep 30

      if ! check_certificate_exists "$DOMAIN"; then
        echo -e "\n ⛔ ${COLOR_RED}ERROR: Certificate not found after generation${CoR}"
        exit 1
      fi

    fi
    #return 0
  else
    echo -e "\n ❌ ${COLOR_RED}Certificate generation failed!${CoR}"
    ERROR_MSG=$(echo "$HTTP_BODY" | jq -r '.error.message // "Unknown error"')
    echo -e " ⛔ Error: ${COLOR_RED}$ERROR_MSG${CoR}"

    DEBUG_STACK=$(echo "$HTTP_BODY" | jq -r '.debug.stack[]? // empty')
    if [ -n "$DEBUG_STACK" ]; then
      echo -e "\n 🔍 Debug Stack:"
      echo "$DEBUG_STACK" | while read -r line; do
        echo -e "  • ${COLOR_YELLOW}$line${CoR}"
      done
    fi

    echo -e "\n ${COLOR_CYAN}🔍${CoR} Troubleshooting suggestions:"
    echo -e "  • Verify domain DNS records are properly configured"
    echo -e "  • Ensure domain is accessible via HTTP/HTTPS"
    echo -e "  • Check if Let's Encrypt rate limits are not exceeded"
    echo -e "  • Verify Nginx Proxy Manager is properly configured"
    echo -e "  • Check if port 80 is open and accessible"
    echo -e "  • Ensure no firewall is blocking access"
    echo -e "  • Check Nginx Proxy Manager logs for more details"

    echo -e "\n ${COLOR_CYAN}💡${CoR} You can try:"
    echo -e "  • Wait a few minutes and try again (DNS propagation)"
    echo -e "  • Check Nginx Proxy Manager logs:"
    echo -e "    ${COLOR_GREEN}docker logs nginx-proxy-manager${CoR}"
    echo -e "  • Check Let's Encrypt logs:"
    echo -e "    ${COLOR_GREEN}docker exec nginx-proxy-manager cat /data/logs/letsencrypt.log${CoR}"
    if [ "$IS_WILDCARD" = true ]; then
      echo -e "  • DNS challenge: check the --dns-credentials keys expected by the provider plugin"
      echo -e "    (Cloudflare: dns_cloudflare_api_token, or dns_cloudflare_email + dns_cloudflare_api_key for the Global API Key)"
    fi

    echo -e "\n 📋 Debug Information:"
    echo -e "  • HTTP Status: $HTTP_STATUS"
    echo -e "  • Response: $HTTP_BODY"
    # Never print DNS provider secrets
    echo -e "  • Request Data: $(echo "$REQUEST_DATA" | jq -c 'if .meta.dns_provider_credentials then .meta.dns_provider_credentials = "***" else . end')"

    return 1
  fi
}

################################
# Enable SSL for a proxy host
host_ssl_enable() {
  local HOST_ID="${1:-}"
  local CERT_ID="${2:-}"

  if [ "$CERT_GENERATE" = true ]; then
    if [ -z "$DOMAIN_EXISTS" ]; then
      echo -e "\n ⛔ ${COLOR_RED}ERROR: No proxy host found for ${COLOR_YELLOW}$CERT_DOMAIN${CoR}"
      echo -e "    Enable SSL manually: ${COLOR_ORANGE}$0 --host-ssl-enable <host_id> ${GENERATED_CERT_ID:-<cert_id>}${CoR}\n"
      exit 1
    fi
    if [ -z "$GENERATED_CERT_ID" ]; then
      echo -e "\n ⛔ ${COLOR_RED}ERROR: No certificate ID available${CoR}"
      exit 1
    fi
    HOST_ID="$DOMAIN_EXISTS"
    CERT_ID="$GENERATED_CERT_ID"
  else
    if [ -z "$HOST_ID" ]; then
      echo -e "\n ⛔ ${COLOR_RED}ERROR  : The --host-ssl-enable option requires a host 🆔${CoR}"
      echo -e "    Usage  : ${COLOR_ORANGE}$0 --host-ssl-enable <host_id> <cert_id>${CoR}"
      echo -e "    Example: ${COLOR_GREEN}$0 --host-ssl-enable 42 240${CoR}\n"
      exit 1
    fi
    if [ -z "$CERT_ID" ]; then
      echo -e "\n ⛔ ${COLOR_RED}ERROR: Certificate ID is required${CoR}"
      echo -e "    Usage  : ${COLOR_ORANGE}$0 --host-ssl-enable <host_id> <cert_id>${CoR}"
      echo -e "    Example: ${COLOR_GREEN}$0 --host-ssl-enable 42 240${CoR}\n"
      exit 1
    fi
  fi
  # Quick check if host exists
  check_token_notverbose
  local CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$(echo "$CHECK_RESPONSE" | jq -r .id)" = "null" ]; then
    echo -e " ${COLOR_RED}❌${CoR} Host ID $HOST_ID not found"
    return 1
  fi

  # Get host domain and current certificate ID
  local HOST_DOMAIN=$(echo "$CHECK_RESPONSE" | jq -r '.domain_names[0]')

  # Update SSL configuration
  local DATA=$(jq -n \
    --arg cert_id "$CERT_ID" \
    '{
            "certificate_id": ($cert_id|tonumber),
            "ssl_forced": true,
            "http2_support": true
        }')

  local HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    --data-raw "$DATA")

  local HTTP_BODY=${HTTP_RESPONSE//HTTPSTATUS:*/}
  local HTTP_STATUS=${HTTP_RESPONSE##*HTTPSTATUS:}

  if [ "${HTTP_STATUS:-0}" -eq 200 ]; then
    echo -e "\n ✅ ${COLOR_GREEN}SSL enabled successfully for${CoR} ${COLOR_YELLOW}$HOST_DOMAIN${CoR} (ID: ${COLOR_CYAN}$HOST_ID${CoR}) (Cert ID: ${COLOR_CYAN}$CERT_ID${CoR})\n"
    return 0
    #exit 0
  else
    echo -e "\n ⛔ ${COLOR_RED}Failed to enable SSL. HTTP status: $HTTP_STATUS${CoR}\n"
    echo -e " 📋 Error details: $HTTP_BODY \n"
    return 1
  fi

}

################################
# disable_ssl
host_ssl_disable() {
  if [ -z "$HOST_ID" ]; then
    echo -e "\n ⛔ ${COLOR_RED}INVALID command: Missing argument${CoR}"
    echo -e "    Usage  : ${COLOR_ORANGE}$0 --host-ssl-disable <host_id>${CoR}"
    echo -e "    Find ID: ${COLOR_ORANGE}$0 --host-list${CoR}\n"
    exit 1
  fi
  check_token_notverbose

  CHECK_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if echo "$CHECK_RESPONSE" | jq -e '.id' >/dev/null 2>&1; then
    DATA=$(jq -n --argjson cert_id null '{
            certificate_id: $cert_id,
            ssl_forced: false,
            http2_support: false,
            hsts_enabled: false,
            hsts_subdomains: false
        }')

    HTTP_RESPONSE=$(curl -s -w "HTTPSTATUS:%{http_code}" -X PUT "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
      -H "Content-Type: application/json; charset=UTF-8" \
      --data-raw "$DATA")

    HTTP_BODY=${HTTP_RESPONSE//HTTPSTATUS:*/}
    HTTP_STATUS=${HTTP_RESPONSE##*HTTPSTATUS:}

    if [ "${HTTP_STATUS:-0}" -eq 200 ]; then
      echo -e "\n 🚫 Disabling 🔓 SSL for proxy 🆔${COLOR_YELLOW}$HOST_ID${CoR}"
      echo -e " ✅ ${COLOR_GREEN}SSL disabled successfully!${CoR} 🆔${COLOR_CYAN}$HOST_ID${CoR}\n"
    else
      echo " Data sent: $DATA" # Log the data sent
      echo -e " ⛔ ${COLOR_RED}Failed to disable SSL. HTTP status: $HTTP_STATUS. Response: $HTTP_BODY${CoR}\n"
    fi
  else
    echo -e " ⛔ ${COLOR_RED}Proxy host with ID $HOST_ID does not exist.${CoR}\n"
  fi
}

################################
# Create a new access list with various options
# Usage:
#   access_list_create <name> [options]
# Options:
#   --auth <username> <password>  Add basic authentication
#   --access allow|deny <ip>      Add IP access rule (legacy syntax)
#   --allow "ip1,ip2"            Add allowed IPs/ranges (comma-separated)
#   --deny "ip1,ip2"             Add denied IPs/ranges (comma-separated)
#   --users "user1,user2"        Add users with password prompts (comma-separated)
#   --satisfy any|all            Set satisfy condition (default: all)
#   --pass-auth                  Enable pass auth
access_list_create() {
  check_token_notverbose

  if [ $# -lt 2 ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: Insufficient arguments${CoR}"
    echo -e "   ${COLOR_CYAN}Usage:${CoR}"
    echo -e "    ${COLOR_ORANGE}$0 --access-list-create <name> [options]${CoR}"
    echo -e "\n   ${COLOR_CYAN}Available options:${CoR}"
    echo -e "     ${COLOR_GREEN}--satisfy [any|all]${CoR}          Set access list satisfaction mode"
    echo -e "     ${COLOR_GREEN}--pass-auth [true|false]${CoR}     Enable/disable password authentication"
    echo -e "     ${COLOR_GREEN}--users \"user1,user2\"${CoR}        List of users (comma-separated)"
    echo -e "     ${COLOR_GREEN}--allow \"ip1,ip2\"${CoR}            List of allowed IPs/ranges"
    echo -e "     ${COLOR_GREEN}--deny \"ip1,ip2\"${CoR}             List of denied IPs/ranges"
    echo -e "     ${COLOR_GREEN}--auth <username> <password>${CoR}  Add authentication user"
    echo -e "     ${COLOR_GREEN}--access allow|deny <ip>${CoR}      Add single IP rule"
    echo -e "\n   ${COLOR_CYAN}Examples:${CoR}"
    echo -e "    ${COLOR_GREEN}$0 --access-list-create secure_area --auth admin secret123${CoR}"
    echo -e "    ${COLOR_GREEN}$0 --access-list-create office --allow \"192.168.1.0/24\"${CoR}"
    echo -e "    ${COLOR_GREEN}$0 --access-list-create full_options --users \"user1,user2\" --allow \"10.0.0.0/8\" --satisfy any --pass-auth true${CoR}\n"
    return 1
  fi

  local NAME="$1"
  shift

  # Initialize variables
  local SATISFY_ANY="false"
  local PASS_AUTH="false"
  local AUTH_ITEMS="[]"
  local IP_CLIENTS="[]"

  echo -e "\n🔑 Creating access list: ${COLOR_GREEN}$NAME${CoR}"

  # Process all arguments
  while [ $# -gt 0 ]; do
    case "$1" in
    --auth)
      if [ $# -lt 3 ]; then
        echo -e "\n ⛔ ${COLOR_RED}ERROR: --auth requires username and password${CoR}"
        return 1
      fi
      AUTH_ITEMS=$(echo "$AUTH_ITEMS" | jq --arg user "$2" --arg pass "$3" '. + [{
                    username: $user,
                    password: $pass
                }]')
      shift 3
      ;;
    --access)
      if [ $# -lt 3 ]; then
        echo -e "\n ⛔ ${COLOR_RED}ERROR: --access requires allow/deny and IP${CoR}"
        return 1
      fi
      if [[ ! "$2" =~ ^(allow|deny)$ ]]; then
        echo -e "\n ⛔ ${COLOR_RED}ERROR: Invalid access type. Must be 'allow' or 'deny'${CoR}"
        return 1
      fi
      IP_CLIENTS=$(echo "$IP_CLIENTS" | jq --arg ip "$3" --arg dir "$2" '. + [{
                    address: $ip,
                    directive: $dir
                }]')
      shift 3
      ;;
    --allow)
      if [ $# -lt 2 ]; then
        echo -e "\n ⛔ ${COLOR_RED}ERROR: --allow requires IP addresses/ranges${CoR}"
        return 1
      fi
      # Split comma-separated IPs and add each one
      IFS=',' read -ra IPS <<<"$2"
      for ip in "${IPS[@]}"; do
        ip=$(echo "$ip" | xargs) # trim whitespace
        IP_CLIENTS=$(echo "$IP_CLIENTS" | jq --arg ip "$ip" '. + [{
                        address: $ip,
                        directive: "allow"
                    }]')
      done
      shift 2
      ;;
    --deny)
      if [ $# -lt 2 ]; then
        echo -e "\n ⛔ ${COLOR_RED}ERROR: --deny requires IP addresses/ranges${CoR}"
        return 1
      fi
      # Split comma-separated IPs and add each one
      IFS=',' read -ra IPS <<<"$2"
      for ip in "${IPS[@]}"; do
        ip=$(echo "$ip" | xargs) # trim whitespace
        IP_CLIENTS=$(echo "$IP_CLIENTS" | jq --arg ip "$ip" '. + [{
                        address: $ip,
                        directive: "deny"
                    }]')
      done
      shift 2
      ;;
    --users)
      if [ $# -lt 2 ]; then
        echo -e "\n ⛔ ${COLOR_RED}ERROR: --users requires user list${CoR}"
        return 1
      fi
      # Split comma-separated users and add each one (will need password prompt or default)
      IFS=',' read -ra USERS <<<"$2"
      for user in "${USERS[@]}"; do
        user=$(echo "$user" | xargs) # trim whitespace
        echo -e "  🔐 Enter password for user ${COLOR_CYAN}$user${CoR}:"
        read -s password
        echo
        AUTH_ITEMS=$(echo "$AUTH_ITEMS" | jq --arg user "$user" --arg pass "$password" '. + [{
                        username: $user,
                        password: $pass
                    }]')
      done
      shift 2
      ;;
    --satisfy)
      if [ $# -lt 2 ]; then
        echo -e "\n ⛔ ${COLOR_RED}ERROR: --satisfy requires any/all${CoR}"
        return 1
      fi
      if [ "$2" = "any" ]; then
        SATISFY_ANY="true"
      elif [ "$2" = "all" ]; then
        SATISFY_ANY="false"
      else
        echo -e "\n ⛔ ${COLOR_RED}ERROR: Invalid satisfy value. Must be 'any' or 'all'${CoR}"
        return 1
      fi
      shift 2
      ;;
    --pass-auth)
      if [ $# -lt 2 ] || { [ "$2" != "true" ] && [ "$2" != "false" ]; }; then
        echo -e "\n ⛔ ${COLOR_RED}ERROR: --pass-auth requires true/false${CoR}"
        return 1
      fi
      PASS_AUTH="$2"
      shift 2
      ;;
    *)
      echo -e "\n ⛔ ${COLOR_RED}ERROR: Unknown option $1${CoR}"
      return 1
      ;;
    esac
  done

  # Check that at least one rule is defined
  if [ "$AUTH_ITEMS" = "[]" ] && [ "$IP_CLIENTS" = "[]" ]; then
    echo -e "\n ⛔ ${COLOR_RED}ERROR: At least one --auth or --access rule is required${CoR}"
    return 1
  fi

  # Build payload
  local PAYLOAD=$(jq -n \
    --arg name "$NAME" \
    --argjson satisfy_any "$SATISFY_ANY" \
    --argjson pass_auth "$PASS_AUTH" \
    --argjson items "$AUTH_ITEMS" \
    --argjson clients "$IP_CLIENTS" \
    '{
            name: $name,
            satisfy_any: $satisfy_any,
            pass_auth: $pass_auth,
            items: $items,
            clients: $clients
        }')

  # Create access list via API
  RESPONSE=$(curl -s -X POST "$BASE_URL/nginx/access-lists" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json" \
    -d "$PAYLOAD")

  # Check for errors
  if [ "$(echo "$RESPONSE" | jq -r '.error.message // empty')" != "" ]; then
    echo -e " ⛔ ${COLOR_RED}Failed to create access list${CoR}"
    echo -e "    Error: $(echo "$RESPONSE" | jq -r '.error.message')"
    return 1
  fi

  # Display results
  local NEW_ID=$(echo "$RESPONSE" | jq -r '.id')
  echo -e " ✅ ${COLOR_GREEN}Access list created successfully!${CoR}"
  echo -e " ┌───────────────────────────────────────────"
  echo -e " │ ID: ${COLOR_YELLOW}$NEW_ID${CoR}"
  echo -e " │ Name: ${COLOR_GREEN}$NAME${CoR}"
  echo -e " │ Satisfy: ${COLOR_CYAN}$([ "$SATISFY_ANY" = "true" ] && echo "any" || echo "all")${CoR}"
  echo -e " │ Pass Auth: ${COLOR_CYAN}$([ "$PASS_AUTH" = "true" ] && echo "yes" || echo "no")${CoR}"

  if [ "$AUTH_ITEMS" != "[]" ]; then
    echo -e " │ 👤 Authentication Rules:"
    echo "$AUTH_ITEMS" | jq -r '.[] | " │  • User: \(.username)"'
  fi

  if [ "$IP_CLIENTS" != "[]" ]; then
    echo -e " │ 🌐 Access Rules:"
    echo "$IP_CLIENTS" | jq -r '.[] | " │  • \(.directive) \(.address)"'
  fi
  echo -e " └───────────────────────────────────────────"
}

# Update an existing access list with various options
# Usage:
#   access_list_update <access_list_id> [options]
# Options:
#   --name "new_name"            Update access list name
#   --satisfy any|all           Update satisfaction mode
#   --pass-auth true|false      Update password authentication
#   --allow "ip1,ip2"           Add allowed IPs/ranges (comma-separated)
#   --deny "ip1,ip2"            Add denied IPs/ranges (comma-separated)
#   --users "user1,user2"       Add users with password prompts (comma-separated)
access_list_update() {
  check_token_notverbose

  if [ -z "$ACCESS_LIST_ID" ]; then
    echo -e "\n ⛔ ${COLOR_RED}Error: ACCESS_LIST_ID is required.${CoR}"
    echo -e "    Usage: $0 --access-list-update <access_list_id> [options]"
    return 1
  fi

  local access_list_id="$ACCESS_LIST_ID"

  # Get the current access list details with expanded items and clients
  # Note: The expand parameter is required to get full details of items and clients
  local current_list=$(curl -s -X GET "$BASE_URL/nginx/access-lists/$access_list_id?expand=items%2Cclients" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$(echo "$current_list" | jq -r '.error | length')" -ne 0 ]; then
    echo -e " ⛔ ${COLOR_RED}Failed to fetch access list details. Error: $(echo "$current_list" | jq -r '.error')${CoR}"
    return 1
  fi

  # Extract current values with proper null handling
  local current_name=$(echo "$current_list" | jq -r '.name // "unnamed"')
  local current_satisfy_any=$(echo "$current_list" | jq -r '.satisfy_any // false')
  local current_pass_auth=$(echo "$current_list" | jq -r '.pass_auth // false')
  # Keep only the fields accepted by PUT (GET adds id, hint, created_on...);
  # an empty password tells NPM to keep the existing one
  local current_items=$(echo "$current_list" | jq '[(.items // [])[] | {username, password: ""}]')
  local current_clients=$(echo "$current_list" | jq '[(.clients // [])[] | {address, directive}]')

  echo -e "\n🔑 ${COLOR_CYAN}Updating access list ID: ${COLOR_YELLOW}$access_list_id${CoR}"
  echo -e "\n${COLOR_CYAN}Current Access List Details:${CoR}"
  echo -e "Name: $current_name"
  echo -e "Satisfy Any: $current_satisfy_any"
  echo -e "Pass Auth: $current_pass_auth"

  # Initialize variables with current values
  local new_name="$current_name"
  local satisfy_any="$current_satisfy_any"
  local pass_auth="$current_pass_auth"
  local items="$current_items"
  local clients="$current_clients"

  # Process command line arguments if provided
  if [ $# -gt 0 ]; then
    echo -e "\n${COLOR_CYAN}Processing command line arguments...${CoR}"

    while [ $# -gt 0 ]; do
      case "$1" in
      --name)
        if [ $# -lt 2 ]; then
          echo -e "\n ⛔ ${COLOR_RED}ERROR: --name requires a value${CoR}"
          return 1
        fi
        new_name="$2"
        echo -e "  📝 Setting name to: ${COLOR_GREEN}$new_name${CoR}"
        shift 2
        ;;
      --satisfy)
        if [ $# -lt 2 ]; then
          echo -e "\n ⛔ ${COLOR_RED}ERROR: --satisfy requires any/all${CoR}"
          return 1
        fi
        if [ "$2" = "any" ]; then
          satisfy_any="true"
          echo -e "  🔄 Setting satisfy to: ${COLOR_GREEN}any${CoR}"
        elif [ "$2" = "all" ]; then
          satisfy_any="false"
          echo -e "  🔄 Setting satisfy to: ${COLOR_GREEN}all${CoR}"
        else
          echo -e "\n ⛔ ${COLOR_RED}ERROR: Invalid satisfy value. Must be 'any' or 'all'${CoR}"
          return 1
        fi
        shift 2
        ;;
      --pass-auth)
        if [ $# -lt 2 ]; then
          echo -e "\n ⛔ ${COLOR_RED}ERROR: --pass-auth requires true/false${CoR}"
          return 1
        fi
        if [ "$2" = "true" ] || [ "$2" = "false" ]; then
          pass_auth="$2"
          echo -e "  🔓 Setting pass auth to: ${COLOR_GREEN}$pass_auth${CoR}"
        else
          echo -e "\n ⛔ ${COLOR_RED}ERROR: Invalid pass auth value. Must be 'true' or 'false'${CoR}"
          return 1
        fi
        shift 2
        ;;
      --allow)
        if [ $# -lt 2 ]; then
          echo -e "\n ⛔ ${COLOR_RED}ERROR: --allow requires IP addresses/ranges${CoR}"
          return 1
        fi
        # Split comma-separated IPs and add each one
        IFS=',' read -ra IPS <<<"$2"
        for ip in "${IPS[@]}"; do
          ip=$(echo "$ip" | xargs) # trim whitespace
          clients=$(echo "$clients" | jq --arg ip "$ip" '. + [{
                            address: $ip,
                            directive: "allow"
                        }]')
        done
        echo -e "  ✅ Added allow rules for: ${COLOR_GREEN}$2${CoR}"
        shift 2
        ;;
      --deny)
        if [ $# -lt 2 ]; then
          echo -e "\n ⛔ ${COLOR_RED}ERROR: --deny requires IP addresses/ranges${CoR}"
          return 1
        fi
        # Split comma-separated IPs and add each one
        IFS=',' read -ra IPS <<<"$2"
        for ip in "${IPS[@]}"; do
          ip=$(echo "$ip" | xargs) # trim whitespace
          clients=$(echo "$clients" | jq --arg ip "$ip" '. + [{
                            address: $ip,
                            directive: "deny"
                        }]')
        done
        echo -e "  ✅ Added deny rules for: ${COLOR_GREEN}$2${CoR}"
        shift 2
        ;;
      --users)
        if [ $# -lt 2 ]; then
          echo -e "\n ⛔ ${COLOR_RED}ERROR: --users requires user list${CoR}"
          return 1
        fi
        # Split comma-separated users and add each one (will need password prompt or default)
        IFS=',' read -ra USERS <<<"$2"
        for user in "${USERS[@]}"; do
          user=$(echo "$user" | xargs) # trim whitespace
          echo -e "  🔐 Enter password for user ${COLOR_CYAN}$user${CoR}:"
          read -s password
          echo
          items=$(echo "$items" | jq --arg user "$user" --arg pass "$password" '. + [{
                            username: $user,
                            password: $pass
                        }]')
        done
        echo -e "  ✅ Added users: ${COLOR_GREEN}$2${CoR}"
        shift 2
        ;;
      *)
        echo -e "\n ⛔ ${COLOR_RED}ERROR: Unknown option $1${CoR}"
        echo -e "   ${COLOR_CYAN}Available options:${CoR}"
        echo -e "     ${COLOR_GREEN}--name <new_name>${CoR}           Update access list name"
        echo -e "     ${COLOR_GREEN}--satisfy any|all${CoR}          Update satisfaction mode"
        echo -e "     ${COLOR_GREEN}--pass-auth true|false${CoR}     Update pass auth setting"
        echo -e "     ${COLOR_GREEN}--allow \"ip1,ip2\"${CoR}         Update allowed IPs/ranges"
        echo -e "     ${COLOR_GREEN}--deny \"ip1,ip2\"${CoR}          Update denied IPs/ranges"
        echo -e "     ${COLOR_GREEN}--users \"user1,user2\"${CoR}     Update list of users"
        return 1
        ;;
      esac
    done
  else
    # Interactive mode if no arguments provided
    echo -e "\n${COLOR_CYAN}No arguments provided, using current values.${CoR}"
    echo -e "💡 ${COLOR_YELLOW}Tip: Use --name, --satisfy, --auth-type, or --pass-auth options for non-interactive updates${CoR}"
  fi

  # Prepare the JSON payload using jq for proper formatting (same structure as create)
  local payload=$(jq -n \
    --arg name "$new_name" \
    --argjson satisfy_any "$satisfy_any" \
    --argjson pass_auth "$pass_auth" \
    --argjson items "$items" \
    --argjson clients "$clients" \
    '{
            name: $name,
            satisfy_any: $satisfy_any,
            pass_auth: $pass_auth,
            items: $items,
            clients: $clients
        }')

  # Update the access list
  local response=$(curl -s -X PUT "$BASE_URL/nginx/access-lists/$access_list_id" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
    -H "Content-Type: application/json; charset=UTF-8" \
    -d "$payload")

  if [ "$(echo "$response" | jq -r '.error | length')" -eq 0 ]; then
    echo -e "\n ✅ ${COLOR_GREEN}Access list updated successfully!${CoR}"
    echo -e "\n${COLOR_CYAN}Updated Access List Details:${CoR}"
    echo -e "ID: $access_list_id"
    echo -e "Name: $new_name"
    echo -e "Satisfy: $([ "$satisfy_any" = "true" ] && echo "any" || echo "all")"
    echo -e "Pass Auth: $pass_auth"
  else
    echo -e "\n ⛔ ${COLOR_RED}Failed to update access list. Error: $(echo "$response" | jq -r '.error')${CoR}"
    return 1
  fi
}

################################
# Delete an access list
access_list_delete() {

  if [ -z "$ACCESS_LIST_ID" ]; then
    echo -e "\n ⛔ ${COLOR_RED}Error: ACCESS_LIST_ID is required.${CoR}"
    echo -e "    Usage: $0 --access-list-delete <access_list_id> [-y]"
    exit 1
  fi
  check_token_notverbose
  echo -e " 🔍 Checking access list ID: ${COLOR_YELLOW}$ACCESS_LIST_ID${CoR}"

  # Check if access list exists
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/access-lists/$ACCESS_LIST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$(echo "$RESPONSE" | jq -r '.error.code')" = "404" ]; then
    echo -e " ⛔ ${COLOR_RED}Access list ID $ACCESS_LIST_ID not found${CoR}"
    exit 1
  fi

  # Show details before deletion
  echo -e " ┌───────────────────────────────────────────"
  echo -e " │ ID: ${COLOR_YELLOW}$ACCESS_LIST_ID${CoR}"
  echo -e " │ Name: ${COLOR_GREEN}$(echo "$RESPONSE" | jq -r '.name')${CoR}"
  echo -e " └───────────────────────────────────────────"

  # Confirm unless AUTO_YES
  if [ "$AUTO_YES" != true ]; then
    echo -e " ⚠️  ${COLOR_RED}WARNING: This action cannot be undone!${CoR}"
    read -n 1 -r -p " 🔔 Confirm deletion? (y/n): " CONFIRM
    echo
    if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then
      echo -e " ❌ ${COLOR_RED}Operation cancelled${CoR}"
      exit 1
    fi
  fi

  # Delete access list
  RESPONSE=$(curl -s -X DELETE "$BASE_URL/nginx/access-lists/$ACCESS_LIST_ID" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ "$RESPONSE" = "true" ]; then
    echo -e " ✅ ${COLOR_GREEN}Access list successfully deleted! ${CoR}🗑️ "
  else
    echo -e " ⛔ ${COLOR_RED}Failed to delete access list.${CoR}"
    if [ -n "$RESPONSE" ]; then
      echo -e "    Error: $RESPONSE"
    fi
    exit 1
  fi
}

################################
# Show all access lists with detailed information

################################
# Show all access lists with detailed information
access_list() {
  check_token_notverbose

  # Get all access lists
  RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/access-lists" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  # Check for API errors
  if [ "$(echo "$RESPONSE" | jq -r 'if type=="object" then .error.message else empty end')" != "" ]; then
    if [ "$JSON_OUTPUT" = true ]; then
      echo "$RESPONSE" | jq '{error: (.error.message // "Failed to fetch access lists")}'
      exit 1
    fi
    echo -e " ⛔ ${COLOR_RED}Failed to fetch access lists${CoR}"
    echo -e "    Error: $(echo "$RESPONSE" | jq -r '.error.message')"
    return 1
  fi

  if [ "$JSON_OUTPUT" = true ]; then
    echo "$RESPONSE" | jq .
    exit 0
  fi

  echo -e "\n📋 ${COLOR_CYAN}Access Lists Management${CoR}\n"

  # Display table header
  echo "┌════════════════════════════════════════════════════════════════════════════════════┐"
  echo -e "│ ${COLOR_CYAN}ID  │ Name                   │ Authorization │ Access   │ Satisfy │ Proxy Hosts    ${CoR}│"
  echo "├════════════════════════════════════════════════════════════════════════════════════┤"

  # Process each access list and format output
  echo "$RESPONSE" | jq -r '.[] | "\(.id)|\(.name)|\(if .items then .items|length else 0 end) User\(if (.items|length//0) != 1 then "s" else "" end)|\(if .clients then .clients|length else 0 end) Rule\(if (.clients|length//0) != 1 then "s" else "" end)|\(.satisfy_any)|\(.proxy_host_count // 0)"' |
    while IFS="|" read -r id name users rules satisfy proxy_hosts; do
      # Format satisfy display (Any/All)
      satisfy_display=$([ "$satisfy" = "true" ] && echo "Any" || echo "All")

      # Print formatted line (name truncated to column width; count guarded above)
      printf "│ %-3s │ %s │ %-13s │ %-8s │ %-7s │ %-15s│\n" \
        "$id" \
        "$(truncate_pad "$name" 22)" \
        "$users" \
        "$rules" \
        "$satisfy_display" \
        "$proxy_hosts Proxy Hosts"
    done

  # Close table
  echo "└════════════════════════════════════════════════════════════════════════════════════┘"

  # Display creation date info
  echo -e "\n${COLOR_CYAN}Note:${CoR} Use --access-list-show <id> to see detailed information about a specific access list\n"
}

################################
# Show detailed information for a specific access list
access_list_show() {
  local id="$1"
  check_token_notverbose

  if [ -z "$id" ]; then
    echo -e "\n⛔ ${COLOR_RED}Error: Access List ID is required${CoR}"
    echo -e "Usage: $0 --access-list-show <id>"
    return 1
  fi

  [ "$JSON_OUTPUT" = true ] || echo -e "\n📋 ${COLOR_CYAN}Access List Details${CoR}"

  # Get specific access list with expanded items and clients
  # Note: The expand parameter is required to get full details of items and clients
  local response=$(curl -s -X GET "$BASE_URL/nginx/access-lists/$id?expand=items%2Cclients" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  # Check if response is valid JSON
  if ! echo "$response" | jq empty 2>/dev/null; then
    if [ "$JSON_OUTPUT" = true ]; then
      echo '{"error": "Invalid response from API"}'
      exit 1
    fi
    echo -e "\n⛔ ${COLOR_RED}Invalid response from API${CoR}"
    return 1
  fi

  # Check if access list exists
  if [ "$(echo "$response" | jq 'has("error")')" = "true" ]; then
    if [ "$JSON_OUTPUT" = true ]; then
      echo '{"error": "Access List not found"}'
      exit 1
    fi
    echo -e "\n⛔ ${COLOR_RED}Access List not found${CoR}"
    return 1
  fi

  if [ "$JSON_OUTPUT" = true ]; then
    echo "$response" | jq .
    exit 0
  fi

  # Create horizontal border
  local h_border=$(printf '%*s' "80" '' | tr ' ' "=")

  # Display basic information
  echo -e "\n${COLOR_GREY}┌$h_border┐${CoR}"
  echo -e "${COLOR_GREY}│${CoR} ${COLOR_CYAN}Basic Information${CoR}"
  echo -e "${COLOR_GREY}├$h_border┤${CoR}"
  echo -e "${COLOR_GREY}│${CoR} ID:         ${COLOR_GREEN}$(echo "$response" | jq -r '.id')${CoR}"
  echo -e "${COLOR_GREY}│${CoR} Name:       ${COLOR_YELLOW}$(echo "$response" | jq -r '.name')${CoR}"
  echo -e "${COLOR_GREY}│${CoR} Auth Type:  ${COLOR_ORANGE}$(echo "$response" | jq -r '.auth_type // "none"')${CoR}"

  # Display authentication settings
  local pass_auth=$(echo "$response" | jq -r '.pass_auth')
  local satisfy=$(echo "$response" | jq -r '.satisfy_any')
  echo -e "${COLOR_GREY}│${CoR} Pass Auth:  $([ "$pass_auth" = "true" ] && echo "${COLOR_GREEN}✓${CoR}" || echo "${COLOR_RED}✗${CoR}")"
  echo -e "${COLOR_GREY}│${CoR} Satisfy:    ${COLOR_YELLOW}$([ "$satisfy" = "true" ] && echo "Any" || echo "All")${CoR}"

  # Display users
  echo -e "${COLOR_GREY}├$h_border┤${CoR}"
  echo -e "${COLOR_GREY}│${CoR} ${COLOR_CYAN}Authorized Users${CoR}"
  echo -e "${COLOR_GREY}├$h_border┤${CoR}"
  if [ "$(echo "$response" | jq 'has("items")')" = "true" ] && [ "$(echo "$response" | jq '.items != null')" = "true" ]; then
    local users_count=$(echo "$response" | jq '.items | length')
    if [ "$users_count" -gt 0 ]; then
      echo "$response" | jq -r '.items[] | "│ • \(.username)"'
    else
      echo -e "${COLOR_GREY}│${CoR} No users configured"
    fi
  else
    echo -e "${COLOR_GREY}│${CoR} No users configured"
  fi

  # Display IP whitelist
  echo -e "${COLOR_GREY}├$h_border┤${CoR}"
  echo -e "${COLOR_GREY}│${CoR} ${COLOR_CYAN}IP Whitelist${CoR}"
  echo -e "${COLOR_GREY}├$h_border┤${CoR}"
  if [ "$(echo "$response" | jq 'has("clients")')" = "true" ] && [ "$(echo "$response" | jq '.clients != null')" = "true" ]; then
    local ips_count=$(echo "$response" | jq '.clients | length')
    if [ "$ips_count" -gt 0 ]; then
      echo "$response" | jq -r '.clients[] | "│ • \(.address) (\(.directive // "allow"))"' |
        while IFS= read -r line; do
          if [[ $line == *"allow"* ]]; then
            echo -e "${COLOR_GREY}│${CoR} • ${COLOR_GREEN}${line#* • }${CoR}"
          else
            echo -e "${COLOR_GREY}│${CoR} • ${COLOR_RED}${line#* • }${CoR}"
          fi
        done
    else
      echo -e "${COLOR_GREY}│${CoR} No IPs whitelisted"
    fi
  else
    echo -e "${COLOR_GREY}│${CoR} No IPs whitelisted"
  fi

  # Close the box
  echo -e "${COLOR_GREY}└$h_border┘${CoR}"

  # Display legend
  echo -e "\n${COLOR_YELLOW}Legend:${CoR}"
  echo -e "  • Pass Auth: ${COLOR_GREEN}✓${CoR} = Enabled, ${COLOR_RED}✗${CoR} = Disabled"
  echo -e "  • IP Rules:  ${COLOR_GREEN}allow${CoR} = Allowed, ${COLOR_RED}deny${CoR} = Denied\n"
}

################################
## backup
# Function to make a full backup

full_backup() {
  check_dependencies
  check_nginx_access
  check_token_notverbose
  DATE=$(date +"_%Y_%m_%d__%H_%M_%S")
  echo -e "\n📦 ${COLOR_YELLOW}Starting full backup...${CoR}"
  # Initialize counters
  local users_count=0
  local certs_count=0
  local hosts_count=0
  local redirect_hosts_count=0
  local stream_hosts_count=0
  local dead_hosts_count=0
  local custom_certs_count=0
  local letsencrypt_certs_count=0
  local access_lists_count=0
  local success_count=0
  local error_count=0

  # Create main backup directory with timestamp
  BACKUP_PATH="$BACKUP_DIR"
  mkdir -p "$BACKUP_PATH"

  # Create required subdirectories
  echo -e "\n📂 ${COLOR_CYAN}Creating backup directories...${CoR}"
  for dir in ".user" ".settings" ".access_lists" ".Proxy_Hosts" ".Redirection_Hosts" ".Stream_Hosts" ".Dead_Hosts" ".ssl"; do
    mkdir -p "$BACKUP_PATH/$dir" || {
      echo -e " ⛔ ${COLOR_RED}Failed to create $dir directory${CoR}"
      return 1
    }
    echo -e " ✓ Created: ${COLOR_GREY}$BACKUP_PATH/$dir${CoR}"
  done

  # Initialize empty JSON for full configuration
  echo "{}" >"$BACKUP_PATH/full_config${DATE}.json"
  echo -e "\n🔄 ${COLOR_CYAN}Starting configuration backup...${CoR}"

  # 1. Backup Users
  #   trap 'echo "Error on line $LINENO"' ERR
  #   set -x  # Debug mode ON
  echo -e "\n👥 ${COLOR_CYAN}Backing up users...${CoR}"
  USERS_RESPONSE=$(curl -s -X GET "$BASE_URL/users" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ -n "$USERS_RESPONSE" ] && echo "$USERS_RESPONSE" | jq empty 2>/dev/null; then
    users_count=$(echo "$USERS_RESPONSE" | jq '. | length')
    # Save users to dedicated file
    echo "$USERS_RESPONSE" | jq '.' >"$BACKUP_PATH/.user/users_${NGINX_IP//./_}$DATE.json"
    # Add users to full configuration
    jq --argjson users "$USERS_RESPONSE" '. + {users: $users}' \
      "$BACKUP_PATH/full_config${DATE}.json" >"$BACKUP_PATH/full_config${DATE}.json.tmp"
    mv "$BACKUP_PATH/full_config${DATE}.json.tmp" "$BACKUP_PATH/full_config${DATE}.json"
    echo -e " ✅ ${COLOR_GREEN}Backed up $users_count users${CoR}"
    success_count=$((success_count + 1))
  else
    echo -e " ⚠️ ${COLOR_YELLOW}No users found or invalid response${CoR}"
    error_count=$((error_count + 1))
  fi
  #    trap - ERR  # Reset trap
  #    set +x  # Debug mode OFF

  # 2. Backup settings
  echo -e "\n⚙️  ${COLOR_CYAN}Backing up settings...${CoR}"
  SETTINGS_RESPONSE=$(curl -s -X GET "$BASE_URL/settings" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  #echo -e "\n🔍 DEBUG Settings Response: $SETTINGS_RESPONSE"  # Debug line
  if [ -n "$SETTINGS_RESPONSE" ] && echo "$SETTINGS_RESPONSE" | jq empty 2>/dev/null; then
    # Save settings to dedicated file
    echo "$SETTINGS_RESPONSE" | jq '.' >"$BACKUP_PATH/.settings/settings_${NGINX_IP//./_}$DATE.json"
    # Add settings to full configuration
    jq --argjson settings "$SETTINGS_RESPONSE" '. + {settings: $settings}' \
      "$BACKUP_PATH/full_config${DATE}.json" >"$BACKUP_PATH/full_config${DATE}.json.tmp"
    mv "$BACKUP_PATH/full_config${DATE}.json.tmp" "$BACKUP_PATH/full_config${DATE}.json"
    echo -e " ✅ ${COLOR_GREEN}Settings backed up successfully${CoR}"
    success_count=$((success_count + 1))
  else
    echo -e " ⚠️ ${COLOR_YELLOW}Invalid settings response${CoR}"
    error_count=$((error_count + 1))
  fi

  # 3. Backup access lists
  echo -e "\n🔑 ${COLOR_CYAN}Backing up access lists...${CoR}"
  # Get list of access list IDs first
  ACCESS_LISTS_IDS=$(curl -s -X GET "$BASE_URL/nginx/access-lists" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" | jq -r '.[].id' 2>/dev/null)

  if [ -n "$ACCESS_LISTS_IDS" ]; then
    access_lists_count=$(echo "$ACCESS_LISTS_IDS" | wc -l | tr -d ' ')
    # Initialize JSON array for complete access lists
    echo "[" >"$BACKUP_PATH/.access_lists/access_lists_${NGINX_IP//./_}$DATE.json"
    local first=true

    # Get each access list with expanded items and clients for complete backup
    # Note: The expand parameter is required to get full details of items and clients
    for list_id in $ACCESS_LISTS_IDS; do
      if [ "$first" = true ]; then
        first=false
      else
        echo "," >>"$BACKUP_PATH/.access_lists/access_lists_${NGINX_IP//./_}$DATE.json"
      fi

      curl -s -X GET "$BASE_URL/nginx/access-lists/$list_id?expand=items%2Cclients" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" >>"$BACKUP_PATH/.access_lists/access_lists_${NGINX_IP//./_}$DATE.json"
    done

    echo "]" >>"$BACKUP_PATH/.access_lists/access_lists_${NGINX_IP//./_}$DATE.json"

    # Verify JSON is valid
    if jq empty "$BACKUP_PATH/.access_lists/access_lists_${NGINX_IP//./_}$DATE.json" 2>/dev/null; then
      # Add access lists to full configuration
      ACCESS_LISTS_RESPONSE=$(cat "$BACKUP_PATH/.access_lists/access_lists_${NGINX_IP//./_}$DATE.json")
      jq --argjson lists "$ACCESS_LISTS_RESPONSE" '. + {access_lists: $lists}' \
        "$BACKUP_PATH/full_config${DATE}.json" >"$BACKUP_PATH/full_config${DATE}.json.tmp"
      mv "$BACKUP_PATH/full_config${DATE}.json.tmp" "$BACKUP_PATH/full_config${DATE}.json"
      echo -e " ✅ ${COLOR_GREEN}Backed up $access_lists_count access lists with complete details${CoR}"
      success_count=$((success_count + 1))
    else
      echo -e " ⚠️ ${COLOR_YELLOW}Failed to create valid access lists backup${CoR}"
      error_count=$((error_count + 1))
    fi
  else
    echo -e " ⚠️ ${COLOR_YELLOW}No access lists found${CoR}"
    error_count=$((error_count + 1))
  fi

  # 4. Backup proxy hosts
  echo -e "\n🌐 ${COLOR_CYAN}Backing up proxy hosts...${CoR}"
  ALL_HOSTS_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ -n "$ALL_HOSTS_RESPONSE" ] && echo "$ALL_HOSTS_RESPONSE" | jq empty 2>/dev/null; then
    hosts_count=$(echo "$ALL_HOSTS_RESPONSE" | jq '. | length')

    # Save all hosts metadata
    echo "$ALL_HOSTS_RESPONSE" | jq '.' >"$BACKUP_PATH/.Proxy_Hosts/all_hosts_${NGINX_IP//./_}$DATE.json"

    # Process each proxy host - use while read with pipe to preserve variables
    while IFS= read -r host; do
      local host_id=$(echo "$host" | jq -r '.id')
      local domain_name=$(echo "$host" | jq -r '.domain_names[0]' | sed 's/[^a-zA-Z0-9.]/_/g')
      local cert_id=$(echo "$host" | jq -r '.certificate_id')

      echo -e "\n 📥 Processing host: ${COLOR_GREEN}$domain_name${CoR} (ID: ${COLOR_YELLOW}$host_id${CoR})"

      # Create directory for this proxy host
      local PROXY_DIR="$BACKUP_PATH/.Proxy_Hosts/$domain_name"
      mkdir -p "$PROXY_DIR/ssl" "$PROXY_DIR/logs"

      # Save proxy host configuration
      echo "$host" | jq '.' >"$PROXY_DIR/proxy_config.json"

      # Get and save nginx configuration
      local NGINX_CONFIG
      NGINX_CONFIG=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id/nginx" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
      if [ -n "$NGINX_CONFIG" ]; then
        echo "$NGINX_CONFIG" >"$PROXY_DIR/nginx.conf"
      fi

      # Get and save logs if they exist
      curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id/access.log" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" >"$PROXY_DIR/logs/access.log"
      curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id/error.log" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" >"$PROXY_DIR/logs/error.log"

      # Process SSL certificate if exists
      if [ -n "$cert_id" ] && [ "$cert_id" != "null" ] && [ "$cert_id" != "0" ]; then
        echo -e "   🔒 Downloading SSL certificate (ID: $cert_id)"

        # Get certificate metadata first
        local CERT_META
        CERT_META=$(curl -s -X GET "$BASE_URL/nginx/certificates/$cert_id" \
          -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

        if [ -n "$CERT_META" ] && echo "$CERT_META" | jq empty 2>/dev/null; then
          echo "$CERT_META" | jq '.' >"$PROXY_DIR/ssl/certificate_meta.json"

          # Get certificate content
          local CERT_CONTENT
          CERT_CONTENT=$(curl -s -X GET "$BASE_URL/nginx/certificates/$cert_id/certificates" \
            -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
            -H "Accept: application/json")

          if [ -n "$CERT_CONTENT" ] && echo "$CERT_CONTENT" | jq empty 2>/dev/null; then
            # Save certificate files in proxy host directory
            echo "$CERT_CONTENT" | jq -r '.certificate' >"$PROXY_DIR/ssl/certificate.pem"
            echo "$CERT_CONTENT" | jq -r '.private' >"$PROXY_DIR/ssl/private.key"
            chmod 600 "$PROXY_DIR/ssl/private.key"

            if echo "$CERT_CONTENT" | jq -r '.intermediate' >/dev/null 2>&1; then
              echo "$CERT_CONTENT" | jq -r '.intermediate' >"$PROXY_DIR/ssl/chain.pem"
            fi

            # Create centralized SSL directory structure
            local CERT_NAME
            CERT_NAME=$(echo "$CERT_META" | jq -r '.nice_name // .domain_names[0]' | sed 's/[^a-zA-Z0-9.]/_/g')
            local CENTRAL_SSL_DIR="$BACKUP_PATH/.ssl/$CERT_NAME"
            mkdir -p "$CENTRAL_SSL_DIR"

            # Save metadata and create symbolic links
            echo "$CERT_META" | jq '.' >"$CENTRAL_SSL_DIR/certificate_meta.json"
            ln -sf "$PROXY_DIR/ssl/certificate.pem" "$CENTRAL_SSL_DIR/certificate.pem"
            ln -sf "$PROXY_DIR/ssl/private.key" "$CENTRAL_SSL_DIR/private.key"
            [ -f "$PROXY_DIR/ssl/chain.pem" ] && ln -sf "$PROXY_DIR/ssl/chain.pem" "$CENTRAL_SSL_DIR/chain.pem"

            # Add symlink to latest version
            ln -sf "$CENTRAL_SSL_DIR" "$BACKUP_PATH/.ssl/${CERT_NAME}_latest"

            echo -e "   ✅ ${COLOR_GREEN}SSL certificate backed up successfully${CoR}"

            # Count certificate type - maintenant les compteurs fonctionneront
            if echo "$CERT_META" | jq -e '.provider // empty | contains("letsencrypt")' >/dev/null 2>&1; then
              letsencrypt_certs_count=$((letsencrypt_certs_count + 1))
            else
              custom_certs_count=$((custom_certs_count + 1))
            fi
            certs_count=$((certs_count + 1))
            success_count=$((success_count + 1))
          else
            echo -e "   ⚠️ ${COLOR_YELLOW}Failed to download certificate content${CoR}"
            error_count=$((error_count + 1))
          fi
        else
          echo -e "   ⚠️ ${COLOR_YELLOW}Failed to get certificate metadata${CoR}"
          error_count=$((error_count + 1))
        fi
      fi

      echo -e " ✅ ${COLOR_GREEN}Host $domain_name backed up successfully${CoR}"
    done < <(echo "$ALL_HOSTS_RESPONSE" | jq -c '.[]')

    # Create latest symlink for hosts
    ln -sf "$BACKUP_PATH/.Proxy_Hosts/all_hosts_${NGINX_IP//./_}$DATE.json" \
      "$BACKUP_PATH/.Proxy_Hosts/all_hosts_latest.json"

    echo -e "\n ✅ ${COLOR_GREEN}Backed up $hosts_count proxy hosts${CoR}"
  else
    echo -e " ⚠️ ${COLOR_YELLOW}No proxy hosts found or invalid response${CoR}"
    error_count=$((error_count + 1))
  fi

  # 5. Backup redirection hosts
  echo -e "\n🔄 ${COLOR_CYAN}Backing up redirection hosts...${CoR}"
  REDIRECTION_HOSTS_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/redirection-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ -n "$REDIRECTION_HOSTS_RESPONSE" ] && echo "$REDIRECTION_HOSTS_RESPONSE" | jq empty 2>/dev/null; then
    redirect_hosts_count=$(echo "$REDIRECTION_HOSTS_RESPONSE" | jq '. | length')
    echo "$REDIRECTION_HOSTS_RESPONSE" | jq '.' >"$BACKUP_PATH/.Redirection_Hosts/redirection_hosts_${NGINX_IP//./_}$DATE.json"
    ln -sf "$BACKUP_PATH/.Redirection_Hosts/redirection_hosts_${NGINX_IP//./_}$DATE.json" \
      "$BACKUP_PATH/.Redirection_Hosts/redirection_hosts_latest.json"
    jq --argjson hosts "$REDIRECTION_HOSTS_RESPONSE" '. + {redirection_hosts: $hosts}' \
      "$BACKUP_PATH/full_config${DATE}.json" >"$BACKUP_PATH/full_config${DATE}.json.tmp"
    mv "$BACKUP_PATH/full_config${DATE}.json.tmp" "$BACKUP_PATH/full_config${DATE}.json"
    echo -e " ✅ ${COLOR_GREEN}Backed up $redirect_hosts_count redirection hosts${CoR}"
    success_count=$((success_count + 1))
  else
    echo -e " ⚠️ ${COLOR_YELLOW}No redirection hosts found or invalid response${CoR}"
    error_count=$((error_count + 1))
  fi

  # 6. Backup stream hosts
  echo -e "\n🔌 ${COLOR_CYAN}Backing up stream hosts...${CoR}"
  STREAM_HOSTS_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/streams" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ -n "$STREAM_HOSTS_RESPONSE" ] && echo "$STREAM_HOSTS_RESPONSE" | jq empty 2>/dev/null; then
    stream_hosts_count=$(echo "$STREAM_HOSTS_RESPONSE" | jq '. | length')
    echo "$STREAM_HOSTS_RESPONSE" | jq '.' >"$BACKUP_PATH/.Stream_Hosts/stream_hosts_${NGINX_IP//./_}$DATE.json"
    ln -sf "$BACKUP_PATH/.Stream_Hosts/stream_hosts_${NGINX_IP//./_}$DATE.json" \
      "$BACKUP_PATH/.Stream_Hosts/stream_hosts_latest.json"
    jq --argjson hosts "$STREAM_HOSTS_RESPONSE" '. + {streams: $hosts}' \
      "$BACKUP_PATH/full_config${DATE}.json" >"$BACKUP_PATH/full_config${DATE}.json.tmp"
    mv "$BACKUP_PATH/full_config${DATE}.json.tmp" "$BACKUP_PATH/full_config${DATE}.json"
    echo -e " ✅ ${COLOR_GREEN}Backed up $stream_hosts_count stream hosts${CoR}"
    success_count=$((success_count + 1))
  else
    echo -e " ⚠️ ${COLOR_YELLOW}No stream hosts found or invalid response${CoR}"
    error_count=$((error_count + 1))
  fi

  # 7. Backup 404 hosts (dead hosts)
  echo -e "\n🚫 ${COLOR_CYAN}Backing up 404 hosts...${CoR}"
  DEAD_HOSTS_RESPONSE=$(curl -s -X GET "$BASE_URL/nginx/dead-hosts" \
    -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")

  if [ -n "$DEAD_HOSTS_RESPONSE" ] && echo "$DEAD_HOSTS_RESPONSE" | jq empty 2>/dev/null; then
    dead_hosts_count=$(echo "$DEAD_HOSTS_RESPONSE" | jq '. | length')
    echo "$DEAD_HOSTS_RESPONSE" | jq '.' >"$BACKUP_PATH/.Dead_Hosts/dead_hosts_${NGINX_IP//./_}$DATE.json"
    ln -sf "$BACKUP_PATH/.Dead_Hosts/dead_hosts_${NGINX_IP//./_}$DATE.json" \
      "$BACKUP_PATH/.Dead_Hosts/dead_hosts_latest.json"
    jq --argjson hosts "$DEAD_HOSTS_RESPONSE" '. + {dead_hosts: $hosts}' \
      "$BACKUP_PATH/full_config${DATE}.json" >"$BACKUP_PATH/full_config${DATE}.json.tmp"
    mv "$BACKUP_PATH/full_config${DATE}.json.tmp" "$BACKUP_PATH/full_config${DATE}.json"
    echo -e " ✅ ${COLOR_GREEN}Backed up $dead_hosts_count 404 hosts${CoR}"
    success_count=$((success_count + 1))
  else
    echo -e " ⚠️ ${COLOR_YELLOW}No 404 hosts found or invalid response${CoR}"
    error_count=$((error_count + 1))
  fi

  # Generate backup report and statistics
  echo -e "\n📊 ${COLOR_YELLOW}Backup Summary:${CoR}"
  echo -e " • ${COLOR_CYAN}Users:${CoR} $users_count"
  echo -e " • ${COLOR_CYAN}Proxy Hosts:${CoR} $hosts_count"
  echo -e " • ${COLOR_CYAN}Redirection Hosts:${CoR} $redirect_hosts_count"
  echo -e " • ${COLOR_CYAN}Stream Hosts:${CoR} $stream_hosts_count"
  echo -e " • ${COLOR_CYAN}404 Hosts:${CoR} $dead_hosts_count"
  echo -e " • ${COLOR_CYAN}SSL Certificates:${CoR} $certs_count"
  echo -e "   ├─ Custom: $custom_certs_count"
  echo -e "   └─ Let's Encrypt: $letsencrypt_certs_count"
  echo -e " • ${COLOR_CYAN}Access Lists:${CoR} $access_lists_count"
  echo -e " • ${COLOR_CYAN}Success/Error:${CoR} $success_count/$error_count"

  # Count backup files by type
  local total_files=$(find "$BACKUP_PATH" -type f \( \
    -name "*.json" -o \
    -name "*.conf" -o \
    -name "*.log" -o \
    -name "*.pem" -o \
    -name "*.key" \
    \) | wc -l)
  local config_files=$(find "$BACKUP_PATH" -maxdepth 1 -type f -name "full_config*.json" | wc -l)
  local proxy_files=$(find "$BACKUP_PATH/.Proxy_Hosts" -type f -name "proxy_config.json" | wc -l)
  local redirect_files=$(find "$BACKUP_PATH/.Redirection_Hosts" -type f -name "*.json" | wc -l)
  local stream_files=$(find "$BACKUP_PATH/.Stream_Hosts" -type f -name "*.json" | wc -l)
  local dead_files=$(find "$BACKUP_PATH/.Dead_Hosts" -type f -name "*.json" | wc -l)
  local ssl_files=$(find "$BACKUP_PATH" -type f \( \
    -name "certificate*.json" -o \
    -name "*.pem" -o \
    -name "*.key" \
    \) | wc -l)
  local access_files=$(find "$BACKUP_PATH/.access_lists" -type f -name "*.json" | wc -l)
  local settings_files=$(find "$BACKUP_PATH/.settings" -type f -name "*.json" | wc -l)
  local user_files=$(find "$BACKUP_PATH/.user" -type f -name "*.json" | wc -l)

  echo -e "\n📁 ${COLOR_YELLOW}Backup Files Count:${CoR}"
  echo -e " • Full Configurations: ${COLOR_GREY}$config_files files${CoR}"
  echo -e " • Proxy Host Files: ${COLOR_GREY}$proxy_files files${CoR}"
  echo -e " • Redirection Host Files: ${COLOR_GREY}$redirect_files files${CoR}"
  echo -e " • Stream Host Files: ${COLOR_GREY}$stream_files files${CoR}"
  echo -e " • 404 Host Files: ${COLOR_GREY}$dead_files files${CoR}"
  echo -e " • SSL Certificate Files: ${COLOR_GREY}$ssl_files files${CoR}"
  echo -e " • Access List Files: ${COLOR_GREY}$access_files files${CoR}"
  echo -e " • Settings Files: ${COLOR_GREY}$settings_files files${CoR}"
  echo -e " • User Files: ${COLOR_GREY}$user_files files${CoR}"
  echo -e " • ${COLOR_GREEN}Total Backup Files: ${COLOR_GREY}$total_files files${CoR}"

  # Display backup locations
  echo -e "\n📂 ${COLOR_YELLOW}Backup Locations:${CoR}"
  echo -e " • Full config: ${COLOR_GREY}$BACKUP_PATH/full_config${DATE}.json${CoR}"
  echo -e " • Latest symlink: ${COLOR_GREY}$BACKUP_PATH/full_config_latest.json${CoR}"
  echo -e " • Proxy configs: ${COLOR_GREY}$BACKUP_PATH/.Proxy_Hosts/${CoR}"
  echo -e " • Host list full: ${COLOR_GREY}$BACKUP_PATH/.Proxy_Hosts/all_hosts_latest.json${CoR}"

  # Calculate and display total backup size
  local backup_size=$(du -sh "$BACKUP_PATH" | cut -f1)
  echo -e "\n💾 ${COLOR_YELLOW}Backup Size:${CoR} ${COLOR_GREY}$backup_size${CoR}"

  # Create latest symlink for full configuration
  ln -sf "$BACKUP_PATH/full_config${DATE}.json" "$BACKUP_PATH/full_config_latest.json"

  # Check for any errors during backup
  if [ $error_count -gt 0 ]; then
    echo -e "\n⚠️  ${COLOR_YELLOW}Backup completed with $error_count errors${CoR}"
    echo -e "   Please check the logs above for details."
  else
    echo -e "\n✅ ${COLOR_GREEN}Backup completed successfully!${CoR}"
  fi

  echo -e "\n📝 ${COLOR_GREY}Backup completed at: $(date '+%Y-%m-%d %H:%M:%S')${CoR}\n"
  return $error_count
}

# Backup a single proxy host (via $HOST_ID) or all proxy hosts (if $HOST_ID is empty),
# including its SSL certificate, using the same on-disk layout as full_backup().
backup_host() {
  check_dependencies
  check_nginx_access
  check_token_notverbose

  BACKUP_PATH="$BACKUP_DIR"
  mkdir -p "$BACKUP_PATH/.Proxy_Hosts"

  local hosts_json
  if [ -n "$HOST_ID" ]; then
    echo -e "\n📦 ${COLOR_YELLOW}Backing up proxy host ID $HOST_ID...${CoR}"
    local single_host
    single_host=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$HOST_ID" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
    if ! echo "$single_host" | jq -e '.id' >/dev/null 2>&1; then
      echo -e " ⛔ ${COLOR_RED}Proxy host ID $HOST_ID not found.${CoR}\n"
      return 1
    fi
    hosts_json="[$single_host]"
  else
    echo -e "\n📦 ${COLOR_YELLOW}Backing up all proxy hosts...${CoR}"
    hosts_json=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
  fi

  if [ -z "$hosts_json" ] || ! echo "$hosts_json" | jq empty 2>/dev/null; then
    echo -e " ⚠️  ${COLOR_YELLOW}No proxy hosts found or invalid response${CoR}\n"
    return 1
  fi

  local count=0
  while IFS= read -r host; do
    local host_id=$(echo "$host" | jq -r '.id')
    local domain_name=$(echo "$host" | jq -r '.domain_names[0]' | sed 's/[^a-zA-Z0-9.]/_/g')
    local cert_id=$(echo "$host" | jq -r '.certificate_id')

    echo -e "\n 📥 Processing host: ${COLOR_GREEN}$domain_name${CoR} (ID: ${COLOR_YELLOW}$host_id${CoR})"

    local PROXY_DIR="$BACKUP_PATH/.Proxy_Hosts/$domain_name"
    mkdir -p "$PROXY_DIR/ssl" "$PROXY_DIR/logs"

    echo "$host" | jq '.' >"$PROXY_DIR/proxy_config.json"

    local NGINX_CONFIG
    NGINX_CONFIG=$(curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id/nginx" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
    [ -n "$NGINX_CONFIG" ] && echo "$NGINX_CONFIG" >"$PROXY_DIR/nginx.conf"

    curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id/access.log" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" >"$PROXY_DIR/logs/access.log"
    curl -s -X GET "$BASE_URL/nginx/proxy-hosts/$host_id/error.log" \
      -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" >"$PROXY_DIR/logs/error.log"

    if [ -n "$cert_id" ] && [ "$cert_id" != "null" ] && [ "$cert_id" != "0" ]; then
      echo -e "   🔒 Downloading SSL certificate (ID: $cert_id)"
      local CERT_META
      CERT_META=$(curl -s -X GET "$BASE_URL/nginx/certificates/$cert_id" \
        -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}")
      if [ -n "$CERT_META" ] && echo "$CERT_META" | jq empty 2>/dev/null; then
        echo "$CERT_META" | jq '.' >"$PROXY_DIR/ssl/certificate_meta.json"
        local CERT_CONTENT
        CERT_CONTENT=$(curl -s -X GET "$BASE_URL/nginx/certificates/$cert_id/certificates" \
          -H "Authorization: Bearer ${TOKEN:-$(cat "$TOKEN_FILE")}" \
          -H "Accept: application/json")
        if [ -n "$CERT_CONTENT" ] && echo "$CERT_CONTENT" | jq empty 2>/dev/null; then
          echo "$CERT_CONTENT" | jq -r '.certificate' >"$PROXY_DIR/ssl/certificate.pem"
          echo "$CERT_CONTENT" | jq -r '.private' >"$PROXY_DIR/ssl/private.key"
          chmod 600 "$PROXY_DIR/ssl/private.key"
          echo "$CERT_CONTENT" | jq -r '.intermediate // empty' >"$PROXY_DIR/ssl/chain.pem"
          echo -e "   ✅ ${COLOR_GREEN}SSL certificate backed up${CoR}"
        else
          echo -e "   ⚠️ ${COLOR_YELLOW}Failed to download certificate content${CoR}"
        fi
      else
        echo -e "   ⚠️ ${COLOR_YELLOW}Failed to get certificate metadata${CoR}"
      fi
    fi

    echo -e " ✅ ${COLOR_GREEN}Host $domain_name backed up successfully${CoR}"
    count=$((count + 1))
  done < <(echo "$hosts_json" | jq -c '.[]')

  echo -e "\n📝 ${COLOR_GREY}Backup completed at: $(date '+%Y-%m-%d %H:%M:%S')${CoR}"
  echo -e " ${COLOR_CYAN}$count${CoR} proxy host(s) backed up in ${COLOR_GREY}$BACKUP_PATH/.Proxy_Hosts/${CoR}\n"
}

# List available per-host proxy backups (written by full_backup() or backup_host()).
# Purely local (no API call), so it works even without a valid/fresh token.
list_backups() {
  check_dependencies
  local ip_port_dir="${NGINX_IP//[.:]/_}_${NGINX_PORT}"
  BACKUP_DIR="${BACKUP_DIR:-$DATA_DIR/$ip_port_dir/backups}"
  BACKUP_PATH="$BACKUP_DIR"
  local dir="$BACKUP_PATH/.Proxy_Hosts"

  if [ ! -d "$dir" ] || [ -z "$(find "$dir" -mindepth 2 -maxdepth 2 -name "proxy_config.json" -print -quit 2>/dev/null)" ]; then
    echo -e "\n ⚠️  ${COLOR_YELLOW}No proxy host backups found in ${COLOR_GREY}$dir${CoR}"
    echo -e "    Run ${COLOR_CYAN}--backup-host${CoR} or ${COLOR_CYAN}--backup${CoR} first.\n"
    return 1
  fi

  echo -e "\n 📋 ${COLOR_YELLOW}Available proxy host backups:${CoR}"
  echo -e " ${COLOR_GREY}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${CoR}"
  printf " %-4s %-35s %s\n" "ID" "Domain" "Last backup"
  while IFS= read -r file; do
    local id domain mtime
    id=$(jq -r '.id // "?"' "$file" 2>/dev/null)
    domain=$(jq -r '.domain_names[0] // "?"' "$file" 2>/dev/null)
    mtime=$(date -r "$file" '+%Y-%m-%d %H:%M:%S' 2>/dev/null)
    printf " ${COLOR_CYAN}%-4s${CoR} %-35s ${COLOR_GREY}%s${CoR}\n" "$id" "$domain" "$mtime"
  done < <(find "$dir" -mindepth 2 -maxdepth 2 -name "proxy_config.json" | sort)
  echo ""
}

######################################
# Main menu logic
######################################
for arg in "$@"; do
  if [ "$arg" = "-y" ]; then
    AUTO_YES=true
    #echo "Debug global: Setting AUTO_YES=true"
    break
  fi
done

# Pre-scan for --purge so its position on the command line does not matter
# (e.g. "--cert-delete 240 --purge" or "--cert-delete --purge 240").
for arg in "$@"; do
  if [ "$arg" = "--purge" ]; then
    CERT_PURGE=true
    break
  fi
done

while [[ "$#" -gt 0 ]]; do
  case "$1" in
  -y)
    AUTO_YES=true
    shift
    ;;
  --json)
    JSON_OUTPUT=true
    shift
    ;;
  --list)
    LIST_JSON_COMMANDS=true
    shift
    ;;
  --purge)
    # Handled via pre-scan (CERT_PURGE); only used together with --cert-delete.
    CERT_PURGE=true
    shift
    ;;
  --help)
    SHOW_HELP=true
    shift
    ;;
  --examples)
    EXAMPLES=true
    shift
    ;;
  --info)
    INFO=true
    shift
    ;;
  --show-default)
    SHOW_DEFAULT=true
    shift
    ;;
  --check-token)
    CHECK_TOKEN=true
    shift
    ;;
  --check-update)
    CHECK_UPDATE=true
    shift
    ;;
  --backup)
    BACKUP=true
    shift
    ;;
  --backup-host)
    shift
    if [[ -n "$1" && "$1" != -* ]]; then
      HOST_ID="$1"
      shift
    fi
    BACKUP_HOST=true
    ;;
  --backup-host-list)
    BACKUP_LIST=true
    shift
    ;;
  --clean-hosts)
    exit 1 # not use !
    CLEAN_HOSTS=true
    shift
    if [[ -n "$1" && "$1" != -* ]]; then
      BACKUP_FILE="$1"
      shift
    else
      BACKUP_FILE="$DEFAULT_BACKUP_FILE"
    fi
    ;;
  --user-list)
    USER_LIST=true
    shift
    ;;
  --user-create)
    shift
    if [[ $# -lt 3 ]]; then
      echo -e "\n 👤 ${COLOR_RED}The --user-create option requires username, password, and email.${CoR}"
      echo -e " Usage: ${COLOR_ORANGE}$0 --user-create <username> <password> <email>${CoR}"
      echo -e " Example:"
      echo -e "   ${COLOR_GREEN}$0 --user-create john secretpass john@domain.com${CoR}\n"
      exit 1
    fi

    USERNAME="$1"
    PASSWORD="$2"
    EMAIL="$3"
    USER_CREATE=true
    shift 3
    # Optional: grant admin role (default is a standard, non-admin user)
    if [ $# -gt 0 ] && [ "$1" = "--admin" ]; then
      USER_IS_ADMIN=true
      shift
    fi
    ;;
  --user-delete)
    shift
    if [[ $# -eq 0 ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --user-delete option requires a user 🆔.${CoR}"
      echo -e " Usage: ${COLOR_ORANGE}$0 --user-delete <user_id>${CoR}"
      exit 1
    fi

    USER_ID="$1"
    USER_DELETE=true
    shift
    ;;
  --host-show)
    shift
    if [[ $# -eq 0 ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-show option requires a host ${CoR}🆔"
      echo -e "    Usage  : ${COLOR_ORANGE}$0 --host-show <ID>${CoR}"
      echo -e "    Example: $0 --host-show 42"
      echo -e "    Find ID: $0 --host-list\n"
      exit 1
    fi
    host_id="$1"
    HOST_SHOW=true
    shift
    ;;
  --host-list)
    HOST_LIST=true
    shift
    ;;
  --host-list-full)
    HOST_LIST_FULL=true
    shift
    ;;
  --host-search)
    shift
    HOST_SEARCHNAME="${1:-}"
    if [ -z "$HOST_SEARCHNAME" ]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-search option requires a host name.${CoR}"
      echo -e "    Usage  : ${COLOR_ORANGE}$0 --host-search hostname${CoR}"
      echo -e "    Example: $0 --host-search domain.com ${COLOR_YELLOW}or${CoR} dom ${COLOR_YELLOW}or${CoR} .com"
      echo -e "    Find ID: $0 --host-list\n"
      exit 1
    fi
    HOST_SEARCH=true
    shift
    ;;
  --host-enable)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-enable option requires a host${CoR} 🆔"
      echo -e "    Usage  : ${COLOR_ORANGE}$0 --host-enable <host_id>${CoR}"
      echo -e "    Example: $0 --host-enable 42"
      echo -e "    Find ID: $0 --host-list\n"
      exit 1
    fi
    HOST_ID="$1"
    HOST_ENABLE=true
    shift
    ;;
  --host-disable)
    shift
    if [[ $# -eq 0 ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-disable option requires host${CoR} 🆔"
      echo -e "    Usage  : ${COLOR_GREEN}$0 --host-disable <host_id>${CoR}"
      echo -e "    Example: $0 --host-disable 42"
      echo -e "    Find ID: $0 --host-list\n"
      exit 1
    fi

    HOST_ID="$1"
    HOST_DISABLE=true
    shift
    ;;
  --host-delete)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-delete option requires a host${CoR} 🆔"
      echo -e "   ${COLOR_CYAN}Usage:${CoR}"
      echo -e "   ${COLOR_ORANGE}$0 --host-delete <host_id> [-y]${CoR}"
      echo -e "   ${COLOR_CYAN}Examples:${CoR}"
      echo -e "   ${COLOR_GREEN}$0 --host-delete 42${CoR}"
      echo -e "   ${COLOR_GREEN}$0 --host-delete 42 -y${CoR} ${COLOR_GREY}# Skip confirmation${CoR}"
      echo -e "\n ${COLOR_YELLOW}💡 Tip: Use --host-list to see all available hosts and their IDs${CoR}"
      exit 1
    fi

    if [[ "$1" =~ ^[0-9]+$ ]]; then
      HOST_ID="$1"
      HOST_DELETE=true
      shift
    else
      echo -e "\n ⛔ ${COLOR_RED}INVALID: Invalid host ID '$1' - must be a number${CoR}"
      echo -e "\n${COLOR_CYAN}Example:${CoR}"
      echo -e " ${COLOR_GREEN}$0 --host-delete 42${CoR}"
      echo -e "\n${COLOR_YELLOW}💡 Tip: Use --host-list to see all available hosts and their IDs${CoR}"
      exit 1
    fi
    ;;
  --host-update)
    if [[ "$#" -lt 3 ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-update option requires a host 🆔 and a field=value pair.${CoR}"
      echo -e "    Usage  : ${COLOR_GREEN}$0 --host-update <host_id> <field=value>${CoR}"
      echo -e "    Find ID: $0 --host-list${CoR}\n"
      exit 1
    fi
    # Check if  $2  is a number
    if [[ "$2" =~ ^[0-9]+$ ]]; then
      HOST_ID="$2"
      FIELD_VALUE="$3"
      # Split FIELD and VALUE
      if [[ "$FIELD_VALUE" == *"="* ]]; then
        FIELD=$(echo "$FIELD_VALUE" | cut -d '=' -f1)
        VALUE=$(echo "$FIELD_VALUE" | cut -d '=' -f2-)
        HOST_UPDATE=true
      else
        echo -e "\n ⛔ ${COLOR_RED}INVALID: The field=value pair is malformed.${CoR}"
        echo -e "   Example: $0 --host-update 42 forward_host=new.backend.local"
        exit 1
      fi

      shift 3
      #host_update "$HOST_ID" "$FIELD" "$VALUE"
      #HOST_UPDATE=true
    else
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-update option requires a valid (numeric) host 🆔.${CoR}"
      exit 1
    fi
    ;;

  --host-create)
    HOST_CREATE=true
    shift
    # Check if there are any remaining arguments after shift
    if [ $# -eq 0 ]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-create option requires arguments${CoR}"
      echo -e "\n Required options:"
      echo -e "  • Domain name ${COLOR_GREY}(positional argument)${CoR}"
      echo -e "  • -i, --forward-host     ${COLOR_GREY}Forward host (e.g., 127.0.0.1)${CoR}"
      echo -e "  • -p, --forward-port     ${COLOR_GREY}Forward port (e.g., 8080)${CoR}"
      echo -e "\n Optional:"
      echo -e "  • -f, --forward-scheme   ${COLOR_GREY}Protocol (http/https, default: http)${CoR}"
      echo -e "  • -b, --block-exploits   ${COLOR_GREY}Block common exploits (true/false)${CoR}"
      echo -e "  • -c, --cache            ${COLOR_GREY}Enable caching (true/false)${CoR}"
      echo -e "  • -w, --websocket        ${COLOR_GREY}Allow websocket upgrade (true/false)${CoR}"
      echo -e "  • -h, --http2            ${COLOR_GREY}Enable HTTP/2 support (true/false)${CoR}"
      echo -e "  • -s, --ssl-force        ${COLOR_GREY}Force SSL (true/false)${CoR}"
      echo -e "  • -l, --custom-locations ${COLOR_GREY}Custom location rules (JSON array)${CoR}"
      echo -e "  • -a, --advanced-config  ${COLOR_GREY}Advanced Nginx configuration (string)${CoR}"
      echo -e "\n Can be combined with:"
      echo -e "  • --cert-generate        ${COLOR_GREY}Generate SSL certificate${CoR}"
      echo -e "  • --host-ssl-enable      ${COLOR_GREY}Enable SSL after creation${CoR}"
      echo -e "  • -y                     ${COLOR_GREY}Skip all confirmations${CoR}"
      echo -e "\n Examples:"
      echo -e " ${COLOR_GREEN}$0 --host-create example.com -i 127.0.0.1 -p 8080${CoR}"
      echo -e " ${COLOR_GREEN}$0 --host-create example.com -i 127.0.0.1 -p 8080 --cert-generate --host-ssl-enable -y${CoR}\n"
      exit 1
    fi

    # Check if first argument is a valid domain (not starting with -)
    if [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: First argument after --host-create must be a domain name${CoR}"
      exit 1
    fi

    DOMAIN_NAMES="$1"
    shift

    # Process remaining options
    while [[ $# -gt 0 ]]; do
      case "$1" in
      -i | --forward-host)
        if [[ -n "$2" && "$2" != -* ]]; then
          FORWARD_HOST="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}INVALID: The --forward-host option requires a valid value${CoR}"
          echo -e "\n Required options:"
          echo -e "  • Domain name ${COLOR_GREY}(positional argument)${CoR}"
          echo -e "  • -i, --forward-host     ${COLOR_GREY}Forward host (e.g., 127.0.0.1)${CoR}"
          echo -e "  • -p, --forward-port     ${COLOR_GREY}Forward port (e.g., 8080)${CoR}"
          echo -e "\n Optional:"
          echo -e "  • -f, --forward-scheme   ${COLOR_GREY}Protocol (http/https, default: http)${CoR}"
          echo -e "  • -b, --block-exploits   ${COLOR_GREY}Block common exploits (true/false, default: false)${CoR}"
          echo -e "  • -c, --cache            ${COLOR_GREY}Enable caching (true/false, default: false)${CoR}"
          echo -e "  • -w, --websocket        ${COLOR_GREY}Allow websocket upgrade (true/false, default: false)${CoR}"
          echo -e "  • -h, --http2            ${COLOR_GREY}Enable HTTP/2 support (true/false, default: false)${CoR}"
          echo -e "  • -s, --ssl-force        ${COLOR_GREY}Force SSL (true/false, default: false)${CoR}"
          echo -e "  • -l, --custom-locations ${COLOR_GREY}Custom location rules (JSON array)${CoR}"
          echo -e "  • -a, --advanced-config  ${COLOR_GREY}Advanced Nginx configuration (string)${CoR}"
          exit 1
        fi
        ;;
      -p | --forward-port)
        if [[ -n "$2" && "$2" != -* && "$2" =~ ^[0-9]+$ ]]; then
          FORWARD_PORT="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}INVALID: The --forward-port option requires a valid number${CoR}"
          echo -e "\n Required options:"
          echo -e "  • Domain name ${COLOR_GREY}(positional argument)${CoR}"
          echo -e "  • -i, --forward-host     ${COLOR_GREY}Forward host (e.g., 127.0.0.1)${CoR}"
          echo -e "  • -p, --forward-port     ${COLOR_GREY}Forward port (e.g., 8080)${CoR}"
          exit 1
        fi
        ;;
      -f | --forward-scheme)
        if [[ -n "$2" && "$2" != -* && "$2" =~ ^(http|https)$ ]]; then
          FORWARD_SCHEME="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}INVALID: The --forward-scheme option must be 'http' or 'https'${CoR}"
          exit 1
        fi
        ;;
      -b | --block-exploits | -c | --cache | -w | --websocket | -h | --http2 | -s | --ssl-force)
        # Process boolean options
        # Note: Variable names must match those used in create_or_update_proxy_host() function
        opt_name=${1#-?}
        opt_name=${opt_name#--}
        if [[ "$2" =~ ^(true|false)$ ]]; then
          case "$opt_name" in
          block-exploits) BLOCK_EXPLOITS="$2" ;;
          cache) CACHING_ENABLED="$2" ;;             # Fixed: was CACHE_ENABLED (Issue #23)
          websocket) ALLOW_WEBSOCKET_UPGRADE="$2" ;; # Fixed: was WEBSOCKET_SUPPORT (Issue #23)
          http2) HTTP2_SUPPORT="$2" ;;
          ssl-force) SSL_FORCED="$2" ;;
          esac
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}INVALID: The $1 option must be 'true' or 'false'${CoR}"
          exit 1
        fi
        ;;
      -l | --custom-locations)
        # Fixed: Added support for custom locations option (Issue #22)
        if [[ -n "$2" && "$2" != -* ]]; then
          CUSTOM_LOCATIONS="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}INVALID: The --custom-locations option requires a JSON value${CoR}"
          echo -e "   ${COLOR_CYAN}Example:${CoR}"
          echo -e "   ${COLOR_GREEN}$0 --host-create example.com -i 192.168.1.10 -p 8080 -l '[{\"path\":\"/api\",\"forward_host\":\"192.168.1.11\",\"forward_port\":8081}]'${CoR}"
          exit 1
        fi
        ;;
      -a | --advanced-config)
        # Fixed: Added support for advanced config option (Issue #22)
        if [[ -n "$2" && "$2" != -* ]]; then
          ADVANCED_CONFIG="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}INVALID: The --advanced-config option requires a configuration string${CoR}"
          echo -e "   ${COLOR_CYAN}Example:${CoR}"
          echo -e "   ${COLOR_GREEN}$0 --host-create example.com -i 192.168.1.10 -p 8080 -a 'proxy_set_header X-Real-IP \\\$remote_addr;'${CoR}"
          exit 1
        fi
        ;;

        # Support for chaining commands
      --cert-generate | --host-ssl-enable | -y | --cert-email | --dns-provider | --dns-credentials)
        # Just store these flags, they'll be processed later
        case "$1" in
        --cert-generate)
          CERT_GENERATE=true
          shift
          if [ $# -gt 0 ] && [[ "$1" != --* ]]; then
            CERT_DOMAIN="$1"
            shift
          else
            # If no specific argument for --cert-generate, use the host domain
            CERT_DOMAIN="$DOMAIN_NAMES"
          fi
          ;;
        --cert-email)
          shift
          CERT_EMAIL="$1"
          shift
          ;;
        --dns-provider)
          shift
          CERT_DNS_PROVIDER="$1"
          shift
          ;;
        --dns-credentials)
          shift
          CERT_DNS_CREDENTIALS="$1"
          shift
          ;;
        --host-ssl-enable)
          HOST_SSL_ENABLE=true
          shift
          ;;
        -y)
          AUTO_YES=true
          shift
          ;;
        esac
        ;;
      *)

        if [[ "$1" == -* ]]; then
          echo -e "\n ⚠️ ${COLOR_YELLOW}WARNING: Unknown option ignored -> $1${CoR}"
        fi
        shift
        ;;
      esac
    done

    # check settings
    if [ -z "$FORWARD_HOST" ] || [ -z "$FORWARD_PORT" ]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: Missing required parameters${CoR}"
      echo -e " Required options:"
      echo -e "    • Domain name: ${COLOR_GREEN}$DOMAIN_NAMES${CoR} ${COLOR_GREY}(provided)${CoR}"
      [ -z "$FORWARD_HOST" ] && echo -e "    • -i, --forward-host     ${COLOR_RED}Missing${CoR}"
      [ -z "$FORWARD_PORT" ] && echo -e "    • -p, --forward-port     ${COLOR_RED}Missing${CoR}"
      echo -e "\n Example:"
      echo -e "   ${COLOR_GREEN}$0 --host-create example.com -i 127.0.0.1 -p 8080${CoR}\n"
      exit 1
    fi

    # Create proxy host
    create_or_update_proxy_host "$DOMAIN_NAMES" "$FORWARD_HOST" "$FORWARD_PORT" \
      "${FORWARD_SCHEME:-http}" "${BLOCK_EXPLOITS:-false}" "${CACHING_ENABLED:-false}" \
      "${ALLOW_WEBSOCKET_UPGRADE:-false}" "${HTTP2_SUPPORT:-false}" "${SSL_FORCED:-false}"
    ;;
  --host-ssl-enable)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}The --host-ssl-enable option requires a host ID and certificate ID.${CoR}"
      echo -e "\n  ${COLOR_CYAN}Usage:${CoR}"
      echo -e "    ${COLOR_ORANGE}$0 --host-ssl-enable <host_id> <cert_id>${CoR}"
      echo -e "  ${COLOR_CYAN}Examples:${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --host-ssl-enable 42 240${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --host-ssl-enable 42 240 -y${CoR} ${COLOR_GREY}# Skip confirmation${CoR}"
      echo -e "  ${COLOR_YELLOW}💡 Tips:${CoR}"
      echo -e "    • Use ${COLOR_GREEN}--host-list${CoR} to see all available hosts"
      echo -e "    • Use ${COLOR_GREEN}--cert-list${CoR} to see all available certificates\n"
      exit 1
    fi

    if [[ "$1" =~ ^[0-9]+$ ]]; then
      HOST_ID="$1"
      shift
      # Check for mandatory cert_id
      if [ $# -gt 0 ] && [[ "$1" =~ ^[0-9]+$ ]]; then
        CERT_ID="$1"
        shift
      else
        echo -e "\n ⛔ ${COLOR_RED}ERROR: Certificate ID is required${CoR}"
        echo -e " ${COLOR_CYAN}Usage:${CoR} $0 --host-ssl-enable <host_id> <cert_id>"
        echo -e " ${COLOR_YELLOW}💡 Use --cert-list to see all available certificates${CoR}\n"
        exit 1
      fi
      HOST_SSL_ENABLE=true
    else
      echo -e "\n ⛔ ${COLOR_RED}ERROR: Invalid host ID '$1' - must be a number${CoR}"
      echo -e "    ${COLOR_CYAN}Usage:${CoR} $0 --host-ssl-enable <host_id> <cert_id>"
      echo -e "    ${COLOR_YELLOW}💡 Use --host-list to see all available hosts${CoR}\n"
      exit 1
    fi
    ;;
  --host-ssl-disable)
    HOST_SSL_DISABLE=true
    shift
    if [ $# -gt 0 ]; then
      HOST_ID="$1"
      shift
    else
      echo -e "\n ⛔ ${COLOR_RED}INVALID command: Missing argument${CoR}"
      echo -e "    Usage      : ${COLOR_ORANGE}$0 --host-ssl-disable <host_id>${CoR}"
      echo -e "    Find HostID: ${COLOR_GREEN}$0 --host-list${CoR}\n"
      exit 1
    fi
    ;;
  --host-acl-enable)
    HOST_ACL_ENABLE=true
    shift
    if [ $# -lt 2 ]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: The --host-acl-enable option requires two arguments: host_id and access_list_id${CoR}"
      echo -e "    Usage  : ${COLOR_ORANGE}$0 --host-acl-enable <host_id> <access_list_id>${CoR}"
      echo -e "    Example: ${COLOR_GREEN}$0 --host-acl-enable 42 5${CoR}"
      echo -e "    Find ID: ${COLOR_ORANGE}$0 --host-list${CoR} AND ${COLOR_ORANGE}--access-list${CoR}\n"
      exit 1
    fi
    HOST_ID="$1"
    ACCESS_LIST_ID="$2"
    shift 2
    ;;
  --host-acl-disable)
    HOST_ACL_DISABLE=true
    shift
    if [ $# -gt 0 ]; then
      HOST_ID="$1"
      shift
    else
      echo -e "\n ⛔ ${COLOR_RED}The --host-acl-disable option requires a host ID.${CoR}"
      echo -e "    Usage: $0 --host-acl-disable <host_id>\n"
      exit 1
    fi
    #host_acl_disable "$HOST_ID"
    ;;
  --cert-generate)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n 🛡️ ${COLOR_RED}The --cert-generate option requires a domain.${CoR}"
      echo -e "\n    ${COLOR_ORANGE}Usage: $0 --cert-generate domain [email] [--cert-email <email>] [--dns-provider <provider>] [--dns-credentials <json>]${CoR}"
      echo -e "\n    ${COLOR_YELLOW}Options${CoR}:"
      echo -e "      • --cert-email <email>          : Email for Let's Encrypt (alternative to positional email)"
      echo -e "      • --dns-provider <provider>     : DNS provider for wildcard certificates"
      echo -e "      • --dns-credentials <json>      : DNS credentials in JSON format"
      echo -e "      • --host-ssl-enable             : Enable SSL after certificate generation"
      echo -e "      • -y                            : Skip confirmations"
      echo -e "    ${COLOR_YELLOW}Note${CoR}:\n      • If email is not provided, default email ${COLOR_YELLOW}$DEFAULT_EMAIL${CoR} will be used"
      echo -e "      • For wildcard certificates (${COLOR_YELLOW}*.domain.com${CoR}), DNS challenge is required\n"
      echo -e "   Examples:"
      echo -e "     ${COLOR_GREEN}$0 --cert-generate example.com${CoR}"
      echo -e "     ${COLOR_GREEN}$0 --cert-generate example.com admin@example.com${CoR}"
      echo -e "     ${COLOR_GREEN}$0 --cert-generate example.com --cert-email admin@example.com${CoR}"
      echo -e "     ${COLOR_GREEN}$0 --cert-generate \"*.example.com\" --dns-provider cloudflare --dns-credentials '{\"dns_cloudflare_api_token\":\"your_token\"}'${CoR}\n"
      exit 1
    fi
    # Store domain
    CERT_DOMAIN="$1"
    CERT_DNS_PROVIDER=""
    CERT_DNS_CREDENTIALS=""
    HOST_SSL_ENABLE=false
    shift
    # Check and store email
    if [ $# -gt 0 ] && [[ "$1" != -* ]]; then
      CERT_EMAIL="$1"
      shift
    else
      CERT_EMAIL="$DEFAULT_EMAIL"
    fi

    # Parse DNS options
    while [ $# -gt 0 ] && [[ "$1" == --* ]]; do
      case "$1" in
      --cert-email)
        shift
        if [ $# -gt 0 ] && [[ "$1" != --* ]]; then
          CERT_EMAIL="$1"
          shift
        else
          echo -e "\n ⛔ ${COLOR_RED}Missing certificate email${CoR}"
          exit 1
        fi
        ;;
      --dns-provider)
        shift
        if [ $# -gt 0 ] && [[ "$1" != --* ]]; then
          CERT_DNS_PROVIDER="$1"
          shift
        else
          echo -e "\n ⛔ ${COLOR_RED}Missing DNS provider value${CoR}"
          exit 1
        fi
        ;;
      --dns-credentials)
        shift
        if [ $# -gt 0 ] && [[ "$1" != --* ]]; then
          CERT_DNS_CREDENTIALS="$1"
          shift
        else
          echo -e "\n ⛔ ${COLOR_RED}Missing DNS credentials${CoR}"
          exit 1
        fi
        ;;
      --host-ssl-enable)
        HOST_SSL_ENABLE=true
        shift
        ;;
      *)
        echo -e "\n ⚠️ ${COLOR_YELLOW}Unknown option: $1${CoR}"
        shift
        ;;
      esac
    done

    # Validate wildcard certificate requirements
    if [[ "$CERT_DOMAIN" == \** ]]; then
      if [ -z "$CERT_DNS_PROVIDER" ] || [ -z "$CERT_DNS_CREDENTIALS" ]; then
        echo -e "\n ⛔ ${COLOR_RED}Wildcard certificates require DNS challenge. Please provide --dns-provider and --dns-credentials.${CoR}"
        echo -e " Example: ${COLOR_GREEN}$0 --cert-generate \"*.example.com\" --dns-provider cloudflare --dns-credentials '{\"dns_cloudflare_api_token\":\"your_token\"}'${CoR}\n"
        exit 1
      fi
    fi

    # Set flag after validating all arguments
    CERT_GENERATE=true
    ;;
  --cert-delete)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}The --cert-delete option requires a certificate ID.${CoR}"
      echo -e "\n   ${COLOR_CYAN}Usage:${CoR}"
      echo -e "    ${COLOR_ORANGE}$0 --cert-delete <cert_id> [-y] [--purge]${CoR}"
      echo -e "\n   ${COLOR_CYAN}Examples:${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --cert-delete 240${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --cert-delete 240 -y${CoR} ${COLOR_GREY}# Skip confirmation${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --cert-delete 240 --purge${CoR} ${COLOR_GREY}# Also remove on-disk cert files (requires NGINX_PATH_DOCKER)${CoR}"
      echo -e "\n   ${COLOR_YELLOW}💡 Tips:${CoR}"
      echo -e "    • Use ${COLOR_GREEN}--cert-list${CoR} to see all certificates and their IDs"
      echo -e "    • ${COLOR_GREY}Without --purge the API does a soft-delete only (the cert leaves the UI but its files remain)${CoR}\n"
      exit 1
    fi
    CERT_DELETE=true
    CERT_ID="$1"
    shift
    ;;
  --cert-show)
    shift
    search_term="${1:-}"
    CERT_SHOW=true
    if [ -n "$search_term" ]; then
      shift
    fi
    ;;
  --cert-list | --cert-show-all)
    LIST_CERT_ALL=true
    shift
    ;;
  --cert-download)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}The --cert-download option requires a certificate ID.${CoR}"
      echo -e "\n   ${COLOR_CYAN}Usage:${CoR}"
      echo -e "    ${COLOR_ORANGE}$0 --cert-download <cert_id> [output_dir] [cert_name]${CoR}"
      echo -e "\n   ${COLOR_CYAN}Examples:${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --cert-download 240${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --cert-download 240 ./certs${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --cert-download 240 ./certs mydomain${CoR}"
      echo -e "\n   ${COLOR_YELLOW}💡 Tips:${CoR}"
      echo -e "    • Use ${COLOR_GREEN}--cert-list${CoR} to see all certificates and their IDs"
      echo -e "    • Supports both new API (JSON) and legacy API (ZIP) with automatic fallback"
      echo -e "    • Creates standardized certificate files (.crt, .key, .chain.crt) and ZIP archive\n"
      exit 1
    fi
    CERT_DOWNLOAD=true
    CERT_ID="$1"
    shift
    # Optional output directory
    if [ $# -gt 0 ] && [[ "$1" != -* ]]; then
      CERT_OUTPUT_DIR="$1"
      shift
    fi
    # Optional certificate name
    if [ $# -gt 0 ] && [[ "$1" != -* ]]; then
      CERT_NAME="$1"
      shift
    fi
    ;;
  --access-list)
    ACCESS_LIST=true
    shift
    ;;
  --access-list-show)
    ACCESS_LIST_SHOW=true
    shift
    # Check if access list ID is provided
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n⛔ ${COLOR_RED}Error: The access list ID is required.${CoR}"
      echo -e "\n   ${COLOR_CYAN}Usage:${CoR}"
      echo -e "    ${COLOR_ORANGE}$0 --access-list-show <id>${CoR}"
      echo -e "\n   ${COLOR_CYAN}Examples:${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --access-list-show 5${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --access-list-show 123${CoR}"
      echo -e "\n   ${COLOR_YELLOW}💡 Tip:${CoR}"
      echo -e "    • Use ${COLOR_GREEN}--access-list${CoR} to see all access lists and their IDs\n"
      exit 1
    fi
    ACCESS_LIST_ID="$1"
    shift
    ;;
  --access-list-create)
    shift
    # Stash remaining args and dispatch at the bottom (like --access-list-update),
    # instead of running mid-parse which left the bottom dispatch unreachable.
    ACCESS_LIST_CREATE=true
    ACCESS_LIST_CREATE_ARGS=()
    while [ $# -gt 0 ]; do
      ACCESS_LIST_CREATE_ARGS+=("$1")
      shift
    done
    ;;
  --access-list-update)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}The --access-list-update option requires an access list ID.${CoR}"
      echo -e "   ${COLOR_CYAN}Usage:${CoR}"
      echo -e "    ${COLOR_ORANGE}$0 --access-list-update <access_list_id> [options]${CoR}"
      echo -e "   ${COLOR_CYAN}Examples:${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --access-list-update 123 --name \"new_name\"${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --access-list-update 123 --name \"new_name\" --satisfy any${CoR}"
      echo -e "   ${COLOR_YELLOW}💡 Tip: Use --access-list to see all available access lists${CoR}"
      exit 1
    fi

    if [[ "$1" =~ ^[0-9]+$ ]]; then
      ACCESS_LIST_ID="$1"
      ACCESS_LIST_UPDATE=true
      shift
    else
      echo -e "\n ⛔ ${COLOR_RED}INVALID: Invalid access list ID '$1' - must be a number${CoR}"
      echo -e "  ${COLOR_CYAN}Examples:${CoR}"
      echo -e "   ${COLOR_GREEN}$0 --access-list-update 123 --name \"new_name\"${CoR}"
      echo -e "   ${COLOR_GREEN}$0 --access-list-update 123 --name \"new_name\" --satisfy any${CoR}"
      echo -e "  ${COLOR_YELLOW}💡 Tip: Use --access-list to see all available access lists${CoR}"
      exit 1
    fi

    # Process remaining arguments for access list update
    # Store them to pass to the function later
    ACCESS_LIST_UPDATE_ARGS=()
    while [ $# -gt 0 ]; do
      ACCESS_LIST_UPDATE_ARGS+=("$1")
      shift
    done
    ;;
  --access-list-delete)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}The --access-list-delete option requires an access list ID.${CoR}"
      echo -e "   ${COLOR_CYAN}Usage:${CoR}"
      echo -e "    ${COLOR_ORANGE}$0 --access-list-delete <access_list_id> [-y]${CoR}"
      echo -e "   ${COLOR_CYAN}Examples:${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --access-list-delete 42${CoR}"
      echo -e "    ${COLOR_GREEN}$0 --access-list-delete 42 -y${CoR} ${COLOR_GREY}# Skip confirmation${CoR}"
      echo -e "   ${COLOR_YELLOW}💡 Tip: Use --access-list to see all available access lists${CoR}"
      exit 1
    fi

    if [[ "$1" =~ ^[0-9]+$ ]]; then
      ACCESS_LIST_ID="$1"
      ACCESS_LIST_DELETE=true
      shift
    else
      echo -e "\n ⛔ ${COLOR_RED}INVALID: Invalid access list ID '$1' - must be a number${CoR}"
      echo -e "  ${COLOR_CYAN}Examples:${CoR}"
      echo -e "   ${COLOR_GREEN}$0 --access-list-delete 42${CoR}"
      echo -e "   ${COLOR_GREEN}$0 --access-list-delete 42 -y${CoR} ${COLOR_GREY}# Skip confirmation${CoR}"
      echo -e "  ${COLOR_YELLOW}💡 Tip: Use --access-list to see all available access lists${CoR}"
      exit 1
    fi
    ;;
  --redirect-host-list)
    REDIRECT_HOST_LIST=true
    shift
    ;;
  --redirect-host-create)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --redirect-host-create requires a domain name.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --redirect-host-create domain.com --forward-domain target.com [options]${CoR}"
      echo -e "   Options:"
      echo -e "     --forward-domain  domain    Target domain (${COLOR_RED}required${CoR})"
      echo -e "     --forward-scheme  http|https (default: http)"
      echo -e "     --http-code       301|302|303|307|308 (default: 301)"
      echo -e "     --preserve-path   true|false (default: false)"
      exit 1
    fi
    DOMAIN_NAMES="$1"
    shift
    while [[ $# -gt 0 ]]; do
      case "$1" in
      --forward-domain)
        if [[ -n "$2" && "$2" != -* ]]; then
          FORWARD_DOMAIN="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--forward-domain requires a value${CoR}"
          exit 1
        fi
        ;;
      --forward-scheme | -f)
        if [[ -n "$2" && "$2" =~ ^(http|https)$ ]]; then
          FORWARD_SCHEME="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--forward-scheme must be 'http' or 'https'${CoR}"
          exit 1
        fi
        ;;
      --http-code)
        if [[ -n "$2" && "$2" =~ ^(301|302|303|307|308)$ ]]; then
          FORWARD_HTTP_CODE="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--http-code must be 301, 302, 303, 307, or 308${CoR}"
          exit 1
        fi
        ;;
      --preserve-path)
        if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
          PRESERVE_PATH="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--preserve-path must be 'true' or 'false'${CoR}"
          exit 1
        fi
        ;;
      -b | --block-exploits)
        if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
          BLOCK_EXPLOITS="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--block-exploits must be 'true' or 'false'${CoR}"
          exit 1
        fi
        ;;
      -a | --advanced-config)
        if [[ -n "$2" && "$2" != -* ]]; then
          ADVANCED_CONFIG="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--advanced-config requires a value${CoR}"
          exit 1
        fi
        ;;
      -y)
        AUTO_YES=true
        shift
        ;;
      *)
        if [[ "$1" == -* ]]; then echo -e "\n ⚠️ ${COLOR_YELLOW}WARNING: Unknown option ignored -> $1${CoR}"; fi
        shift
        ;;
      esac
    done
    if [ -z "$FORWARD_DOMAIN" ]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --forward-domain is required${CoR}"
      echo -e "   Example: ${COLOR_GREEN}$0 --redirect-host-create example.com --forward-domain target.com${CoR}"
      exit 1
    fi
    REDIRECT_HOST_CREATE=true
    ;;
  --redirect-host-delete)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --redirect-host-delete requires a host 🆔.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --redirect-host-delete <id> [-y]${CoR}"
      echo -e "   Example: ${COLOR_GREEN}$0 --redirect-host-delete 5${CoR}"
      exit 1
    fi
    if [[ "$1" =~ ^[0-9]+$ ]]; then
      REDIRECT_HOST_ID="$1"
      REDIRECT_HOST_DELETE=true
      shift
    else
      echo -e "\n ⛔ ${COLOR_RED}INVALID: ID must be a number.${CoR}"
      exit 1
    fi
    ;;
  --redirect-host-enable)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --redirect-host-enable requires a host 🆔.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --redirect-host-enable <id>${CoR}"
      exit 1
    fi
    REDIRECT_HOST_ID="$1"
    REDIRECT_HOST_ENABLE=true
    shift
    ;;
  --redirect-host-disable)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --redirect-host-disable requires a host 🆔.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --redirect-host-disable <id>${CoR}"
      exit 1
    fi
    REDIRECT_HOST_ID="$1"
    REDIRECT_HOST_DISABLE=true
    shift
    ;;
  --stream-host-list)
    STREAM_HOST_LIST=true
    shift
    ;;
  --stream-host-create)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]] || ! [[ "$1" =~ ^[0-9]+$ ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --stream-host-create requires an incoming port (number).${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --stream-host-create <incoming_port> --forward-host <host> --forward-port <port> [options]${CoR}"
      echo -e "   Options:"
      echo -e "     --forward-host  host|ip     Target host (${COLOR_RED}required${CoR})"
      echo -e "     --forward-port  port        Target port (${COLOR_RED}required${CoR})"
      echo -e "     --tcp                       Enable TCP forwarding"
      echo -e "     --udp                       Enable UDP forwarding"
      echo -e "     --cert-id       id          Certificate ID (default: 0)"
      exit 1
    fi
    INCOMING_PORT="$1"
    shift
    while [[ $# -gt 0 ]]; do
      case "$1" in
      --forward-host)
        if [[ -n "$2" && "$2" != -* ]]; then
          FORWARD_HOST="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--forward-host requires a value${CoR}"
          exit 1
        fi
        ;;
      --forward-port)
        if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then
          FORWARD_PORT="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--forward-port must be a number${CoR}"
          exit 1
        fi
        ;;
      --tcp)
        TCP_FORWARDING=true
        shift
        ;;
      --udp)
        UDP_FORWARDING=true
        shift
        ;;
      --cert-id)
        if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then
          CERT_ID="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--cert-id must be a number${CoR}"
          exit 1
        fi
        ;;
      -y)
        AUTO_YES=true
        shift
        ;;
      *)
        if [[ "$1" == -* ]]; then echo -e "\n ⚠️ ${COLOR_YELLOW}WARNING: Unknown option ignored -> $1${CoR}"; fi
        shift
        ;;
      esac
    done
    if [ -z "$FORWARD_HOST" ] || [ -z "$FORWARD_PORT" ]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --forward-host and --forward-port are required${CoR}"
      echo -e "   Example: ${COLOR_GREEN}$0 --stream-host-create 53 --forward-host pihole --forward-port 53 --tcp --udp${CoR}"
      exit 1
    fi
    STREAM_HOST_CREATE=true
    ;;
  --stream-host-delete)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --stream-host-delete requires a host 🆔.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --stream-host-delete <id> [-y]${CoR}"
      echo -e "   Example: ${COLOR_GREEN}$0 --stream-host-delete 5${CoR}"
      exit 1
    fi
    if [[ "$1" =~ ^[0-9]+$ ]]; then
      STREAM_HOST_ID="$1"
      STREAM_HOST_DELETE=true
      shift
    else
      echo -e "\n ⛔ ${COLOR_RED}INVALID: ID must be a number.${CoR}"
      exit 1
    fi
    ;;
  --stream-host-enable)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --stream-host-enable requires a host 🆔.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --stream-host-enable <id>${CoR}"
      exit 1
    fi
    STREAM_HOST_ID="$1"
    STREAM_HOST_ENABLE=true
    shift
    ;;
  --stream-host-disable)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --stream-host-disable requires a host 🆔.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --stream-host-disable <id>${CoR}"
      exit 1
    fi
    STREAM_HOST_ID="$1"
    STREAM_HOST_DISABLE=true
    shift
    ;;
  --dead-host-list)
    DEAD_HOST_LIST=true
    shift
    ;;
  --dead-host-create)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --dead-host-create requires a domain name.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --dead-host-create domain.com [options]${CoR}"
      echo -e "   Options:"
      echo -e "     --cert-id          id          Certificate ID (default: 0)"
      echo -e "     --ssl-forced       true|false  (default: false)"
      echo -e "     --http2            true|false  (default: false)"
      echo -e "     --hsts             true|false  (default: false)"
      echo -e "     --hsts-subdomains  true|false  (default: false)"
      echo -e "     --advanced-config  string      Custom nginx config"
      exit 1
    fi
    DOMAIN_NAMES="$1"
    shift
    while [[ $# -gt 0 ]]; do
      case "$1" in
      --cert-id)
        if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then
          CERT_ID="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--cert-id must be a number${CoR}"
          exit 1
        fi
        ;;
      --ssl-forced)
        if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
          SSL_FORCED="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--ssl-forced must be 'true' or 'false'${CoR}"
          exit 1
        fi
        ;;
      --http2)
        if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
          HTTP2_SUPPORT="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--http2 must be 'true' or 'false'${CoR}"
          exit 1
        fi
        ;;
      --hsts)
        if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
          HSTS_ENABLED="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--hsts must be 'true' or 'false'${CoR}"
          exit 1
        fi
        ;;
      --hsts-subdomains)
        if [[ -n "$2" && "$2" =~ ^(true|false)$ ]]; then
          HSTS_SUBDOMAINS="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--hsts-subdomains must be 'true' or 'false'${CoR}"
          exit 1
        fi
        ;;
      -a | --advanced-config)
        if [[ -n "$2" && "$2" != -* ]]; then
          ADVANCED_CONFIG="$2"
          shift 2
        else
          echo -e "\n ⛔ ${COLOR_RED}--advanced-config requires a value${CoR}"
          exit 1
        fi
        ;;
      -y)
        AUTO_YES=true
        shift
        ;;
      *)
        if [[ "$1" == -* ]]; then echo -e "\n ⚠️ ${COLOR_YELLOW}WARNING: Unknown option ignored -> $1${CoR}"; fi
        shift
        ;;
      esac
    done
    DEAD_HOST_CREATE=true
    ;;
  --dead-host-delete)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --dead-host-delete requires a host 🆔.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --dead-host-delete <id> [-y]${CoR}"
      echo -e "   Example: ${COLOR_GREEN}$0 --dead-host-delete 5${CoR}"
      exit 1
    fi
    if [[ "$1" =~ ^[0-9]+$ ]]; then
      DEAD_HOST_ID="$1"
      DEAD_HOST_DELETE=true
      shift
    else
      echo -e "\n ⛔ ${COLOR_RED}INVALID: ID must be a number.${CoR}"
      exit 1
    fi
    ;;
  --dead-host-enable)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --dead-host-enable requires a host 🆔.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --dead-host-enable <id>${CoR}"
      exit 1
    fi
    DEAD_HOST_ID="$1"
    DEAD_HOST_ENABLE=true
    shift
    ;;
  --dead-host-disable)
    shift
    if [ $# -eq 0 ] || [[ "$1" == -* ]]; then
      echo -e "\n ⛔ ${COLOR_RED}INVALID: --dead-host-disable requires a host 🆔.${CoR}"
      echo -e "   Usage  : ${COLOR_ORANGE}$0 --dead-host-disable <id>${CoR}"
      exit 1
    fi
    DEAD_HOST_ID="$1"
    DEAD_HOST_DISABLE=true
    shift
    ;;
  *)
    echo -e "\n ${COLOR_RED}⛔ Unknown option:${CoR} $1"
    echo -e "    ${COLOR_GREY}Use --help to see available commands.${CoR}\n"
    exit 1
    ;;
  esac
  #shift
done

##############################################################
# logic
##############################################################
#echo "Debug after case: ACCESS_LIST_DELETE=$ACCESS_LIST_DELETE ACCESS_LIST_ID=$ACCESS_LIST_ID AUTO_YES=$AUTO_YES"

if [ "$LIST_JSON_COMMANDS" = true ]; then
  list_json_commands
elif [ "$SHOW_HELP" = true ]; then
  show_help
elif [ "$SHOW_DEFAULT" = true ]; then
  show_default
elif [ "$EXAMPLES" = true ]; then
  examples_cli
elif [ "$CHECK_TOKEN" = true ]; then
  check_token true
elif [ "$CHECK_UPDATE" = true ]; then
  check_update
elif [ "$INFO" = true ]; then
  display_info
# Actions users
elif [ "$USER_CREATE" = true ]; then
  user_create "$USERNAME" "$PASSWORD" "$EMAIL"
elif [ "$USER_DELETE" = true ]; then
  user_delete "$USER_ID"
elif [ "$USER_LIST" = true ]; then
  user_list

elif [ "$CERT_DELETE" = true ]; then
  cert_delete "$CERT_ID"
elif [ "$CERT_SHOW" = true ]; then
  cert_show "$search_term"
elif [ "$LIST_CERT_ALL" = true ]; then
  list_cert_all
elif [ "$CERT_DOWNLOAD" = true ]; then
  cert_download "$CERT_ID" "${CERT_OUTPUT_DIR:-./certificates}" "${CERT_NAME:-certificate_$CERT_ID}"

elif [ "$ACCESS_LIST" = true ]; then
  access_list
elif [ "$ACCESS_LIST_CREATE" = true ]; then
  access_list_create "${ACCESS_LIST_CREATE_ARGS[@]}"
elif [ "$ACCESS_LIST_UPDATE" = true ]; then
  access_list_update "${ACCESS_LIST_UPDATE_ARGS[@]}"
elif [ "$ACCESS_LIST_DELETE" = true ]; then
  access_list_delete
elif [ "$ACCESS_LIST_SHOW" = true ]; then
  access_list_show "$ACCESS_LIST_ID"

# Actions hotes
elif [ "$HOST_LIST" = true ]; then
  host_list
elif [ "$HOST_LIST_FULL" = true ]; then
  host_list_full
elif [ "$HOST_SEARCH" = true ]; then
  host_search
elif [ "$HOST_SHOW" = true ]; then
  host_show "$HOST_ID"

elif [ "$HOST_CREATE" = true ]; then
  # Certificate generation (--cert-generate) is handled inside create_or_update_proxy_host
  create_or_update_proxy_host "$DOMAIN_NAMES" "$FORWARD_HOST" "$FORWARD_PORT"
  exit 0

# Actions SSL
elif [ "$CERT_GENERATE" = true ] && [ "$HOST_CREATE" != true ]; then # ✅ Ajout de la condition
  cert_generate "$CERT_DOMAIN" "$CERT_EMAIL" "$CERT_DNS_PROVIDER" "$CERT_DNS_CREDENTIALS"
  if [ "$HOST_SSL_ENABLE" = true ]; then
    host_ssl_enable "$HOST_ID"
    exit 0
  fi

  #elif [ "$CERT_GENERATE" = true ]; then
  #    cert_generate "$CERT_DOMAIN" "$CERT_EMAIL" "$CERT_DNS_PROVIDER" "$CERT_DNS_CREDENTIALS"
  #  If --host-ssl-enable
#    if [ "$HOST_SSL_ENABLE" = true ]; then
#        host_ssl_enable "$HOST_ID"
#        exit 0
#    fi

elif [ "$HOST_DELETE" = true ]; then
  host_delete "$HOST_ID"
elif [ "$HOST_ENABLE" = true ]; then
  host_enable "$HOST_ID"
elif [ "$HOST_DISABLE" = true ]; then
  host_disable "$HOST_ID"

elif [ "$HOST_UPDATE" = true ]; then
  host_update "$HOST_ID" "$FIELD" "$VALUE"
  exit 0

# Actions ACL
elif [ "$HOST_ACL_ENABLE" = true ]; then
  host_acl_enable
elif [ "$HOST_ACL_DISABLE" = true ]; then
  host_acl_disable

# Redirection Host Management
elif [ "$REDIRECT_HOST_LIST" = true ]; then
  redirect_host_list
elif [ "$REDIRECT_HOST_CREATE" = true ]; then
  create_or_update_redirect_host
elif [ "$REDIRECT_HOST_DELETE" = true ]; then
  redirect_host_delete "$REDIRECT_HOST_ID"
elif [ "$REDIRECT_HOST_ENABLE" = true ]; then
  redirect_host_enable "$REDIRECT_HOST_ID"
elif [ "$REDIRECT_HOST_DISABLE" = true ]; then
  redirect_host_disable "$REDIRECT_HOST_ID"

# Stream Host Management
elif [ "$STREAM_HOST_LIST" = true ]; then
  stream_host_list
elif [ "$STREAM_HOST_CREATE" = true ]; then
  create_or_update_stream_host
elif [ "$STREAM_HOST_DELETE" = true ]; then
  stream_host_delete "$STREAM_HOST_ID"
elif [ "$STREAM_HOST_ENABLE" = true ]; then
  stream_host_enable "$STREAM_HOST_ID"
elif [ "$STREAM_HOST_DISABLE" = true ]; then
  stream_host_disable "$STREAM_HOST_ID"

# Dead Host (404) Management
elif [ "$DEAD_HOST_LIST" = true ]; then
  dead_host_list
elif [ "$DEAD_HOST_CREATE" = true ]; then
  create_or_update_dead_host
elif [ "$DEAD_HOST_DELETE" = true ]; then
  dead_host_delete "$DEAD_HOST_ID"
elif [ "$DEAD_HOST_ENABLE" = true ]; then
  dead_host_enable "$DEAD_HOST_ID"
elif [ "$DEAD_HOST_DISABLE" = true ]; then
  dead_host_disable "$DEAD_HOST_ID"

elif [ "$HOST_SSL_ENABLE" = true ]; then
  host_ssl_enable "$HOST_ID" "$CERT_ID"
elif [ "$HOST_SSL_DISABLE" = true ]; then
  host_ssl_disable
elif [ "$SSL_RESTORE" = true ]; then
  restore_ssl_certificates

# Actions backup/restore
elif [ "$BACKUP" = true ]; then
  full_backup
elif [ "$BACKUP_HOST" = true ]; then
  backup_host
elif [ "$BACKUP_LIST" = true ]; then
  list_backups
elif [ "$CLEAN_HOSTS" = true ]; then
  clean-hosts
  #reimport_hosts "$@"
  #reimport_hosts "$BACKUP_FILE"
  #exit $?
  #check_validity_of_backup_file "$BACKUP_FILE"

else
  display_info
  exit 0
  #
  # echo -e "\n ⛔ ${COLOR_RED}No valid option provided${CoR}"
  # echo -e " Use --help to see available commands."
  # exit 1
fi