#!/usr/bin/env bash
set -euo pipefail

# ---------------- Colors ----------------
RED="\033[1;31m"
GRN="\033[1;32m"
YLW="\033[1;33m"
CYN="\033[1;36m"
DIM="\033[0;90m"
RST="\033[0m"

log(){ echo -e "${CYN}➜${RST} $*"; }
ok(){  echo -e "${GRN}✔${RST} $*"; }
warn(){ echo -e "${YLW}⚠${RST} $*"; }
dbg(){ echo -e "${DIM}• $*${RST}"; }
die(){ echo -e "${RED}✖ $*${RST}" >&2; exit 1; }

DOMAIN=""
PORT=""

while [[ $# -gt 0 ]]; do
  case "$1" in
    --domain) [[ $# -ge 2 ]] || die "Missing value for --domain"; DOMAIN="$2"; shift 2 ;;
    --port)   [[ $# -ge 2 ]] || die "Missing value for --port"; PORT="$2"; shift 2 ;;
    *) die "Unknown option: $1. Usage: $0 --domain <domain> --port <port>" ;;
  esac
done

[[ -n "$DOMAIN" && -n "$PORT" ]] || die "Usage: $0 --domain <domain> --port <port>"

NGINX_CONF="/etc/nginx/sites-available/$DOMAIN"
NGINX_LINK="/etc/nginx/sites-enabled/$DOMAIN"
WEBROOT="/var/www/certbot"
LE_DIR="/etc/letsencrypt"
LE_OPTIONS="$LE_DIR/options-ssl-nginx.conf"
LE_DHPARAMS="$LE_DIR/ssl-dhparams.pem"
EMAIL="admin@$DOMAIN"

ensure_pkg(){
  pkg="$1"
  if ! command -v "$pkg" >/dev/null 2>&1; then
    warn "$pkg missing — installing"
    export DEBIAN_FRONTEND=noninteractive
    apt-get update -y >/dev/null
    apt-get install -y "$pkg" >/dev/null || die "Failed to install $pkg"
    ok "$pkg installed"
  else
    dbg "$pkg already installed"
  fi
}

ensure_le_files(){
  mkdir -p "$LE_DIR"

  if [[ ! -f "$LE_OPTIONS" ]]; then
    warn "Creating missing certbot ssl options"
    cat > "$LE_OPTIONS" <<'EOF'
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
EOF
    chmod 644 "$LE_OPTIONS"
  fi

  if [[ ! -f "$LE_DHPARAMS" ]]; then
    warn "Generating DH params (one-time cost)"
    openssl dhparam -out "$LE_DHPARAMS" 2048 >/dev/null 2>&1
    chmod 644 "$LE_DHPARAMS"
    ok "DH params created"
  fi
}

cleanup_site(){
  warn "Removing broken nginx config"
  rm -f "$NGINX_CONF" "$NGINX_LINK"
}

write_http_acme_config(){
  log "Writing temporary HTTP ACME config"
  mkdir -p "$WEBROOT"
  cat > "$NGINX_CONF" <<EOL
server {
  listen 80;
  server_name $DOMAIN;

  location /.well-known/acme-challenge/ {
    root $WEBROOT;
  }

  location / {
    proxy_pass http://127.0.0.1:$PORT;
    proxy_set_header Host \$host;
    proxy_set_header X-Real-IP \$remote_addr;
    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto \$scheme;
  }
}
EOL
  ln -sf "$NGINX_CONF" "$NGINX_LINK"
}

write_final_https_config(){
  log "Writing final HTTPS config"
  cat > "$NGINX_CONF" <<EOL
server {
  listen 80;
  server_name $DOMAIN;
  return 301 https://\$host\$request_uri;
}

server {
  listen 443 ssl;
  server_name $DOMAIN;

  ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
  include /etc/letsencrypt/options-ssl-nginx.conf;
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

  location / {
    proxy_pass http://127.0.0.1:$PORT;
    proxy_set_header Host \$host;
    proxy_set_header X-Real-IP \$remote_addr;
    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto \$scheme;

    proxy_buffers 8 32k;
    proxy_buffer_size 64k;
    client_max_body_size 500M;
  }
}
EOL
  ln -sf "$NGINX_CONF" "$NGINX_LINK"
}

nginx_start_or_reload(){
  if systemctl is-active --quiet nginx; then
    dbg "Testing nginx configuration"
    nginx -t >/dev/null || { journalctl -u nginx -n 80 --no-pager; die "nginx config invalid"; }
    systemctl reload nginx
    ok "nginx reloaded"
  else
    warn "nginx inactive — starting"
    systemctl start nginx || { journalctl -u nginx -n 80 --no-pager; die "failed to start nginx"; }
    ok "nginx started"
  fi
}

cert_exists(){
  [[ -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" && -f "/etc/letsencrypt/live/$DOMAIN/privkey.pem" ]]
}

# ---------------- Execution ----------------

log "Checking dependencies"l
ensure_pkg nginx
ensure_pkg certbot
apt-get install -y python3-certbot-nginx >/dev/null 2>&1 || true

ensure_le_files
cleanup_site
write_http_acme_config
nginx_start_or_reload

log "Obtaining certificate for $DOMAIN"

if cert_exists; then
  ok "Existing certificate detected — skipping issuance"
else
  if certbot certonly --webroot -w "$WEBROOT" -d "$DOMAIN" --agree-tos --non-interactive -m "$EMAIL"; then
    ok "Certificate issued via webroot"
  else
    warn "Webroot failed — trying nginx installer fallback"
    certbot --nginx -d "$DOMAIN" --agree-tos --non-interactive -m "$EMAIL" \
      || die "Certbot failed"
    ok "Certificate issued via nginx plugin"
  fi
fi

write_final_https_config

log "Validating nginx"
nginx -t >/dev/null || { journalctl -u nginx -n 80 --no-pager; die "nginx test failed"; }

systemctl restart nginx
ok "HTTPS enabled for $DOMAIN"