#!/bin/bash

cat << "EOF"
  ██████╗██╗  ██╗ █████╗ ███╗   ██╗ ██████╗ ███████╗
 ██╔════╝██║  ██║██╔══██╗████╗  ██║██╔════╝ ██╔════╝
 ██║     ███████║███████║██╔██╗ ██║██║  ███╗█████╗  
 ██║     ██╔══██║██╔══██║██║╚██╗██║██║   ██║██╔══╝  
 ╚██████╗██║  ██║██║  ██║██║ ╚████║╚██████╔╝███████╗
  ╚═════╝╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚══════╝
                                                    
 ███╗   ███╗ █████╗ ██╗  ██╗███████╗██████╗ 
 ████╗ ████║██╔══██╗██║ ██╔╝██╔════╝██╔══██╗
 ██╔████╔██║███████║█████╔╝ █████╗  ██████╔╝
 ██║╚██╔╝██║██╔══██║██╔═██╗ ██╔══╝  ██╔══██╗
 ██║ ╚═╝ ██║██║  ██║██║  ██╗███████╗██║  ██║
 ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝
                        Configuration Wizard
EOF

# Get the absolute path of the script directory
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ENV_FILE="$SCRIPT_DIR/.env"
MKDOCS_YML="$SCRIPT_DIR/mkdocs/mkdocs.yml"  # Fixed path - removed extra 'docs' directory
TUNNEL_CONFIG_DIR="$SCRIPT_DIR/configs/cloudflare"
TUNNEL_CONFIG_FILE="$TUNNEL_CONFIG_DIR/tunnel-config.yml"
SERVICES_YAML="$SCRIPT_DIR/configs/homepage/services.yaml"
MAIN_HTML="$SCRIPT_DIR/mkdocs/docs/overrides/main.html"
MAP_ENV_FILE="$SCRIPT_DIR/map/.env"  # Add the map's .env file path
DOCKER_COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml"

echo "Looking for .env file at: $ENV_FILE"

# Function to generate a random secure password
generate_password() {
  local length=${1:-16}
  openssl rand -base64 48 | tr -dc 'a-zA-Z0-9!@#$%^&*()-_=+' | head -c "$length"
}

# Function to safely update environment variables in .env file
update_env_var() {
  local key=$1
  local value=$2
  
  # More robust method to handle special characters in passwords
  if grep -q "^$key=" "$ENV_FILE"; then
    # Create a temporary file
    local tmpfile=$(mktemp)
    
    # Process the .env file line by line
    while IFS= read -r line; do
      if [[ "$line" =~ ^$key= ]]; then
        echo "$key=$value" >> "$tmpfile"
      else
        echo "$line" >> "$tmpfile"
      fi
    done < "$ENV_FILE"
    
    # Replace the original file with the temporary file
    mv "$tmpfile" "$ENV_FILE"
    echo "Updated $key in .env file"
  else
    # Add new key-value pair if it doesn't exist
    echo "$key=$value" >> "$ENV_FILE"
    echo "Added $key to .env file"
  fi
}

# Function to create a timestamped backup of the .env file
backup_env_file() {
  if [ -f "$ENV_FILE" ]; then
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    local backup_file="$ENV_FILE.backup_$timestamp"
    
    echo "Creating backup of current .env file to: $backup_file"
    if cp "$ENV_FILE" "$backup_file"; then
      echo "Backup created successfully!"
      return 0
    else
      echo "Failed to create backup file. Proceeding with caution..."
      return 1
    fi
  fi
}

# Function to fix permissions on directories that containers need to write to
# This prevents EACCES errors when containers try to create files/directories
fix_container_permissions() {
  echo ""
  echo "=== Fixing Container Directory Permissions ==="
  echo "Setting up directories that containers need write access to..."
  
  # Get the user/group IDs (default to 1000 if not set)
  local user_id=${USER_ID:-1000}
  local group_id=${GROUP_ID:-1000}
  
  # Define directories that need to be writable by containers
  # Format: "path:description"
  local -a writable_dirs=(
    "$SCRIPT_DIR/configs/code-server/.config:Code Server config"
    "$SCRIPT_DIR/configs/code-server/.local:Code Server local data"
    "$SCRIPT_DIR/mkdocs/.cache:MkDocs cache (social cards, etc.)"
    "$SCRIPT_DIR/mkdocs/site:MkDocs built site"
    "$SCRIPT_DIR/assets/uploads:Listmonk uploads"
    "$SCRIPT_DIR/assets/images:Shared images"
  )
  
  local errors=0
  
  for dir_entry in "${writable_dirs[@]}"; do
    local dir_path="${dir_entry%%:*}"
    local dir_desc="${dir_entry#*:}"
    
    # Create directory if it doesn't exist
    if [ ! -d "$dir_path" ]; then
      echo "  Creating: $dir_path ($dir_desc)"
      mkdir -p "$dir_path"
    fi
    
    # Add .gitkeep to track empty directories in git
    if [ ! -f "$dir_path/.gitkeep" ]; then
      touch "$dir_path/.gitkeep"
    fi
    
    # Fix permissions - make writable by container user
    if chmod -R 777 "$dir_path" 2>/dev/null; then
      echo "  ✅ $dir_desc: permissions fixed"
    else
      echo "  ⚠️  $dir_desc: could not fix permissions (may need sudo)"
      ((errors++))
    fi
  done
  
  # Handle directories that may have been created by containers with different UIDs
  # These need special handling (may require sudo)
  local -a potentially_owned_by_container=(
    "$SCRIPT_DIR/mkdocs/site"
  )
  
  for dir_path in "${potentially_owned_by_container[@]}"; do
    if [ -d "$dir_path" ]; then
      # Check if we own the directory
      if [ ! -w "$dir_path" ]; then
        echo ""
        echo "  ⚠️  Directory $dir_path is not writable."
        echo "      This may have been created by a container with a different UID."
        echo "      To fix, run: sudo chown -R $user_id:$group_id $dir_path"
        ((errors++))
      fi
    fi
  done
  
  echo ""
  if [ $errors -eq 0 ]; then
    echo "✅ All container directories are properly configured!"
  else
    echo "⚠️  Some directories may need manual permission fixes."
    echo "   You can try: sudo chown -R $user_id:$group_id $SCRIPT_DIR"
  fi
  echo ""
  
  return $errors
}

# Function to get all used ports on the system
get_used_ports() {
  local used_ports=()
  
  # Try different methods to get used ports, in order of preference
  if command -v ss >/dev/null 2>&1; then
    # Use ss (preferred, modern replacement for netstat)
    while IFS= read -r line; do
      if [[ "$line" =~ :([0-9]+)[[:space:]] ]]; then
        used_ports+=("${BASH_REMATCH[1]}")
      fi
    done < <(ss -tuln 2>/dev/null | grep -E ':[0-9]+[[:space:]]')
  elif command -v netstat >/dev/null 2>&1; then
    # Use netstat (fallback)
    while IFS= read -r line; do
      if [[ "$line" =~ :([0-9]+)[[:space:]] ]]; then
        used_ports+=("${BASH_REMATCH[1]}")
      fi
    done < <(netstat -tuln 2>/dev/null | grep -E ':[0-9]+[[:space:]]')
  elif command -v lsof >/dev/null 2>&1; then
    # Use lsof (another fallback)
    while IFS= read -r line; do
      if [[ "$line" =~ :([0-9]+)[[:space:]] ]]; then
        used_ports+=("${BASH_REMATCH[1]}")
      fi
    done < <(lsof -i -P -n 2>/dev/null | grep LISTEN | grep -E ':[0-9]+[[:space:]]')
  else
    echo "Warning: No port scanning tools available (ss, netstat, or lsof)"
    return 1
  fi
  
  # Remove duplicates and sort
  printf '%s\n' "${used_ports[@]}" | sort -nu
}

# Function to check if a specific port is available
is_port_available() {
  local port=$1
  local used_ports_list=$2
  
  # Check if port is in the used ports list
  if echo "$used_ports_list" | grep -q "^$port$"; then
    return 1  # Port is in use
  else
    return 0  # Port is available
  fi
}

