#!/usr/bin/env bash
#
# Usage:
#   taler-merchant-rproxy-setup --domain some.domain.name [--nginx | --apache] [--httponly | --httpsonly]
#
# If neither --nginx nor --apache is specified, the script:
#   1) Detects if exactly one of them is installed -> uses it
#   2) Otherwise, errors out
#
# Description:
#   - Requires --domain <name>
#   - At most one of {--nginx, --apache} (or auto-detection)
#   - Optionally {--httponly} or {--httpsonly} (but not both)
#   - Checks for required packages (nginx/apache2, certbot (unless HTTP-only))
#   - Verifies Apache modules if using --apache (proxy, proxy_http, headers, ssl)
#   - Attempts to start the selected web server
#   - Runs certbot to get certificates (unless HTTP-only)
#   - Updates config(s), backs up originals, optionally forces HTTP->HTTPS
#   - Activates the new configuration
#
# Paths used:
#   - Nginx:  /etc/nginx/sites-available/taler-merchant
#   - Apache: /etc/apache2/sites-available/taler-merchant.conf
#

###########################
# 0. Parse input arguments
###########################

DOMAIN=""
USE_NGINX=0
USE_APACHE=0
HTTP_ONLY=0
HTTPS_ONLY=0

usage() {
  echo "Usage:"
  echo "  taler-merchant-rproxy-setup --domain <example.com> [--nginx | --apache] [--httponly | --httpsonly]"
  echo
  echo "Description:"
  echo "  Configures reverse proxy settings for Taler merchant under either Nginx or Apache."
  echo "  If no server type is specified, the script auto-detects if exactly one of them is installed."
  echo
  echo "Options:"
  echo "  --domain <example.com>    (Required) Domain name to configure"
  echo "  --nginx                   Force use of Nginx"
  echo "  --apache                  Force use of Apache"
  echo "  --httponly                Only configure HTTP (no TLS). Skips certbot."
  echo "  --httpsonly               Configure HTTPS with automatic redirect from HTTP."
  echo "  -h, --help                Show this help message and exit."
  exit 0
}

##########################
# 0.a. Must run as root
##########################
if [[ $EUID -ne 0 ]]; then
  echo "ERROR: This script must be run as root (e.g. with sudo)."
  exit 1
fi

while [[ $# -gt 0 ]]; do
  case "$1" in
    --domain)
      DOMAIN="$2"
      shift 2
      ;;
    --nginx)
      USE_NGINX=1
      shift
      ;;
    --apache)
      USE_APACHE=1
      shift
      ;;
    --httponly)
      HTTP_ONLY=1
      shift
      ;;
    --httpsonly)
      HTTPS_ONLY=1
      shift
      ;;
    -h|--help)
      usage
      ;;
    *)
      echo "Unknown argument: $1"
      echo "Use --help for usage information."
      exit 1
      ;;
  esac
done

# Check domain
if [[ -z "$DOMAIN" ]]; then
  echo "ERROR: --domain <name> is required."
  echo "Use --help for usage information."
  exit 1
fi

##############################
# 0.b. Optional DNS check
##############################
# Checks that the domain resolves to at least one local IP.
# If it doesn't, you can either warn or exit. Below, we exit.
# If your environment uses NAT or multiple interfaces, you may
# wish to relax this check into a warning.

if command -v dig &>/dev/null; then
  # Gather the local machine's IP addresses
  local_ips="$(hostname -I 2>/dev/null || true)"
  # Attempt to resolve $DOMAIN via DNS
  domain_ips="$(dig +short A "$DOMAIN")"

  if [[ -z "$domain_ips" ]]; then
    echo "ERROR: DNS lookup for '$DOMAIN' returned no A record."
    echo "Please ensure the domain name is configured correctly in DNS."
    exit 1
  fi

  echo "Local IP(s):   $local_ips"
  echo "Domain IP(s):  $domain_ips"

  match_found=0
  while read -r dip; do
    if echo "$local_ips" | grep -qw "$dip"; then
      match_found=1
      break
    fi
  done <<< "$domain_ips"

  if [[ $match_found -eq 0 ]]; then
    echo "ERROR: None of the DNS IPs for '$DOMAIN' match this server's IP(s)."
    echo "Fix DNS or check networking before continuing."
    exit 1
  fi
else
  echo "WARNING: 'dig' not installed; skipping DNS check."
fi

##############################
# Detect installed web server
##############################
check_installed() {
  dpkg -s "$1" &>/dev/null
}

