#!/usr/bin/env bash
#
# setup-ssl.sh — Install a free Let's Encrypt SSL certificate on
# Amazon Linux 1 + Apache using acme.sh
#
# Usage:
#   sudo bash setup-ssl.sh PRIMARY_DOMAIN [EXTRA_DOMAIN ...]
#   e.g. sudo bash setup-ssl.sh dev.basetax.co.uk mtd.dev.basetax.co.uk api.dev.basetax.co.uk bookkeeping.dev.basetax.co.uk
#
# Prerequisites:
#   - A domain with DNS A record pointing to this EC2 instance's public IP
#   - Apache (httpd) installed and serving on port 80
#   - Security group allows inbound TCP 80 AND 443
#   - Run as root (or with sudo)
#
set -euo pipefail

# ── Argument handling ────────────────────────────────────────────────
if [[ $# -lt 1 ]]; then
    echo "Usage: sudo bash setup-ssl.sh PRIMARY_DOMAIN [EXTRA_DOMAIN ...]"
    echo "  e.g. sudo bash setup-ssl.sh dev.basetax.co.uk mtd.dev.basetax.co.uk api.dev.basetax.co.uk"
    exit 1
fi

DOMAIN="$1"            # primary domain (used for cert paths / filenames)
ALL_DOMAINS=("$@")     # every domain goes into the SAN certificate

# ── Pre-flight checks ───────────────────────────────────────────────
if [[ $EUID -ne 0 ]]; then
    echo "ERROR: This script must be run as root (use sudo)."
    exit 1
fi

# acme.sh refuses to run when it detects SUDO_USER. Since we already
# verified we are root, clear the variable so acme.sh cooperates.
unset SUDO_USER

echo "==> Checking that Apache is running..."
if ! service httpd status >/dev/null 2>&1; then
    echo "ERROR: Apache (httpd) is not running. Start it first: sudo service httpd start"
    exit 1
fi

echo "==> Checking that port 443 is not already bound by another process..."
if ss -tlnp | grep -q ':443 '; then
    echo "WARNING: Something is already listening on port 443. Continuing anyway."
fi

# ── Step 1: Install mod_ssl if missing ───────────────────────────────
# Amazon Linux 1 may have httpd24 (Apache 2.4) instead of httpd (2.2).
# The SSL module package name differs between the two.
if rpm -q httpd24 >/dev/null 2>&1; then
    SSL_PKG="mod24_ssl"
elif rpm -q httpd >/dev/null 2>&1; then
    SSL_PKG="mod_ssl"
else
    echo "ERROR: Neither httpd24 nor httpd appears to be installed."
    exit 1
fi

echo "==> Installing $SSL_PKG (if not already present)..."
yum install -y "$SSL_PKG"

# ── Step 2: Install acme.sh ─────────────────────────────────────────
# acme.sh is a pure-shell ACME client — no Python or Snap dependencies.
# It works reliably on Amazon Linux 1 where certbot often fails.
ACME_HOME="/root/.acme.sh"

if [[ ! -d "$ACME_HOME" ]]; then
    echo "==> Installing acme.sh..."
    curl https://get.acme.sh | sh -s email=admin@"$DOMAIN"
else
    echo "==> acme.sh already installed, upgrading..."
    "$ACME_HOME"/acme.sh --upgrade
fi

# Source acme.sh so it's available in this session
source "$ACME_HOME"/acme.sh.env

# ── Step 3: Issue the certificate ────────────────────────────────────
# Uses standalone mode — temporarily stops Apache so acme.sh can bind
# port 80 with its own HTTP server for the ACME challenge. This avoids
# any interference from existing Apache redirects or vhost configs.

echo "==> Issuing certificate for: ${ALL_DOMAINS[*]} ..."

DOMAIN_ARGS=""
for d in "${ALL_DOMAINS[@]}"; do
    DOMAIN_ARGS="$DOMAIN_ARGS -d $d"
done

echo "==> Temporarily stopping Apache for ACME verification..."
service httpd stop

"$ACME_HOME"/acme.sh --issue $DOMAIN_ARGS --standalone --server letsencrypt --force

echo "==> Restarting Apache..."
service httpd start

# ── Step 4: Install the certificate for Apache ──────────────────────
CERT_DIR="/etc/ssl/basetax"
mkdir -p "$CERT_DIR"

echo "==> Installing certificate to $CERT_DIR ..."

"$ACME_HOME"/acme.sh --install-cert -d "$DOMAIN" \
    --cert-file      "$CERT_DIR/cert.pem" \
    --key-file       "$CERT_DIR/key.pem" \
    --fullchain-file "$CERT_DIR/fullchain.pem" \
    --reloadcmd      "service httpd graceful"

# ── Step 5: Configure Apache SSL virtual hosts ───────────────────────
# Create one vhost file per domain, all sharing the same SAN certificate.

for d in "${ALL_DOMAINS[@]}"; do
    SSL_CONF="/etc/httpd/conf.d/ssl-${d}.conf"
    echo "==> Writing Apache SSL config for $d → $SSL_CONF ..."

    cat > "$SSL_CONF" <<APACHE_CONF
<VirtualHost *:443>
    ServerName $d

    DocumentRoot /var/www/html

    SSLEngine on
    SSLCertificateFile      $CERT_DIR/fullchain.pem
    SSLCertificateKeyFile   $CERT_DIR/key.pem

    # Modern TLS settings — disable old protocols and weak ciphers
    SSLProtocol             all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder     on

    # HSTS header (optional but recommended — uncomment when you're confident)
    # Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"

    # Proxy to a local app server (uncomment and adjust port per subdomain)
    # ProxyPreserveHost On
    # ProxyPass        / http://127.0.0.1:3000/
    # ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>

# Redirect HTTP to HTTPS for $d (except ACME challenges for renewals)
<VirtualHost *:80>
    ServerName $d
    DocumentRoot /var/www/html

    # Let ACME challenges through without redirect
    Alias /.well-known/acme-challenge /var/www/html/.well-known/acme-challenge
    <Directory /var/www/html/.well-known/acme-challenge>
        AllowOverride None
        Require all granted
    </Directory>

    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
    RewriteRule ^(.*)\$ https://%{HTTP_HOST}\$1 [R=301,L]
</VirtualHost>
APACHE_CONF
done

# ── Step 6: Test config and reload ───────────────────────────────────
# Use the correct binary name for httpd24 vs httpd
if command -v httpd >/dev/null 2>&1; then
    HTTPD_BIN="httpd"
elif command -v apachectl >/dev/null 2>&1; then
    HTTPD_BIN="apachectl"
else
    HTTPD_BIN="httpd"
fi

echo "==> Testing Apache configuration..."
if $HTTPD_BIN -t 2>&1; then
    echo "==> Configuration OK. Reloading Apache..."
    service httpd graceful
else
    echo "ERROR: Apache config test failed. Check /etc/httpd/conf.d/ssl-*.conf"
    exit 1
fi

# ── Step 7: Verify auto-renewal cron ────────────────────────────────
# acme.sh automatically installs a cron job during installation.
echo "==> Verifying auto-renewal cron..."
if crontab -l 2>/dev/null | grep -q acme.sh; then
    echo "    Auto-renewal cron is active."
else
    echo "    WARNING: No acme.sh cron found. Adding one now..."
    "$ACME_HOME"/acme.sh --install-cronjob
fi

# ── Done ─────────────────────────────────────────────────────────────
echo ""
echo "============================================"
echo " SSL setup complete!"
echo "============================================"
echo ""
echo " Domains:"
for d in "${ALL_DOMAINS[@]}"; do
    echo "   - https://$d"
done
echo ""
echo " Certificate:  $CERT_DIR/fullchain.pem"
echo " Private key:  $CERT_DIR/key.pem"
echo " Apache confs: /etc/httpd/conf.d/ssl-*.conf"
echo ""
echo " The certificate will auto-renew via cron."
echo " To test renewal:  $ACME_HOME/acme.sh --renew -d $DOMAIN --force"
echo " To check cron:    crontab -l | grep acme"
echo ""
echo " IMPORTANT: Make sure your EC2 Security Group"
echo " allows inbound TCP on port 443 (HTTPS)."
echo ""
echo " NEXT STEP: Edit each /etc/httpd/conf.d/ssl-*.conf"
echo " to set the correct ProxyPass port per subdomain."
echo "============================================"