# Function to find next available port starting from a given port
find_next_available_port() {
  local start_port=$1
  local used_ports_list=$2
  local max_attempts=${3:-100}  # Maximum ports to check
  
  for ((i=0; i<max_attempts; i++)); do
    local test_port=$((start_port + i))
    
    # Skip ports below 1024 (system ports) and above 65535
    if [ "$test_port" -lt 1024 ] || [ "$test_port" -gt 65535 ]; then
      continue
    fi
    
    if is_port_available "$test_port" "$used_ports_list"; then
      echo "$test_port"
      return 0
    fi
  done
  
  echo "Error: Could not find available port starting from $start_port" >&2
  return 1
}

# Function to initialize available ports for services
initialize_available_ports() {
  echo "Scanning system for used ports to avoid conflicts..."
  
  # Get list of all used ports
  local used_ports_list
  used_ports_list=$(get_used_ports)
  
  if [ $? -ne 0 ] || [ -z "$used_ports_list" ]; then
    echo "Warning: Could not scan system ports. Using default ports."
    echo "You may need to manually resolve conflicts later."
    return 1
  fi
  
  echo "Found $(echo "$used_ports_list" | wc -l) ports currently in use"
  
  # Define desired starting ports for each service
  local -A service_ports=(
    ["CODE_SERVER_PORT"]=8888
    ["LISTMONK_PORT"]=9000
    ["LISTMONK_DB_PORT"]=5432
    ["MKDOCS_PORT"]=4000
    ["MKDOCS_SITE_SERVER_PORT"]=4001
    ["N8N_PORT"]=5678
    ["NOCODB_PORT"]=8090
    ["HOMEPAGE_PORT"]=3010
    ["GITEA_WEB_PORT"]=3030
    ["GITEA_SSH_PORT"]=2222
    ["MAP_PORT"]=3000
    ["INFLUENCE_PORT"]=3333
    ["MINI_QR_PORT"]=8089
    ["REDIS_PORT"]=6379
    ["PROMETHEUS_PORT"]=9090
    ["GRAFANA_PORT"]=3001
    ["CADVISOR_PORT"]=8080
    ["NODE_EXPORTER_PORT"]=9100
    ["REDIS_EXPORTER_PORT"]=9121
    ["ALERTMANAGER_PORT"]=9093
    ["GOTIFY_PORT"]=8889
    ["MAILHOG_SMTP_PORT"]=1025
    ["MAILHOG_WEB_PORT"]=8025
  )
  
  # Find available ports for each service
  local -A available_ports
  for service in "${!service_ports[@]}"; do
    local preferred_port=${service_ports[$service]}
    local available_port
    
    if is_port_available "$preferred_port" "$used_ports_list"; then
      available_port=$preferred_port
      echo "✅ $service: Using preferred port $preferred_port"
    else
      available_port=$(find_next_available_port "$preferred_port" "$used_ports_list")
      if [ $? -eq 0 ]; then
        echo "⚠️  $service: Port $preferred_port in use, using $available_port instead"
      else
        echo "❌ $service: Could not find available port, using $preferred_port (may conflict)"
        available_port=$preferred_port
      fi
    fi
    
    available_ports[$service]=$available_port
    # Add the assigned port to used_ports_list to avoid double-assignment
    used_ports_list=$(printf '%s\n%s' "$used_ports_list" "$available_port" | sort -nu)
  done
  
  # Export the available ports as global variables
  for service in "${!available_ports[@]}"; do
    export "$service=${available_ports[$service]}"
  done
  
  echo "Port assignment completed successfully!"
  return 0
}

# Function to initialize the .env file with default values
initialize_env_file() {
  echo "Initializing new .env file with available ports..."
  
  # Initialize available ports before creating the .env file
  initialize_available_ports
  
  cat > "$ENV_FILE" << EOL
# Never share this file publicly. It contains sensitive information.
# This file is used to configure various applications and services.
# Generated by Changemaker Config Wizard on $(date)

# User and Group Configuration
USER_NAME=coder
USER_ID=1000
GROUP_ID=1000

# Port Configuration (automatically assigned to avoid conflicts)
CODE_SERVER_PORT=${CODE_SERVER_PORT:-8888}
LISTMONK_PORT=${LISTMONK_PORT:-9000}
LISTMONK_DB_PORT=${LISTMONK_DB_PORT:-5432}
MKDOCS_PORT=${MKDOCS_PORT:-4000}
MKDOCS_SITE_SERVER_PORT=${MKDOCS_SITE_SERVER_PORT:-4001}
N8N_PORT=${N8N_PORT:-5678}
NOCODB_PORT=${NOCODB_PORT:-8090}
HOMEPAGE_PORT=${HOMEPAGE_PORT:-3010}
GITEA_WEB_PORT=${GITEA_WEB_PORT:-3030}
GITEA_SSH_PORT=${GITEA_SSH_PORT:-2222}
MAP_PORT=${MAP_PORT:-3000}
INFLUENCE_PORT=${INFLUENCE_PORT:-3333}
MINI_QR_PORT=${MINI_QR_PORT:-8089}

# Centralized Services Ports
REDIS_PORT=${REDIS_PORT:-6379}
PROMETHEUS_PORT=${PROMETHEUS_PORT:-9090}
GRAFANA_PORT=${GRAFANA_PORT:-3001}

# Monitoring Exporters Ports
CADVISOR_PORT=${CADVISOR_PORT:-8080}
NODE_EXPORTER_PORT=${NODE_EXPORTER_PORT:-9100}
REDIS_EXPORTER_PORT=${REDIS_EXPORTER_PORT:-9121}

# Alerting Services Ports
ALERTMANAGER_PORT=${ALERTMANAGER_PORT:-9093}
GOTIFY_PORT=${GOTIFY_PORT:-8889}

# MailHog Email Testing Ports
MAILHOG_SMTP_PORT=${MAILHOG_SMTP_PORT:-1025}
MAILHOG_WEB_PORT=${MAILHOG_WEB_PORT:-8025}

# Domain Configuration
BASE_DOMAIN=https://changeme.org
DOMAIN=changeme.org
LISTMONK_HOSTNAME=listmonk.changeme.org
N8N_HOST=n8n.changeme.org
GITEA_DOMAIN=git.changeme.org
GITEA_ROOT_URL=https://git.changeme.org
HOMEPAGE_VAR_BASE_URL=https://changeme.org

# Cookie and CORS Configuration
COOKIE_DOMAIN=.changeme.org
ALLOWED_ORIGINS=https://map.changeme.org,http://localhost:3000

# Cloudflare Configuration
CF_API_TOKEN=your_cloudflare_api_token
CF_ZONE_ID=your_cloudflare_zone_id
CF_TUNNEL_ID=your_cloudflared_tunnel_id
CF_DOMAIN=changeme.org
CF_ACCOUNT_ID=your_cloudflare_account_id

# Database Configuration (PostgreSQL for Listmonk)
POSTGRES_USER=listmonk
POSTGRES_PASSWORD=changeMe
POSTGRES_DB=listmonk

# Listmonk Database Performance Settings
LISTMONK_DB_MAX_OPEN=25
LISTMONK_DB_MAX_IDLE=25
LISTMONK_DB_MAX_LIFETIME=300s

# Listmonk Admin Configuration
LISTMONK_ADMIN_USER=admin
LISTMONK_ADMIN_PASSWORD=changeMe

# N8N Configuration
N8N_USER_EMAIL=admin@example.com
N8N_USER_PASSWORD=changeMe
N8N_ENCRYPTION_KEY=changeMe
GENERIC_TIMEZONE=UTC

# Nocodb Configuration
NOCODB_JWT_SECRET=changeMe
NOCODB_DB_NAME=nocodb
NOCODB_DB_USER=noco
NOCODB_DB_PASSWORD=changeMe

# Gitea Database Configuration
GITEA_DB_PASSWD=changeMe
GITEA_DB_ROOT_PASSWORD=changeMe

# Centralized Services Configuration
# Redis (used by all applications for caching, sessions, queues)
REDIS_HOST=redis-changemaker
REDIS_PORT=6379
REDIS_PASSWORD=

# Prometheus (metrics collection)
PROMETHEUS_PORT=9090
PROMETHEUS_RETENTION_TIME=30d

# Grafana (monitoring dashboards)
GRAFANA_PORT=3001
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=changeMe
GRAFANA_ROOT_URL=http://localhost:3001

# Monitoring Exporters
CADVISOR_PORT=8080
NODE_EXPORTER_PORT=9100
REDIS_EXPORTER_PORT=9121

# Alertmanager (alert routing)
ALERTMANAGER_PORT=9093

# Gotify (push notifications)
GOTIFY_PORT=8889
GOTIFY_ADMIN_USER=admin
GOTIFY_ADMIN_PASSWORD=changeMe
GOTIFY_APP_TOKEN=

# Alert Email Configuration
ALERT_EMAIL_TO=admin@changeme.org
EOL

  echo "New .env file created with conflict-free port assignments."
  
  # Show port assignments summary
  echo ""
  echo "=== Port Assignments Summary ==="
  echo "Code Server: ${CODE_SERVER_PORT:-8888}"
  echo "Listmonk: ${LISTMONK_PORT:-9000}"
  echo "Listmonk DB: ${LISTMONK_DB_PORT:-5432}"
  echo "MkDocs: ${MKDOCS_PORT:-4000}"
  echo "MkDocs Site: ${MKDOCS_SITE_SERVER_PORT:-4001}"
  echo "N8N: ${N8N_PORT:-5678}"
  echo "NocoDB: ${NOCODB_PORT:-8090}"
  echo "Homepage: ${HOMEPAGE_PORT:-3010}"
  echo "Gitea Web: ${GITEA_WEB_PORT:-3030}"
  echo "Gitea SSH: ${GITEA_SSH_PORT:-2222}"
  echo "Map: ${MAP_PORT:-3000}"
  echo "Influence: ${INFLUENCE_PORT:-3333}"
  echo "Mini QR: ${MINI_QR_PORT:-8089}"
  echo ""
  echo "=== Centralized Services ==="
  echo "Redis: ${REDIS_PORT:-6379}"
  echo "Prometheus: ${PROMETHEUS_PORT:-9090}"
  echo "Grafana: ${GRAFANA_PORT:-3001}"
  echo ""
  echo "=== Monitoring Services ==="
  echo "cAdvisor: ${CADVISOR_PORT:-8080}"
  echo "Node Exporter: ${NODE_EXPORTER_PORT:-9100}"
  echo "Redis Exporter: ${REDIS_EXPORTER_PORT:-9121}"
  echo "Alertmanager: ${ALERTMANAGER_PORT:-9093}"
  echo "Gotify: ${GOTIFY_PORT:-8889}"
  echo ""
  echo "=== Email Testing ==="
  echo "MailHog SMTP: ${MAILHOG_SMTP_PORT:-1025}"
  echo "MailHog Web: ${MAILHOG_WEB_PORT:-8025}"
  echo "================================"
}

