#!/usr/bin/env bash
# Configure existing independent status server domain and Caddy managed ACME TLS.
# Does not touch ArchForge checkout, SQLite, admin account or main ArchForge website.
set -Eeuo pipefail
umask 077
fail(){ printf '[ERROR] %s\n' "$*" >&2; exit 1; }
info(){ printf '[*] %s\n' "$*"; }
ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
# shellcheck source=domain-lib.sh
source "$ROOT_DIR/scripts/domain-lib.sh"
[[ $EUID -eq 0 ]] || fail 'Run: sudo bash ./configure-domain.sh (or bash as root)'
[[ -t 0 ]] || fail 'An interactive SSH terminal is required'
[[ -f /etc/os-release ]] || fail 'Cannot check operating system'
# No arbitrary environment path overrides for privileged install operations.
source /etc/os-release
[[ ${ID:-} == debian && ${VERSION_ID:-} == 13 ]] || fail 'This setup is for Debian 13 only'

CFG=/etc/archforge-status/status.env
CADDYFILE=/etc/caddy/Caddyfile
SITEFILE=/etc/caddy/conf.d/archforge-status.caddy
[[ -f "$CFG" && ! -L "$CFG" ]] || fail 'Status configuration missing. Run install.sh before domain setup.'
[[ -f "$CADDYFILE" && ! -L "$CADDYFILE" ]] || fail 'Caddyfile missing. Install Caddy first.'
for prog in caddy systemctl curl dig python3; do
  command -v "$prog" >/dev/null || fail "$prog is missing. Install with: apt-get install -y caddy curl dnsutils python3"
done
mkdir -p /etc/caddy/conf.d
[[ ! -L "$SITEFILE" ]] || fail 'Refusing to change a symlinked Caddy site configuration'
OLD_DOMAIN=$(af_read_public_domain "$CFG") || fail 'STATUS_PUBLIC_URL is invalid in status.env'

printf '\n==============================================\n'
printf ' ArchForge Status — Domein & SSL Wizard\n Debian 13 • Caddy (automatic HTTPS)\n==============================================\n\n'
printf 'Current domain: %s\n' "$OLD_DOMAIN"
read -rp "New/confirmed status domain [${OLD_DOMAIN}]: " DOMAIN
DOMAIN=${DOMAIN:-$OLD_DOMAIN}
DOMAIN=${DOMAIN,,}
af_valid_domain "$DOMAIN" || fail 'Invalid domain. Use a complete host such as status.archforge.nl.'
read -rp 'Public IPv4 of THIS Debian VPS (VPS 2): ' IPV4
af_valid_ipv4 "$IPV4" || fail 'Please enter a valid IPv4 address of VPS 2.'
python3 - "$IPV4" <<'PYIP' || fail 'VPS IP must be a public, globally routable IPv4 address.'
import ipaddress,sys
assert ipaddress.IPv4Address(sys.argv[1]).is_global
PYIP
read -rp 'Public IPv6 of VPS 2 (Enter if no working IPv6): ' IPV6
[[ -z "$IPV6" ]] || af_valid_ipv6 "$IPV6" || fail 'Invalid IPv6 address'
read -rp 'ACME contact email (recommended, Enter to skip): ' EMAIL
af_valid_email "$EMAIL" || fail 'Invalid email'

printf '\nChecking public DNS for %s ...\n' "$DOMAIN"
A_RECORDS=$(af_dns_records A "$DOMAIN")
AAAA_RECORDS=$(af_dns_records AAAA "$DOMAIN")
printf 'DNS A: %s\n' "${A_RECORDS:-[not found]}"
printf 'DNS AAAA: %s\n' "${AAAA_RECORDS:-[not found]}"
if [[ -z "$A_RECORDS" ]] || [[ "$(printf '%s\n' "$A_RECORDS" | sort -u)" != "$IPV4" ]]; then
  printf '\n[DNS NOT READY] Add/change this record at your DNS provider:\n'
  printf 'Type A | Host %s | Value %s\n' "$DOMAIN" "$IPV4"
  printf 'Remove any other A records for this subdomain pointing elsewhere.\n'
  printf 'Wait for DNS propagation, then rerun this script. No configuration changed.\n'
  exit 2
fi
if [[ -n "$AAAA_RECORDS" ]]; then
  [[ -n "$IPV6" ]] || fail 'DNS AAAA exists but no VPS 2 IPv6 was supplied. Remove incorrect AAAA or rerun with your real IPv6. No changes made.'
  python3 - "$IPV6" "$AAAA_RECORDS" <<'PY' || fail 'DNS AAAA does not match the VPS 2 IPv6 address. No changes made.'
import ipaddress, sys
expected = ipaddress.IPv6Address(sys.argv[1])
found = [ipaddress.IPv6Address(line) for line in sys.argv[2].splitlines() if line.strip()]
assert found and all(value == expected for value in found)
PY
fi
if [[ -n "$IPV6" && -z "$AAAA_RECORDS" ]]; then
  info 'No AAAA record found. IPv6 is optional; IPv4 HTTPS can work without it.'