# If user did NOT specify --nginx or --apache, see if exactly one is installed.
if [[ $USE_NGINX -eq 0 && $USE_APACHE -eq 0 ]]; then
  NGINX_INSTALLED=0
  APACHE_INSTALLED=0
  if check_installed nginx; then
    NGINX_INSTALLED=1
  fi
  if check_installed apache2; then
    APACHE_INSTALLED=1
  fi

  if [[ $NGINX_INSTALLED -eq 1 && $APACHE_INSTALLED -eq 0 ]]; then
    USE_NGINX=1
    echo "Detected only nginx installed; proceeding with nginx."
  elif [[ $NGINX_INSTALLED -eq 0 && $APACHE_INSTALLED -eq 1 ]]; then
    USE_APACHE=1
    echo "Detected only apache2 installed; proceeding with apache."
  else
    echo "ERROR: Both or neither of nginx/apache2 are installed."
    echo "       Please install one or specify --nginx / --apache explicitly."
    exit 1
  fi
fi

# At this point, we have either USE_NGINX=1 or USE_APACHE=1.

# Check that at most one of {--httponly, --httpsonly}
if [[ $HTTP_ONLY -eq 1 && $HTTPS_ONLY -eq 1 ]]; then
  echo "ERROR: Cannot specify both --httponly and --httpsonly."
  exit 1
fi

# We need certbot only if HTTPS is involved
if [[ $HTTP_ONLY -eq 0 ]]; then
  if ! check_installed certbot; then
    echo "ERROR: certbot is not installed."
    echo "Install it via: sudo apt-get install certbot"
    exit 1
  fi
fi

###################################
# 1. Check presence of chosen server
###################################
if [[ $USE_NGINX -eq 1 ]]; then
  if ! check_installed nginx; then
    echo "ERROR: nginx is not installed or not detected."
    echo "Install it via: sudo apt-get install nginx"
    exit 1
  fi
else
  if ! check_installed apache2; then
    echo "ERROR: apache2 is not installed or not detected."
    echo "Install it via: sudo apt-get install apache2"
    exit 1
  fi

  # Check Apache modules. If missing, enable them. Then restart Apache.
  APACHE_MODULES="$(apache2ctl -M 2>/dev/null)"
  for mod in proxy proxy_http headers ssl; do
    if ! echo "$APACHE_MODULES" | grep -qE "^ $mod(_module)?"; then
      echo "Apache module '$mod' not enabled. Enabling it now..."
      a2enmod "$mod"
      NEED_RESTART=1
    fi
  done

  if [[ -n "$NEED_RESTART" ]]; then
    echo "Restarting apache2 to load newly enabled module(s)..."
    systemctl restart apache2
  fi
fi

###########################################
# 2. Start/ensure the requested service is up
###########################################
start_service() {
  local service_name="$1"
  if ! systemctl is-active --quiet "$service_name"; then
    echo "Attempting to start $service_name ..."
    if ! systemctl start "$service_name"; then
      echo "ERROR: Could not start $service_name. Fix manually or switch server type."
      exit 1
    fi
  fi
}

if [[ $USE_NGINX -eq 1 ]]; then
  start_service "nginx"
else
  start_service "apache2"
fi

#######################################################
# 2.5 Adjust config for HTTP-only (if requested FIRST)
#######################################################
CONFIG_FILE_NGINX="/etc/nginx/sites-available/taler-merchant"
CONFIG_FILE_APACHE="/etc/apache2/sites-available/taler-merchant.conf"

backup_and_edit_nginx_http_only() {
  if [[ ! -f "${CONFIG_FILE_NGINX}.legacy" && -f "$CONFIG_FILE_NGINX" ]]; then
    sudo cp "$CONFIG_FILE_NGINX" "${CONFIG_FILE_NGINX}.legacy"
  fi
  if [[ -f "${CONFIG_FILE_NGINX}.legacy" ]]; then
    sudo cp "${CONFIG_FILE_NGINX}.legacy" "$CONFIG_FILE_NGINX"
  fi
  sudo sed -i "s/%%your\.domain%%/$DOMAIN/g" "$CONFIG_FILE_NGINX" 2>/dev/null
  # Remove any 'server { ... listen 443 ... }' block
  sudo sed -i '/listen 443/,/}/d' "$CONFIG_FILE_NGINX" 2>/dev/null
}

backup_and_edit_apache_http_only() {
  if [[ ! -f "${CONFIG_FILE_APACHE}.legacy" && -f "$CONFIG_FILE_APACHE" ]]; then
    sudo cp "$CONFIG_FILE_APACHE" "${CONFIG_FILE_APACHE}.legacy"
  fi
  if [[ -f "${CONFIG_FILE_APACHE}.legacy" ]]; then
    sudo cp "${CONFIG_FILE_APACHE}.legacy" "$CONFIG_FILE_APACHE"
  fi
  sudo sed -i "s/%%your\.domain%%/$DOMAIN/g" "$CONFIG_FILE_APACHE" 2>/dev/null
  # Remove everything from "<VirtualHost *:443>" to "</VirtualHost>"
  sudo sed -i '/<VirtualHost \*:443>/,/<\/VirtualHost>/d' "$CONFIG_FILE_APACHE" 2>/dev/null
}