# Function to update the site_url in mkdocs.yml
update_mkdocs_yml() {
  local new_domain=$1
  
  if [ ! -f "$MKDOCS_YML" ]; then
    echo "Warning: mkdocs.yml not found at $MKDOCS_YML"
    return 1
  fi
  
  echo "Updating site_url in mkdocs.yml..."
  
  # Create a backup of the mkdocs.yml file
  local timestamp=$(date +"%Y%m%d_%H%M%S")
  local backup_file="${MKDOCS_YML}.backup_${timestamp}"
  cp "$MKDOCS_YML" "$backup_file"
  echo "Created backup of mkdocs.yml at $backup_file"
  
  # Update the site_url value - handle both http and https
  sed -i "s|^site_url:.*|site_url: https://$new_domain|" "$MKDOCS_YML"
  
  if grep -q "site_url: https://$new_domain" "$MKDOCS_YML"; then
    echo "✅ Updated site_url in mkdocs.yml to: https://$new_domain"
    return 0
  else
    echo "Warning: Failed to update site_url in mkdocs.yml"
    return 1
  fi
}

# Function to update service URLs in services.yaml
update_services_yaml() {
  local new_domain=$1
  local local_ip=${2:-"localhost"}  # Optional parameter for local IP address

  if [ ! -f "$SERVICES_YAML" ]; then
    echo "Warning: services.yaml not found at $SERVICES_YAML"
    return 1
  fi

  echo "Updating service URLs in services.yaml..."

  # Create a backup of the services.yaml file
  local timestamp=$(date +"%Y%m%d_%H%M%S")
  local backup_file="${SERVICES_YAML}.backup_${timestamp}"
  cp "$SERVICES_YAML" "$backup_file"
  echo "Created backup of services.yaml at $backup_file"

  # Load environment variables to get port numbers
  load_env_vars

  # Define service name to subdomain mapping for Production tab
  # This approach is URL-agnostic - it doesn't matter what the current URLs are
  declare -A production_mappings=(
    ["Code Server"]="code.$new_domain"
    ["Listmonk"]="listmonk.$new_domain"
    ["NocoDB"]="db.$new_domain"
    ["Main Site"]="$new_domain"
    ["MkDocs (Live)"]="docs.$new_domain"
    ["Mini QR"]="qr.$new_domain"
    ["MailHog"]="mail.$new_domain"
    ["n8n"]="n8n.$new_domain"
    ["Gitea"]="git.$new_domain"
    ["Prometheus"]="prometheus.$new_domain"
    ["Grafana"]="grafana.$new_domain"
    ["Alertmanager"]="alertmanager.$new_domain"
    ["Gotify"]="gotify.$new_domain"
    ["cAdvisor"]="cadvisor.$new_domain"
  )

  # Define service name to local URL mapping for Local tab
  declare -A local_mappings=(
    ["Code Server"]="$local_ip:${CODE_SERVER_PORT:-8888}"
    ["NocoDB"]="$local_ip:${NOCODB_PORT:-8090}"
    ["Homepage"]="$local_ip:${HOMEPAGE_PORT:-3010}"
    ["Main Site"]="$local_ip:${MKDOCS_SITE_SERVER_PORT:-4001}"
    ["MkDocs (Live)"]="$local_ip:${MKDOCS_PORT:-4000}"
    ["Mini QR"]="$local_ip:${MINI_QR_PORT:-8089}"
    ["Listmonk"]="$local_ip:${LISTMONK_PORT:-9001}"
    ["MailHog"]="$local_ip:${MAILHOG_WEB_PORT:-8025}"
    ["n8n"]="$local_ip:${N8N_PORT:-5678}"
    ["Gitea"]="$local_ip:${GITEA_WEB_PORT:-3030}"
    ["Prometheus"]="$local_ip:${PROMETHEUS_PORT:-9090}"
    ["Grafana"]="$local_ip:${GRAFANA_PORT:-3001}"
    ["Alertmanager"]="$local_ip:${ALERTMANAGER_PORT:-9093}"
    ["Gotify"]="$local_ip:${GOTIFY_PORT:-8889}"
    ["cAdvisor"]="$local_ip:${CADVISOR_PORT:-8080}"
    ["Node Exporter"]="$local_ip:${NODE_EXPORTER_PORT:-9100}/metrics"
    ["Redis Exporter"]="$local_ip:${REDIS_EXPORTER_PORT:-9121}/metrics"
  )

  # Update Production URLs
  echo "Updating Production tab URLs..."
  for service_name in "${!production_mappings[@]}"; do
    local target_url="https://${production_mappings[$service_name]}"

    # Use awk to find and update the href for Production services only
    awk -v service="$service_name" -v new_url="$target_url" '
    BEGIN {
      in_production = 0
      in_service = 0
    }

    # Track if we are in Production section
    /^- Production/ { in_production = 1; in_service = 0 }
    /^- Local/ { in_production = 0; in_service = 0 }

    # Check if we found the service name in Production section
    in_production && /^    - [^:]+:/ {
      if ($0 ~ ("    - " service ":")) {
        in_service = 1
      } else {
        in_service = 0
      }
    }

    # If we are in the target service and find href line, update it
    in_production && in_service && /href:/ {
      gsub(/href: "[^"]*"/, "href: \"" new_url "\"")
    }

    # Print the line (modified or not)
    { print }
    ' "$SERVICES_YAML" > "${SERVICES_YAML}.tmp"

    mv "${SERVICES_YAML}.tmp" "$SERVICES_YAML"
    echo "  ✓ Production: $service_name -> $target_url"
  done

  # Update Local URLs
  echo "Updating Local tab URLs..."
  for service_name in "${!local_mappings[@]}"; do
    local target_url="http://${local_mappings[$service_name]}"

    # Use awk to find and update the href for Local services only
    awk -v service="$service_name" -v new_url="$target_url" '
    BEGIN {
      in_local = 0
      in_service = 0
    }

    # Track if we are in Local section
    /^- Local/ { in_local = 1; in_service = 0 }
    /^- Production/ { in_local = 0; in_service = 0 }

    # Check if we found the service name in Local section
    in_local && /^    - [^:]+:/ {
      if ($0 ~ ("    - " service ":")) {
        in_service = 1
      } else {
        in_service = 0
      }
    }

    # If we are in the target service and find href line, update it
    in_local && in_service && /href:/ {
      gsub(/href: "[^"]*"/, "href: \"" new_url "\"")
    }

    # Print the line (modified or not)
    { print }
    ' "$SERVICES_YAML" > "${SERVICES_YAML}.tmp"

    mv "${SERVICES_YAML}.tmp" "$SERVICES_YAML"
    echo "  ✓ Local: $service_name -> $target_url"
  done

  echo "✅ All service URLs updated:"
  echo "   - Production tab: $new_domain"
  echo "   - Local tab: $local_ip"
  return 0
}