fi

printf '\nCaddy needs TCP 80/443 reachable from the internet to issue a certificate.\n'
printf 'Set DNS directly to VPS 2 (not through VPS 1). Check the VPS provider firewall.\n'
if command -v ss >/dev/null; then
  printf '\nCurrent port listeners (check for nginx/apache conflicts):\n'
  ss -ltnp | grep -E '(^State|:80[[:space:]]|:443[[:space:]])' || true
fi
if command -v ufw >/dev/null && ufw status | grep -q '^Status: active'; then
  read -rp 'UFW is active. Allow TCP 80 and 443? Type ALLOW: ' UFW_ANSWER
  if [[ "$UFW_ANSWER" == ALLOW ]]; then
    ufw allow 80/tcp
    ufw allow 443/tcp
  else
    info 'UFW rules untouched; make sure both ports are reachable.'
  fi
fi
printf '\nWill configure HTTPS for https://%s and update STATUS_PUBLIC_URL.\n' "$DOMAIN"
printf 'The status database, administrator and other secrets will be preserved.\n'
read -rp 'Type ENABLE to apply and start Caddy: ' CONFIRM
[[ "$CONFIRM" == ENABLE ]] || fail 'Cancelled without changing application or Caddy settings.'

# Backup all impacted files before changing them. Restore on validation/service failure.
TEMP=$(mktemp -d /root/.archforge-tls-setup.XXXXXXXX)
chmod 700 "$TEMP"
cleanup(){ rm -rf -- "$TEMP"; }
trap cleanup EXIT
cp -a -- "$CFG" "$TEMP/status.env"
cp -a -- "$CADDYFILE" "$TEMP/Caddyfile"
if [[ -f "$SITEFILE" ]]; then cp -a -- "$SITEFILE" "$TEMP/site.caddy"; fi
restore_previous() {
  printf '[!] Domain setup failed; restoring previous local configuration.\n' >&2
  cp -a -- "$TEMP/status.env" "$CFG"
  cp -a -- "$TEMP/Caddyfile" "$CADDYFILE"
  if [[ -f "$TEMP/site.caddy" ]]; then cp -a -- "$TEMP/site.caddy" "$SITEFILE"; else rm -f -- "$SITEFILE"; fi
  systemctl reload caddy >/dev/null 2>&1 || true
}
if ! af_render_caddy "$DOMAIN" "$EMAIL" > "$SITEFILE"; then
  restore_previous
  fail 'Unable to generate safe Caddy configuration'
fi
chmod 644 "$SITEFILE"
if ! grep -Eq '^[[:space:]]*import[[:space:]]+/etc/caddy/conf\.d/\*\.caddy[[:space:]]*$' "$CADDYFILE"; then
  printf '\nimport /etc/caddy/conf.d/*.caddy\n' >> "$CADDYFILE"
fi
if ! caddy validate --config "$CADDYFILE"; then
  restore_previous
  fail 'Caddy validation failed. Inspect other domain bindings and Caddyfile imports.'
fi
if ! systemctl enable --now caddy || ! systemctl reload caddy; then
  restore_previous
  fail 'Caddy could not start/reload. Check port 80/443 conflicts and journalctl -u caddy.'
fi
if ! af_set_public_domain "$CFG" "$DOMAIN"; then
  restore_previous
  fail 'Could not update STATUS_PUBLIC_URL. Application secrets were preserved.'
fi
if systemctl is-active --quiet archforge-status; then
  if ! systemctl restart archforge-status; then
    restore_previous
    systemctl restart archforge-status || true
    fail 'Status service restart failed. Old domain settings restored.'
  fi
else
  info 'archforge-status is not active. Start it separately once admin setup is complete.'
fi

info 'Caddy accepts the domain configuration and has started certificate management.'
info 'Verifying a trusted HTTPS certificate from the local Caddy instance...'
TLS_OK=false
for attempt in 1 2 3 4 5; do
  if curl --silent --show-error --fail --max-time 8 --resolve "${DOMAIN}:443:127.0.0.1" "https://${DOMAIN}/healthz" -o /dev/null 2>"$TEMP/curl.err"; then
    TLS_OK=true
    break
  fi
  sleep 3
done
printf '\n==============================================\n'
printf ' Domain configured: https://%s\n' "$DOMAIN"
printf ' Admin panel: https://%s/admin/login\n' "$DOMAIN"
if [[ "$TLS_OK" == true ]]; then
  printf ' TLS: locally verified (trusted certificate, live /healthz)\n'
else
  printf ' TLS: NOT YET VERIFIED — issuance may still be pending!\n'
  printf ' Check DNS, public TCP 80/443, provider firewall and Caddy logs.\n'
  printf ' Logs: journalctl -u caddy -n 80 --no-pager\n'
  printf ' Direct check: curl -Iv https://%s\n' "$DOMAIN"
fi
printf '==============================================\n'
# DNS correctness and validation succeeded, but TLS handshake may need time/ports.
# Do not claim the public site is already reachable in that case.