if [[ $HTTP_ONLY -eq 1 ]]; then
  if [[ $USE_NGINX -eq 1 ]]; then
    backup_and_edit_nginx_http_only
    if ! systemctl reload nginx; then
      echo "ERROR: Failed to reload nginx after HTTP-only config changes."
      exit 1
    fi
  else
    backup_and_edit_apache_http_only
    if ! systemctl reload apache2; then
      echo "ERROR: Failed to reload apache2 after HTTP-only config changes."
      exit 1
    fi
  fi
fi

#############################################
# 3. Acquire certificate via certbot
#############################################
if [[ $HTTP_ONLY -eq 0 ]]; then
  echo "Running certbot to obtain certificate for $DOMAIN ..."
  echo "Please follow the certbot prompts."
  if ! certbot certonly --webroot -w /var/www/html -d "$DOMAIN"; then
    echo "ERROR: certbot failed. Exiting."
    exit 1
  fi
fi

##############################################################
# 4. Update config to use SSL (unless strictly HTTP only)
##############################################################
backup_and_edit_nginx_https() {
  if [[ ! -f "${CONFIG_FILE_NGINX}.legacy" && -f "$CONFIG_FILE_NGINX" ]]; then
    sudo cp "$CONFIG_FILE_NGINX" "${CONFIG_FILE_NGINX}.legacy"
  fi
  if [[ -f "${CONFIG_FILE_NGINX}.legacy" ]]; then
    sudo cp "${CONFIG_FILE_NGINX}.legacy" "$CONFIG_FILE_NGINX"
  fi
  sudo sed -i "s/%%your\.domain%%/$DOMAIN/g" "$CONFIG_FILE_NGINX" 2>/dev/null

  if [[ $HTTPS_ONLY -eq 1 ]]; then
    # Insert a simple HTTP->HTTPS redirect into the server block with "listen 80;"
    sudo sed -i '/listen 80;/a \
    if ($scheme = http) { return 301 https://$host$request_uri; }' "$CONFIG_FILE_NGINX" 2>/dev/null
  fi
}

backup_and_edit_apache_https() {
  if [[ ! -f "${CONFIG_FILE_APACHE}.legacy" && -f "$CONFIG_FILE_APACHE" ]]; then
    sudo cp "$CONFIG_FILE_APACHE" "${CONFIG_FILE_APACHE}.legacy"
  fi
  if [[ -f "${CONFIG_FILE_APACHE}.legacy" ]]; then
    sudo cp "${CONFIG_FILE_APACHE}.legacy" "$CONFIG_FILE_APACHE"
  fi
  sudo sed -i "s/%%your\.domain%%/$DOMAIN/g" "$CONFIG_FILE_APACHE" 2>/dev/null

  if [[ $HTTPS_ONLY -eq 1 ]]; then
    # Insert naive rewrite for forcing HTTPS
    sudo sed -i '/<VirtualHost \*:80>/a \
    RewriteEngine On\nRewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R=301,L]' "$CONFIG_FILE_APACHE" 2>/dev/null
  fi
}

if [[ $HTTP_ONLY -eq 0 ]]; then
  if [[ $USE_NGINX -eq 1 ]]; then
    backup_and_edit_nginx_https
    if ! systemctl reload nginx; then
      echo "ERROR: Failed to reload nginx after enabling HTTPS."
      exit 1
    fi
  else
    backup_and_edit_apache_https
    if ! systemctl reload apache2; then
      echo "ERROR: Failed to reload apache2 after enabling HTTPS."
      exit 1
    fi
  fi
else
  echo "HTTP-only mode requested; skipping HTTPS config edits."
fi

##################################################
# 5. Activate the configuration and final reload
##################################################
if [[ $USE_NGINX -eq 1 ]]; then
  # Symlink into sites-enabled if not already done
  if [[ -f "/etc/nginx/sites-available/taler-merchant" && ! -e "/etc/nginx/sites-enabled/taler-merchant" ]]; then
    echo "Linking /etc/nginx/sites-available/taler-merchant to /etc/nginx/sites-enabled/"
    ln -s /etc/nginx/sites-available/taler-merchant /etc/nginx/sites-enabled/
  fi

  echo "Testing nginx configuration..."
  if ! nginx -t; then
    echo "ERROR: 'nginx -t' reported a problem. Please fix the config before proceeding."
    exit 1
  fi

  echo "Reloading nginx with new configuration..."
  if ! systemctl reload nginx; then
    echo "ERROR: Failed to reload nginx after final activation."
    exit 1
  fi
else
  echo "Enabling the taler-merchant site in Apache..."
  if ! a2ensite taler-merchant; then
    echo "ERROR: Failed to run 'a2ensite taler-merchant'."
    exit 1
  fi

  echo "Reloading Apache with new configuration..."
  if ! systemctl reload apache2; then
    echo "ERROR: Failed to reload apache2 after final activation."
    exit 1
  fi
fi

echo "Done. Configuration updated and activated for $DOMAIN."