# Function to update the login URL in main.html
update_main_html() {
  local new_domain=$1
  
  if [ ! -f "$MAIN_HTML" ]; then
    echo "Warning: main.html not found at $MAIN_HTML"
    return 1
  fi
  
  echo "Updating login URL in main.html..."
  
  # Create a backup of the main.html file
  local timestamp=$(date +"%Y%m%d_%H%M%S")
  local backup_file="${MAIN_HTML}.backup_${timestamp}"
  cp "$MAIN_HTML" "$backup_file"
  echo "Created backup of main.html at $backup_file"
  
  # Update the login button href - handle current domain
  sed -i "s|href=\"https://homepage\.[^\"]*\"|href=\"https://homepage.$new_domain\"|g" "$MAIN_HTML"
  
  # Also update any albertademocracytaskforce.org references
  sed -i "s|albertademocracytaskforce\.org|$new_domain|g" "$MAIN_HTML"
  
  # Update any test.com or changeme.org references
  sed -i "s|test\.com|$new_domain|g" "$MAIN_HTML"
  sed -i "s|changeme\.org|$new_domain|g" "$MAIN_HTML"
  
  echo "✅ Updated login URL in main.html to: https://homepage.$new_domain"
  return 0
}

# Function to get Cloudflare API Token and Zone ID
get_cloudflare_credentials() {
  echo ""
  echo "To use Cloudflare tunnels, you'll need to configure your credentials."
  echo ""
  echo "=== Cloudflare Configuration ==="
  echo ""
  echo "You'll need:"
  echo "1. Your Cloudflare API Token (with Zone.DNS and Account.Cloudflare Tunnel permissions)"
  echo "2. Your Cloudflare Zone ID (found in the Cloudflare dashboard overview)"
  echo "3. Your Cloudflare Account ID (found in the Cloudflare dashboard)"
  echo ""
  echo "These credentials will be used for:"
  echo "- Creating and configuring tunnels"
  echo "- Managing DNS records"
  echo "- Setting up access policies"
  echo ""
}

# Function to update the tunnel configuration file with new domain
update_tunnel_config() {
  local new_domain=$1
  local tunnel_id=${2:-"(insert-tunnel-id)"}
  local creds_path=${3:-"/path/to/credentials/file"}
  
  # Create directory if it doesn't exist
  mkdir -p "$TUNNEL_CONFIG_DIR"
  
  echo "Updating tunnel configuration with new domain..."
  
  # Create a backup if file exists
  if [ -f "$TUNNEL_CONFIG_FILE" ]; then
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    local backup_file="${TUNNEL_CONFIG_FILE}.backup_${timestamp}"
    cp "$TUNNEL_CONFIG_FILE" "$backup_file"
    echo "Created backup of tunnel-config.yml at $backup_file"
  fi
  
  # Load current environment variables to get port numbers
  load_env_vars
  
  # Create/update the tunnel configuration
  cat > "$TUNNEL_CONFIG_FILE" << EOL
# filepath: /home/bunker-admin/changemaker.lite/configs/cloudflare/tunnel-config.yml
# Cloudflare Tunnel Configuration
# Auto-generated by Changemaker Configuration Wizard

tunnel: $tunnel_id # e.g. 1234567890abcdef
credentials-file: $creds_path # e.g. /home/bunker-admin/.cloudflared/[insert tunnel number].json
ingress:

  - hostname: homepage.$new_domain
    service: http://localhost:${HOMEPAGE_PORT:-3010}

  - hostname: code.$new_domain
    service: http://localhost:${CODE_SERVER_PORT:-8888}

  - hostname: listmonk.$new_domain
    service: http://localhost:${LISTMONK_PORT:-9001}
    
  - hostname: docs.$new_domain
    service: http://localhost:${MKDOCS_PORT:-4000}
    
  - hostname: $new_domain
    service: http://localhost:${MKDOCS_SITE_SERVER_PORT:-4002}
    
  - hostname: n8n.$new_domain
    service: http://localhost:${N8N_PORT:-5678}
    
  - hostname: db.$new_domain
    service: http://localhost:${NOCODB_PORT:-8090}

  - hostname: git.$new_domain
    service: http://localhost:${GITEA_WEB_PORT:-3030}

  - hostname: map.$new_domain
    service: http://localhost:${MAP_PORT:-3000}

  - hostname: influence.$new_domain
    service: http://localhost:${INFLUENCE_PORT:-3333}

  - hostname: qr.$new_domain
    service: http://localhost:${MINI_QR_PORT:-8089}

  - hostname: prometheus.$new_domain
    service: http://localhost:${PROMETHEUS_PORT:-9090}

  - hostname: grafana.$new_domain
    service: http://localhost:${GRAFANA_PORT:-3001}

  - hostname: alertmanager.$new_domain
    service: http://localhost:${ALERTMANAGER_PORT:-9093}

  - hostname: gotify.$new_domain
    service: http://localhost:${GOTIFY_PORT:-8889}

  - hostname: cadvisor.$new_domain
    service: http://localhost:${CADVISOR_PORT:-8080}

  # Catch-all rule (required)
  - service: http_status:404
EOL
  
  echo "✅ Updated tunnel configuration for domain: $new_domain"
  return 0
}

