#!/usr/bin/env bash
#
# Attach one customer domain to this server and issue a TLS certificate.
# Idempotent: re-running for an existing domain renews/repairs rather than duplicates.
# Run as root, AFTER the domain's A/AAAA record already resolves to this server.
#
#   bash add-domain.sh shop.example.com --email ops@example.com
#   bash add-domain.sh shop.example.com --email ops@example.com --with-www
#
# Why per-domain blocks exist at all: the application is multi-tenant off the
# Host header and needs no per-domain root. Certificates are the exception —
# certbot must match a concrete server_name, which `default_server _` is not.

set -euo pipefail

DOMAIN="${1:-}"; shift || true
EMAIL=""
WITH_WWW=0

while [[ $# -gt 0 ]]; do
  case "$1" in
    --email)    EMAIL="$2"; shift 2 ;;
    --with-www) WITH_WWW=1; shift ;;
    *) echo "unknown argument: $1" >&2; exit 2 ;;
  esac
done

[[ $EUID -eq 0 ]] || { echo "must run as root" >&2; exit 1; }
[[ -n "$DOMAIN" ]] || { echo "usage: add-domain.sh <domain> --email <address> [--with-www]" >&2; exit 2; }
[[ -n "$EMAIL"  ]] || { echo "--email is required (certbot expiry notices)" >&2; exit 2; }

# Fail loudly rather than let certbot fail obscurely on an unpointed domain.
echo "==> checking DNS for $DOMAIN"
RESOLVED="$(getent hosts "$DOMAIN" | awk '{print $1}' | head -1 || true)"
if [[ -z "$RESOLVED" ]]; then
  echo "ERROR: $DOMAIN does not resolve. Point its A record at this server first." >&2
  exit 1
fi
echo "    resolves to $RESOLVED"

NAMES="$DOMAIN"
CERT_ARGS=(-d "$DOMAIN")
if [[ $WITH_WWW -eq 1 ]]; then
  NAMES="$DOMAIN www.$DOMAIN"
  CERT_ARGS+=(-d "www.$DOMAIN")
fi

CONF="/etc/nginx/sites-available/tenant-$DOMAIN.conf"
echo "==> nginx server block: $CONF"
cat > "$CONF" <<NGINX
# Tenant domain: $DOMAIN
# Same root as the catch-all — the SPA resolves the tenant from the Host header.
# This block exists so certbot has a concrete server_name to attach TLS to.

server {
    listen 80;
    listen [::]:80;
    server_name $NAMES;

    root /srv/marketplaces/current/frontend;
    index index.html;

    location = /index.html {
        add_header Cache-Control "no-store, must-revalidate" always;
        try_files \$uri =404;
    }

    location ~* \.(js|css|woff2?|png|jpe?g|svg|gif|webp|avif|ico)\$ {
        expires 1y;
        add_header Cache-Control "public, immutable" always;
        try_files \$uri =404;
    }

    location /health {
        access_log off;
        return 200 "ok\n";
        add_header Content-Type text/plain;
    }

    location /api/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        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_read_timeout 60s;
    }

    location / {
        try_files \$uri \$uri/ /index.html;
    }

    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    gzip on;
    gzip_types text/plain text/css application/javascript application/json image/svg+xml;
    gzip_min_length 1024;
}
NGINX

ln -sfn "$CONF" "/etc/nginx/sites-enabled/tenant-$DOMAIN.conf"
nginx -t
systemctl reload nginx

echo "==> certificate"
# --nginx rewrites the block above in place to add listen 443 + ssl directives
# and an HTTP->HTTPS redirect. Re-running is a no-op when the cert is current.
certbot --nginx "${CERT_ARGS[@]}" \
  --non-interactive --agree-tos --email "$EMAIL" \
  --redirect --keep-until-expiring

nginx -t
systemctl reload nginx

echo "==> companion API domain(s)"
CONFIGURE_API="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/configure-api-domain.sh"
[[ -x "$CONFIGURE_API" ]] || {
  echo "ERROR: configure-api-domain.sh must be executable and next to add-domain.sh" >&2
  exit 1
}
IFS=. read -ra DOMAIN_LABELS <<< "$DOMAIN"
LABEL_COUNT=${#DOMAIN_LABELS[@]}
TAKE=2
TLD=${DOMAIN_LABELS[LABEL_COUNT-1]}
SECOND_LEVEL=${DOMAIN_LABELS[LABEL_COUNT-2]}
if (( LABEL_COUNT >= 3 && ${#TLD} == 2 && ${#SECOND_LEVEL} <= 3 )); then
  TAKE=3
fi
START=$((LABEL_COUNT - TAKE))
API_BASE_DOMAIN=$(IFS=.; echo "${DOMAIN_LABELS[*]:START}")
"$CONFIGURE_API" --domain "$API_BASE_DOMAIN" --email "$EMAIL"

echo "==> renewal timer"
systemctl enable --now certbot.timer
systemctl status certbot.timer --no-pager | head -3 || true

echo
echo "done. verify:"
echo "  curl -I https://$DOMAIN/health"
echo "  certbot certificates | grep -A3 $DOMAIN"