# Function to load environment variables from .env file
load_env_vars() {
  if [ -f "$ENV_FILE" ]; then
    # Load variables from .env file, ignoring comments and empty lines
    while IFS= read -r line; do
      if [[ "$line" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then
        export "$line"
      fi
    done < <(grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$ENV_FILE")
  fi
}

# Function to sync ports from root .env to map .env
sync_map_ports() {
    echo "Syncing ports from root .env to map configuration..."
    
    # Load the current port values from root .env
    local mkdocs_port=$(grep "^MKDOCS_PORT=" "$ENV_FILE" | cut -d'=' -f2)
    local mkdocs_site_port=$(grep "^MKDOCS_SITE_SERVER_PORT=" "$ENV_FILE" | cut -d'=' -f2)
    local map_port=$(grep "^MAP_PORT=" "$ENV_FILE" | cut -d'=' -f2)
    
    # Set defaults if not found
    mkdocs_port=${mkdocs_port:-4000}
    mkdocs_site_port=${mkdocs_site_port:-4002}
    map_port=${map_port:-3000}
    
    # Update the map's .env with the correct ports
    if grep -q "^PORT=" "$MAP_ENV_FILE"; then
        sed -i "s|^PORT=.*|PORT=$map_port|" "$MAP_ENV_FILE"
    else
        echo "PORT=$map_port" >> "$MAP_ENV_FILE"
    fi
    
    # Add/Update MkDocs configuration
    if grep -q "^MKDOCS_URL=" "$MAP_ENV_FILE"; then
        sed -i "s|^MKDOCS_URL=.*|MKDOCS_URL=http://localhost:$mkdocs_site_port|" "$MAP_ENV_FILE"
    else
        echo "" >> "$MAP_ENV_FILE"
        echo "# MkDocs Integration" >> "$MAP_ENV_FILE"
        echo "MKDOCS_URL=http://localhost:$mkdocs_site_port" >> "$MAP_ENV_FILE"
    fi
    
    if grep -q "^MKDOCS_SEARCH_URL=" "$MAP_ENV_FILE"; then
        sed -i "s|^MKDOCS_SEARCH_URL=.*|MKDOCS_SEARCH_URL=http://localhost:$mkdocs_site_port|" "$MAP_ENV_FILE"
    else
        echo "MKDOCS_SEARCH_URL=http://localhost:$mkdocs_site_port" >> "$MAP_ENV_FILE"
    fi
    
    if grep -q "^MKDOCS_SITE_SERVER_PORT=" "$MAP_ENV_FILE"; then
        sed -i "s|^MKDOCS_SITE_SERVER_PORT=.*|MKDOCS_SITE_SERVER_PORT=$mkdocs_site_port|" "$MAP_ENV_FILE"
    else
        echo "MKDOCS_SITE_SERVER_PORT=$mkdocs_site_port" >> "$MAP_ENV_FILE"
    fi
    
    echo "✅ Synced ports to map configuration:"
    echo "   - Map Port: $map_port"
    echo "   - MkDocs Dev Port: $mkdocs_port"
    echo "   - MkDocs Site Port: $mkdocs_site_port"
    echo "   - MkDocs URL: http://localhost:$mkdocs_site_port"
}

# Function to update or create the map's .env file with domain settings
update_map_env() {
  local new_domain=$1

  # If the map .env file does not exist, create it with defaults
  if [ ! -f "$MAP_ENV_FILE" ]; then
    echo "Map .env file not found at $MAP_ENV_FILE, creating a new one with defaults."
    cat > "$MAP_ENV_FILE" <<EOL
NOCODB_API_URL=https://db.$new_domain/api/v1
NOCODB_API_TOKEN=changeme

# NocoDB View URL is the URL to your NocoDB view where the map data is stored.
NOCODB_VIEW_URL=

# NOCODB_LOGIN_SHEET is the URL to your NocoDB login sheet.
NOCODB_LOGIN_SHEET=

# NOCODB_SETTINGS_SHEET is the URL to your NocoDB settings sheet.
NOCODB_SETTINGS_SHEET=

# NOCODB_SHIFTS_SHEET is the urls to your shifts sheets.
NOCODB_SHIFTS_SHEET=

# NOCODB_SHIFT_SIGNUPS_SHEET is the URL to your NocoDB shift signups sheet where users can add their own shifts.
NOCODB_SHIFT_SIGNUPS_SHEET=

# Server Configuration
PORT=3000
NODE_ENV=production

# Session Secret (IMPORTANT: Generate a secure random string for production)
# You can generate one with: openssl rand -hex 32
SESSION_SECRET=$(openssl rand -hex 32 2>/dev/null || echo "changeme")

# Map Defaults (Edmonton, Alberta, Canada)
DEFAULT_LAT=53.5461
DEFAULT_LNG=-113.4938
DEFAULT_ZOOM=11

# Optional: Map Boundaries (prevents users from adding points outside area)
# BOUND_NORTH=53.7
# BOUND_SOUTH=53.4
# BOUND_EAST=-113.3
# BOUND_WEST=-113.7

# Cloudflare Settings
TRUST_PROXY=true
COOKIE_DOMAIN=.$new_domain

# Update NODE_ENV to production for HTTPS
NODE_ENV=production

# Add allowed origin
ALLOWED_ORIGINS=https://map.$new_domain,http://localhost:3000

# Add allowed origin
ALLOWED_ORIGINS=https://map.$new_domain,http://localhost:3000

# SMTP Configuration
SMTP_HOST=smtp.insert.here
SMTP_PORT=insert_port
SMTP_SECURE=false
SMTP_USER=changeme@$new_domain
SMTP_PASS=changeme
EMAIL_FROM_NAME="$new_domain Map"
EMAIL_FROM_ADDRESS=changeme@$new_domain

# App Configuration
APP_NAME="$new_domain Map"

# Listmonk Configuration
LISTMONK_API_URL=http://listmonk_app:9000/api
LISTMONK_PASSWORD=changeme
LISTMONK_SYNC_ENABLED=true
LISTMONK_INITIAL_SYNC=false  # Set to true to sync existing data

EOL
    echo "✅ Created new map .env file at $MAP_ENV_FILE"
    return 0
  fi

  echo "Updating map .env file with new domain settings..."

  # Create a backup of the map's .env file
  local timestamp=$(date +"%Y%m%d_%H%M%S")
  local backup_file="${MAP_ENV_FILE}.backup_${timestamp}"
  cp "$MAP_ENV_FILE" "$backup_file"
  echo "Created backup of map .env at $backup_file"

  # Update DOMAIN
  if grep -q "^DOMAIN=" "$MAP_ENV_FILE"; then
    sed -i "s|^DOMAIN=.*|DOMAIN=$new_domain|" "$MAP_ENV_FILE"
  else
    echo "DOMAIN=$new_domain" >> "$MAP_ENV_FILE"
  fi

  # Update NOCODB_API_URL to use new domain
  if grep -q "^NOCODB_API_URL=" "$MAP_ENV_FILE"; then
    sed -i "s|^NOCODB_API_URL=.*|NOCODB_API_URL=https://db.$new_domain/api/v1|" "$MAP_ENV_FILE"
  else
    echo "NOCODB_API_URL=https://db.$new_domain/api/v1" >> "$MAP_ENV_FILE"
  fi

  # Add NOCODB_CUTS_SHEET if missing
  if ! grep -q "^NOCODB_CUTS_SHEET=" "$MAP_ENV_FILE"; then
    echo "NOCODB_CUTS_SHEET=" >> "$MAP_ENV_FILE"
  fi

  # Update MKDOCS_URL to use new domain
  if grep -q "^MKDOCS_URL=" "$MAP_ENV_FILE"; then
    sed -i "s|^MKDOCS_URL=.*|MKDOCS_URL=https://$new_domain|" "$MAP_ENV_FILE"
  else
    echo "MKDOCS_URL=https://$new_domain" >> "$MAP_ENV_FILE"
  fi

  # Update MKDOCS_SEARCH_URL to use new domain
  if grep -q "^MKDOCS_SEARCH_URL=" "$MAP_ENV_FILE"; then
    sed -i "s|^MKDOCS_SEARCH_URL=.*|MKDOCS_SEARCH_URL=https://$new_domain|" "$MAP_ENV_FILE"
  else
    echo "MKDOCS_SEARCH_URL=https://$new_domain" >> "$MAP_ENV_FILE"
  fi

  # Update COOKIE_DOMAIN
  if grep -q "^COOKIE_DOMAIN=" "$MAP_ENV_FILE"; then
    sed -i "s|^COOKIE_DOMAIN=.*|COOKIE_DOMAIN=.$new_domain|" "$MAP_ENV_FILE"
  else
    echo "COOKIE_DOMAIN=.$new_domain" >> "$MAP_ENV_FILE"
  fi

  # Update ALLOWED_ORIGINS
  local allowed_origins="https://map.$new_domain,http://localhost:3000"
  if grep -q "^ALLOWED_ORIGINS=" "$MAP_ENV_FILE"; then
    sed -i "s|^ALLOWED_ORIGINS=.*|ALLOWED_ORIGINS=$allowed_origins|" "$MAP_ENV_FILE"
  else
    echo "ALLOWED_ORIGINS=$allowed_origins" >> "$MAP_ENV_FILE"
  fi

  # Update EMAIL_FROM_NAME
  if grep -q "^EMAIL_FROM_NAME=" "$MAP_ENV_FILE"; then
    sed -i "s|^EMAIL_FROM_NAME=.*|EMAIL_FROM_NAME=\"$new_domain Map\"|" "$MAP_ENV_FILE"
  else
    echo "EMAIL_FROM_NAME=\"$new_domain Map\"" >> "$MAP_ENV_FILE"
  fi

  # Update EMAIL_FROM_ADDRESS if it contains a domain reference
  if grep -q "^EMAIL_FROM_ADDRESS=" "$MAP_ENV_FILE"; then
    # Only update if it looks like it contains a domain placeholder
    if grep -q "changeme@\|insert_from_address" "$MAP_ENV_FILE"; then
      sed -i "s|^EMAIL_FROM_ADDRESS=.*|EMAIL_FROM_ADDRESS=changeme@$new_domain|" "$MAP_ENV_FILE"
    fi
  else
    echo "EMAIL_FROM_ADDRESS=changeme@$new_domain" >> "$MAP_ENV_FILE"
  fi

  # Update SMTP_USER if it contains a domain reference
  if grep -q "^SMTP_USER=" "$MAP_ENV_FILE"; then
    # Only update if it looks like it contains a domain placeholder
    if grep -q "changeme@\|@bnkops.ca" "$MAP_ENV_FILE"; then
      sed -i "s|^SMTP_USER=.*|SMTP_USER=changeme@$new_domain|" "$MAP_ENV_FILE"
    fi
  else
    echo "SMTP_USER=changeme@$new_domain" >> "$MAP_ENV_FILE"
  fi

  # Update APP_NAME
  if grep -q "^APP_NAME=" "$MAP_ENV_FILE"; then
    sed -i "s|^APP_NAME=.*|APP_NAME=\"$new_domain Map\"|" "$MAP_ENV_FILE"
  else
    echo "APP_NAME=\"$new_domain Map\"" >> "$MAP_ENV_FILE"
  fi

  # Update domain references in NocoDB URLs while preserving the sheet IDs and paths
  # This will update domains like cmlite.org, changeme.org, etc. to the new domain
  sed -i "s|://db\.cmlite\.org/|://db.$new_domain/|g" "$MAP_ENV_FILE"
  sed -i "s|://map\.cmlite\.org|://map.$new_domain|g" "$MAP_ENV_FILE"

  echo "✅ Updated map .env file with:"
  echo "   - NOCODB_API_URL=https://db.$new_domain/api/v1"
  echo "   - COOKIE_DOMAIN=.$new_domain"
  echo "   - ALLOWED_ORIGINS=$allowed_origins"
  echo "   - Updated all NocoDB URLs to use $new_domain domain"
  
  # Sync ports to map configuration
  sync_map_ports
  
  return 0
}

# Function to check for port conflicts in existing .env file
check_port_conflicts() {
  echo "Checking for port conflicts in existing configuration..."
  
  # Get list of all used ports on system
  local used_ports_list
  used_ports_list=$(get_used_ports)
  
  if [ $? -ne 0 ] || [ -z "$used_ports_list" ]; then
    echo "Warning: Could not scan system ports. Skipping conflict check."
    return 1
  fi
  
  # Check each configured port
  local -a conflicts=()
  local -a port_vars=(
    "CODE_SERVER_PORT"
    "LISTMONK_PORT"
    "LISTMONK_DB_PORT"
    "MKDOCS_PORT"
    "MKDOCS_SITE_SERVER_PORT"
    "N8N_PORT"
    "NOCODB_PORT"
    "HOMEPAGE_PORT"
    "GITEA_WEB_PORT"
    "GITEA_SSH_PORT"
    "MAP_PORT"
    "INFLUENCE_PORT"
    "MINI_QR_PORT"
    "REDIS_PORT"
    "PROMETHEUS_PORT"
    "GRAFANA_PORT"
    "CADVISOR_PORT"
    "NODE_EXPORTER_PORT"
    "REDIS_EXPORTER_PORT"
    "ALERTMANAGER_PORT"
    "GOTIFY_PORT"
    "MAILHOG_SMTP_PORT"
    "MAILHOG_WEB_PORT"
  )
  
  for var in "${port_vars[@]}"; do
    local port_value="${!var}"
    if [ -n "$port_value" ] && ! is_port_available "$port_value" "$used_ports_list"; then
      conflicts+=("$var=$port_value")
    fi
  done
  
  if [ ${#conflicts[@]} -gt 0 ]; then
    echo ""
    echo "⚠️  WARNING: Port conflicts detected!"
    echo "The following ports are already in use on your system:"
    for conflict in "${conflicts[@]}"; do
      echo "  - $conflict"
    done
    echo ""
    echo "You may need to:"
    echo "1. Stop services using these ports, or"
    echo "2. Edit .env file to use different ports"
    echo ""
  else
    echo "✅ No port conflicts detected!"
  fi
  
  return 0
}

# Function to get instance identifier
get_instance_identifier() {
  # Try to get from directory name first
  local dir_name=$(basename "$SCRIPT_DIR")
  local default_instance=""
  
  # Extract potential instance name from directory
  if [[ "$dir_name" =~ changemaker\.lite\.(.+)$ ]]; then
    default_instance="${BASH_REMATCH[1]}"
  elif [[ "$dir_name" != "changemaker.lite" ]]; then
    default_instance="$dir_name"
  fi
  
  # Send informational messages to stderr so they don't get captured
  echo "" >&2
  echo "=== Instance Configuration ===" >&2
  echo "To run multiple Changemaker instances on the same machine," >&2
  echo "each instance needs a unique identifier for containers and networks." >&2
  echo "" >&2
  
  if [ -n "$default_instance" ]; then
    echo "Detected potential instance name from directory: $default_instance" >&2
    read -p "Use this instance identifier? [Y/n]: " use_detected
    if [[ ! "$use_detected" =~ ^[Nn]$ ]]; then
      echo "$default_instance"
      return 0
    fi
  fi
  
  read -p "Enter instance identifier (letters, numbers, hyphens only) [default: main]: " instance_id
  
  # Validate and sanitize instance identifier
  if [ -z "$instance_id" ]; then
    instance_id="main"
  fi
  
  # Remove invalid characters and convert to lowercase
  instance_id=$(echo "$instance_id" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]//g')
  
  if [ -z "$instance_id" ]; then
    instance_id="main"
  fi
  
  # Only output the final instance_id to stdout (this gets captured)
  echo "$instance_id"
}

# Function to update docker-compose.yml with unique names
update_docker_compose_names() {
  local instance_id=$1
  
  if [ -z "$instance_id" ] || [ "$instance_id" = "main" ]; then
    echo "Using default container names (no instance suffix)"
    return 0
  fi
  
  # Check if docker-compose.yml exists and is not empty
  if [ ! -f "$DOCKER_COMPOSE_FILE" ] || [ ! -s "$DOCKER_COMPOSE_FILE" ]; then
    echo "Error: docker-compose.yml does not exist or is empty at: $DOCKER_COMPOSE_FILE"
    echo "Please ensure docker-compose.yml exists before running this script."
    return 1
  fi
  
  echo "Updating docker-compose.yml with instance identifier: $instance_id"
  
  # Create a backup of the docker-compose.yml file
  local timestamp=$(date +"%Y%m%d_%H%M%S")
  local backup_file="${DOCKER_COMPOSE_FILE}.backup_${timestamp}"
  cp "$DOCKER_COMPOSE_FILE" "$backup_file"
  echo "Created backup of docker-compose.yml at $backup_file"
  
  # Create temporary file for modifications
  local temp_file=$(mktemp)
  
  # Verify temp file was created
  if [ ! -f "$temp_file" ]; then
    echo "Error: Could not create temporary file"
    return 1
  fi
  
  # Update container names, network names, and volume names
  # Process the file and save to temp file
  sed \
      -e "s/container_name: \([^-]*\)-changemaker$/container_name: \1-changemaker-${instance_id}/g" \
      -e "s/container_name: \([^-]*\)_\([^-]*\)_changemaker$/container_name: \1_\2_changemaker_${instance_id}/g" \
      -e "s/container_name: \([^-]*\)_\([^-]*\)$/container_name: \1_\2_${instance_id}/g" \
      -e "s/container_name: \([^-]*\)$/container_name: \1-${instance_id}/g" \
      -e "s/changemaker-lite:/changemaker-lite-${instance_id}:/g" \
      -e "s/- changemaker-lite$/- changemaker-lite-${instance_id}/g" \
      -e "s/listmonk-data:/listmonk-data-${instance_id}:/g" \
      -e "s/source: listmonk-data$/source: listmonk-data-${instance_id}/g" \
      -e "s/n8n_data:/n8n_data_${instance_id}:/g" \
      -e "s/source: n8n_data$/source: n8n_data_${instance_id}/g" \
      -e "s/nc_data:/nc_data_${instance_id}:/g" \
      -e "s/source: nc_data$/source: nc_data_${instance_id}/g" \
      -e "s/db_data:/db_data_${instance_id}:/g" \
      -e "s/source: db_data$/source: db_data_${instance_id}/g" \
      -e "s/gitea_data:/gitea_data_${instance_id}:/g" \
      -e "s/source: gitea_data$/source: gitea_data_${instance_id}/g" \
      -e "s/mysql_data:/mysql_data_${instance_id}:/g" \
      -e "s/source: mysql_data$/source: mysql_data_${instance_id}/g" \
      -e "s/redis-data:/redis-data-${instance_id}:/g" \
      -e "s/source: redis-data$/source: redis-data-${instance_id}/g" \
      -e "s/prometheus-data:/prometheus-data-${instance_id}:/g" \
      -e "s/source: prometheus-data$/source: prometheus-data-${instance_id}/g" \
      -e "s/grafana-data:/grafana-data-${instance_id}:/g" \
      -e "s/source: grafana-data$/source: grafana-data-${instance_id}/g" \
      "$DOCKER_COMPOSE_FILE" > "$temp_file"
  
  # Check if temp file has content
  if [ ! -s "$temp_file" ]; then
    echo "Error: sed operation produced empty file"
    echo "Restoring from backup..."
    cp "$backup_file" "$DOCKER_COMPOSE_FILE"
    rm -f "$temp_file"
    return 1
  fi
  
  # Replace the original file only if temp file has content
  mv "$temp_file" "$DOCKER_COMPOSE_FILE"
  
  echo "✅ Updated docker-compose.yml with instance-specific names:"
  echo "   - Container names: *-${instance_id}"
  echo "   - Network name: changemaker-lite-${instance_id}"
  echo "   - Volume names: *-${instance_id}"
  
  return 0
}

# Function to update .env file with instance identifier
update_env_instance_config() {
  local instance_id=$1
  
  if [ -n "$instance_id" ] && [ "$instance_id" != "main" ]; then
    update_env_var "INSTANCE_ID" "$instance_id"
    update_env_var "COMPOSE_PROJECT_NAME" "changemaker-lite-${instance_id}"
    echo "Updated .env with instance configuration"
  fi
}

# Initialize a new .env file if it doesn't exist
if [ ! -f "$ENV_FILE" ]; then
  echo "No .env file found. Creating a new one from scratch."
  touch "$ENV_FILE"
  initialize_env_file
else
  echo "Found existing .env file. Will update values."
  backup_env_file
  
  # For existing .env files, also scan ports and suggest alternatives if conflicts exist
  echo ""
  echo "Checking existing port assignments for conflicts..."
  load_env_vars
  check_port_conflicts
fi

# Load existing environment variables
load_env_vars

echo -e "\n\nWelcome to Changemaker Config!\n"
echo "This script will help you configure your .env file for Changemaker."
echo "Please provide the following information:"

# Get instance identifier and update docker-compose.yml
echo -e "\n---- Instance Configuration ----"
instance_identifier=$(get_instance_identifier)
# Strip any whitespace/newlines from the captured value
instance_identifier=$(echo "$instance_identifier" | tr -d '\n\r' | xargs)

# Only update docker-compose.yml if we have a non-default instance ID
if [ -n "$instance_identifier" ] && [ "$instance_identifier" != "main" ]; then
  if update_docker_compose_names "$instance_identifier"; then
    echo "✅ Docker Compose configuration updated successfully"
  else
    echo "⚠️  Warning: Failed to update docker-compose.yml"
    echo "   Continuing with default configuration..."
  fi
else
  echo "Using default instance configuration (no modifications to docker-compose.yml)"
fi

update_env_instance_config "$instance_identifier"

# Domain configuration
echo -e "\n---- Domain Configuration ----"
read -p "Enter your domain name (without protocol, e.g., example.com): " domain_name

if [ -z "$domain_name" ]; then
  echo "Domain name cannot be empty. Using default: changeme.org"
  domain_name="changeme.org"
fi

# Local IP configuration for Homepage Local tab
echo -e "\n---- Local Network Configuration ----"
echo "For the Homepage dashboard, you can configure the Local tab to use a specific"
echo "IP address for accessing services on your local network (e.g., Tailscale IP)."
echo ""
read -p "Enter local IP address [default: localhost]: " local_ip

if [ -z "$local_ip" ]; then
  local_ip="localhost"
  echo "Using default: localhost"
else
  echo "Using local IP: $local_ip"
fi

echo -e "\nUpdating domain settings in .env file..."

# Update main domain settings
update_env_var "DOMAIN" "$domain_name"
update_env_var "BASE_DOMAIN" "https://$domain_name"
update_env_var "HOMEPAGE_VAR_BASE_URL" "https://$domain_name"
update_env_var "LISTMONK_HOSTNAME" "listmonk.$domain_name"
update_env_var "N8N_HOST" "n8n.$domain_name"
update_env_var "CF_DOMAIN" "$domain_name"
update_env_var "GITEA_DOMAIN" "git.$domain_name"
update_env_var "GITEA_ROOT_URL" "https://git.$domain_name"

# Update cookie and CORS settings
update_env_var "COOKIE_DOMAIN" ".$domain_name"
update_env_var "ALLOWED_ORIGINS" "https://map.$domain_name,http://localhost:3000"

# Update alert email to use new domain
update_env_var "ALERT_EMAIL_TO" "admin@$domain_name"

echo "Domain settings updated successfully!"

# Update the map's .env file
echo -e "\nUpdating map configuration..."
update_map_env "$domain_name"

# Cloudflare Configuration
echo -e "\n---- Cloudflare Configuration ----"
get_cloudflare_credentials

read -p "Do you want to configure Cloudflare settings now? [Y/n]: " configure_cf

if [[ ! "$configure_cf" =~ ^[Nn]$ ]]; then
  # Get Cloudflare API token
  read -p "Enter your Cloudflare API Token: " cf_api_token
  if [ -z "$cf_api_token" ] || [ "$cf_api_token" = "your_cloudflare_api_token" ]; then
    echo "Warning: API token is required for Cloudflare integration"
    cf_api_token="your_cloudflare_api_token"
  fi
  update_env_var "CF_API_TOKEN" "$cf_api_token"

  # Get Cloudflare Zone ID
  read -p "Enter your Cloudflare Zone ID: " cf_zone_id
  if [ -z "$cf_zone_id" ] || [ "$cf_zone_id" = "your_cloudflare_zone_id" ]; then
    echo "Warning: Zone ID is required for DNS configuration"
    cf_zone_id="your_cloudflare_zone_id"
  fi
  update_env_var "CF_ZONE_ID" "$cf_zone_id"

  # Get Cloudflare Account ID
  read -p "Enter your Cloudflare Account ID: " cf_account_id
  if [ -z "$cf_account_id" ] || [ "$cf_account_id" = "your_cloudflare_account_id" ]; then
    echo "Warning: Account ID is required for tunnel operations"
    cf_account_id="your_cloudflare_account_id"
  fi
  update_env_var "CF_ACCOUNT_ID" "$cf_account_id"
  
  # Note: CF_TUNNEL_ID will be set by start-production.sh when the tunnel is created
  update_env_var "CF_TUNNEL_ID" "will_be_set_by_start_production"
  
  echo ""
  echo "Cloudflare configuration saved to .env file."
  echo ""
  echo "To complete the setup and deploy your services:"
  echo "1. Start your services with: docker compose up -d"
  echo "2. Run ./start-production.sh to configure the Cloudflare tunnel"
  echo ""
else
  echo "Skipping Cloudflare configuration."
  echo "You'll need to configure Cloudflare settings manually before running start-production.sh."
fi

# Update the site_url in mkdocs.yml
echo -e "\nUpdating site_url in mkdocs.yml..."
update_mkdocs_yml "$domain_name"

# Update service URLs in services.yaml
echo -e "\nUpdating service URLs in services.yaml..."
update_services_yaml "$domain_name" "$local_ip"

# Update the login URL in main.html
echo -e "\nUpdating login URL in main.html..."
update_main_html "$domain_name"

# Listmonk Admin Credentials configuration
echo -e "\n---- Listmonk Admin Credentials ----"
read -p "Enter Listmonk admin email/username [default: admin@example.com]: " listmonk_user
read -sp "Enter Listmonk admin password [default: changeMe]: " listmonk_password
echo # Add new line after password input

if [ -z "$listmonk_user" ]; then
  listmonk_user="admin@example.com"
fi

if [ -z "$listmonk_password" ]; then
  listmonk_password="changeMe"
fi

update_env_var "LISTMONK_ADMIN_USER" "$listmonk_user"
update_env_var "LISTMONK_ADMIN_PASSWORD" "$listmonk_password"

echo "Listmonk admin credentials updated."

# N8N User Credentials configuration
echo -e "\n---- N8N Admin Credentials ----"
read -p "Enter N8N admin email [default: admin@example.com]: " n8n_email
read -sp "Enter N8N admin password [default: changeMe]: " n8n_password
echo # Add new line after password input

if [ -z "$n8n_email" ]; then
  n8n_email="admin@example.com"
fi

if [ -z "$n8n_password" ]; then
  n8n_password="changeMe"
fi

update_env_var "N8N_USER_EMAIL" "$n8n_email"
update_env_var "N8N_USER_PASSWORD" "$n8n_password"

echo "N8N admin credentials updated."

# Generate secure passwords for database and encryption
echo -e "\n---- Generating Secure Passwords ----"
echo "Generating secure passwords for database and encryption keys..."

# Generate and update database password
postgres_password=$(generate_password 20)
update_env_var "POSTGRES_PASSWORD" "$postgres_password"

# Generate and update N8N encryption key
n8n_encryption_key=$(generate_password 32)
update_env_var "N8N_ENCRYPTION_KEY" "$n8n_encryption_key"

# Generate and update NocoDB passwords
nocodb_jwt_secret=$(generate_password 32)
update_env_var "NOCODB_JWT_SECRET" "$nocodb_jwt_secret"

nocodb_db_password=$(generate_password 20)
update_env_var "NOCODB_DB_PASSWORD" "$nocodb_db_password"

# Generate and update Gitea passwords (these should already exist in the file)
gitea_db_password=$(generate_password 20)
update_env_var "GITEA_DB_PASSWD" "$gitea_db_password"

gitea_db_root_password=$(generate_password 20)
update_env_var "GITEA_DB_ROOT_PASSWORD" "$gitea_db_root_password"

# Generate and update Grafana admin password
grafana_admin_password=$(generate_password 20)
update_env_var "GRAFANA_ADMIN_PASSWORD" "$grafana_admin_password"

# Generate and update Gotify admin password
gotify_admin_password=$(generate_password 20)
update_env_var "GOTIFY_ADMIN_PASSWORD" "$gotify_admin_password"

echo "Secure passwords generated and updated."

# Fix container directory permissions before finishing
fix_container_permissions

echo -e "\n✅ Configuration completed successfully!"
echo "Your .env file has been configured with:"
echo "- Instance ID: $instance_identifier"
echo "- Domain: $domain_name"
echo "- Local IP: $local_ip (for Homepage Local tab)"
echo "- Cookie Domain: .$domain_name"
echo "- Allowed Origins: https://map.$domain_name,http://localhost:3000"
echo "- Map .env updated with domain settings"
echo "- Listmonk Admin: $listmonk_user"
echo "- N8N Admin Email: $n8n_email"
echo "- Secure random passwords for database, encryption, and NocoDB"
echo "- Grafana Admin Password: Generated (see .env file)"
echo "- Gotify Admin Password: Generated (see .env file)"
echo "- Centralized services: Redis, Prometheus, Grafana"
echo "- Monitoring services: cAdvisor, Node Exporter, Redis Exporter, Alertmanager, Gotify"
echo "- Email testing: MailHog"
echo "- Tunnel configuration updated at: $TUNNEL_CONFIG_FILE"
echo "- Homepage services.yaml configured with Production and Local tabs"
echo -e "\nYour .env file is located at: $ENV_FILE"
echo "A backup of your original .env file was created before modifications."

echo ""
echo "======================================"
echo "Next Steps:"
echo "======================================"
echo ""
if [ -n "$instance_identifier" ] && [ "$instance_identifier" != "main" ]; then
  echo "Instance: $instance_identifier"
  echo ""
fi
echo "1. Start services locally:"
echo "   docker compose up -d"
echo ""
echo "2. Test all services at:"
echo "   - Homepage: http://localhost:${HOMEPAGE_PORT:-3010}"
echo "   - Code Server: http://localhost:${CODE_SERVER_PORT:-8888}"
echo "   - Listmonk: http://localhost:${LISTMONK_PORT:-9000}"
echo "   - Documentation: http://localhost:${MKDOCS_PORT:-4000}"
echo "   - n8n: http://localhost:${N8N_PORT:-5678}"
echo "   - NocoDB: http://localhost:${NOCODB_PORT:-8090}"
echo "   - Gitea: http://localhost:${GITEA_WEB_PORT:-3030}"
echo "   - Map: http://localhost:${MAP_PORT:-3000}"
echo "   - Influence: http://localhost:${INFLUENCE_PORT:-3333}"
echo "   - Mini QR: http://localhost:${MINI_QR_PORT:-8089}"
echo ""
echo "   Centralized Services:"
echo "   - Redis: http://localhost:${REDIS_PORT:-6379}"
echo ""
echo "   Email Testing:"
echo "   - MailHog Web UI: http://localhost:${MAILHOG_WEB_PORT:-8025}"
echo "   - MailHog SMTP: localhost:${MAILHOG_SMTP_PORT:-1025}"
echo ""
echo "   Monitoring Services (optional monitoring profile):"
echo "   - Prometheus: http://localhost:${PROMETHEUS_PORT:-9090}"
echo "   - Grafana: http://localhost:${GRAFANA_PORT:-3001}"
echo "   - Alertmanager: http://localhost:${ALERTMANAGER_PORT:-9093}"
echo "   - Gotify: http://localhost:${GOTIFY_PORT:-8889}"
echo "   - cAdvisor: http://localhost:${CADVISOR_PORT:-8080}"
echo "   - Node Exporter: http://localhost:${NODE_EXPORTER_PORT:-9100}/metrics"
echo "   - Redis Exporter: http://localhost:${REDIS_EXPORTER_PORT:-9121}/metrics"
echo ""
echo "   To start with monitoring:"
echo "   docker compose --profile monitoring up -d"
echo ""
echo "   Monitoring Credentials:"
echo "   - Grafana: admin / (check .env: GRAFANA_ADMIN_PASSWORD)"
echo "   - Gotify: admin / (check .env: GOTIFY_ADMIN_PASSWORD)"
echo ""
echo "3. When ready for production:"
echo "   ./start-production.sh"
echo ""
echo "======================================"