#!/usr/bin/env bash
# AutoSSL watchdog: runs after every AutoSSL cycle.
# Detects cert/key mismatches introduced by AutoSSL renewals BEFORE they break Apache.
# Fixes them automatically using cPanel API when possible.
#
# Triggered by: cron (hourly, offset to run ~5 min after AutoSSL)
# Also safe to run manually anytime.

set -uo pipefail

LOG_FILE="/opt/server-resilience/logs/autossl-watchdog-$(date +%Y%m%d).log"
ALERT_SCRIPT="/opt/server-resilience/bin/send-alert"
SSL_TLS_DIR="/var/cpanel/ssl/apache_tls"

mkdir -p "$(dirname "$LOG_FILE")"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }

FIXED=0; UNFIXABLE=0

log "=== AutoSSL watchdog run ==="

for dir in "$SSL_TLS_DIR"/*/; do
    domain=$(basename "$dir")
    combined="$dir/combined"
    key_file="$dir/key"

    [[ ! -f "$combined" || ! -f "$key_file" ]] && continue

    # Only check domains active in Apache config
    grep -q "apache_tls/$domain/" /etc/apache2/conf/httpd.conf /etc/apache2/conf.d/*.conf 2>/dev/null || continue

    cert_md5=$(openssl x509 -noout -modulus -in "$combined" 2>/dev/null | openssl md5 | awk '{print $2}')
    key_md5=$(openssl rsa -noout -modulus -in "$key_file" 2>/dev/null | openssl md5 | awk '{print $2}')

    [[ -z "$cert_md5" ]] && continue
    [[ "$cert_md5" == "$key_md5" ]] && continue

    log "MISMATCH DETECTED: $domain — cert=$cert_md5 key=$key_md5"

    # ── Fix strategy 1: Check if a wildcard cert covers this domain ──────────
    # Extract base domain (e.g. news.cmptv.ca → *.cmptv.ca)
    BASE_DOMAIN=$(echo "$domain" | sed 's/^[^.]*\.//')
    WILDCARD_DIR="$SSL_TLS_DIR/*.${BASE_DOMAIN}"

    if [[ -d "$WILDCARD_DIR" ]]; then
        wc_cert_md5=$(openssl x509 -noout -modulus -in "$WILDCARD_DIR/combined" 2>/dev/null | openssl md5 | awk '{print $2}')
        wc_key_md5=$(openssl rsa -noout -modulus -in "$WILDCARD_DIR/key" 2>/dev/null | openssl md5 | awk '{print $2}')
        if [[ -n "$wc_cert_md5" && "$wc_cert_md5" == "$wc_key_md5" ]]; then
            log "Fixing $domain using wildcard cert for *.$BASE_DOMAIN"
            # Find cPanel user
            CPANEL_USER=$(grep "^$domain:" /etc/userdatadomains 2>/dev/null | cut -d= -f2 | cut -d= -f1 || echo "")
            if [[ -n "$CPANEL_USER" ]]; then
                TMPDIR=$(mktemp -d)
                openssl x509 -in "$WILDCARD_DIR/combined" > "$TMPDIR/cert.pem" 2>/dev/null
                cp "$WILDCARD_DIR/key" "$TMPDIR/key.pem"
                awk '/-----BEGIN CERTIFICATE-----/{n++} n==2{print}' "$WILDCARD_DIR/combined" > "$TMPDIR/ca.pem"
                RESULT=$(/usr/local/cpanel/bin/whmapi1 installssl \
                    user="$CPANEL_USER" domain="$domain" \
                    crt=@"$TMPDIR/cert.pem" key=@"$TMPDIR/key.pem" cabundle=@"$TMPDIR/ca.pem" 2>/dev/null \
                    | grep "result:" | awk '{print $2}')
                rm -rf "$TMPDIR"
                if [[ "$RESULT" == "1" ]]; then
                    log "SUCCESS: Installed wildcard cert for $domain via whmapi1"
                    ((FIXED++))
                    continue
                fi
            fi
            # Fallback: direct file copy if whmapi1 fails
            log "whmapi1 failed or no user found — directly installing wildcard key for $domain"
            install -m 600 "$WILDCARD_DIR/key" "$key_file"
            # Verify fix
            new_key_md5=$(openssl rsa -noout -modulus -in "$key_file" 2>/dev/null | openssl md5 | awk '{print $2}')
            if [[ "$cert_md5" == "$new_key_md5" ]]; then
                log "SUCCESS: Direct key replacement fixed $domain"
                ((FIXED++))
                continue
            fi
        fi
    fi

    # ── Fix strategy 2: Trigger AutoSSL re-run for this domain ───────────────
    log "Triggering AutoSSL re-run for $domain"
    CPANEL_USER=$(grep "^$domain:" /etc/userdatadomains 2>/dev/null | cut -d= -f2 | cut -d= -f1 || echo "")
    if [[ -n "$CPANEL_USER" ]]; then
        /usr/local/cpanel/scripts/autossl_check --user="$CPANEL_USER" &>/dev/null &
        log "AutoSSL check triggered for user $CPANEL_USER (covers $domain)"
    fi

    # ── Alert: this domain needs attention ───────────────────────────────────
    log "UNFIXABLE (for now): $domain — sending alert"
    "$ALERT_SCRIPT" "CRITICAL" \
        "AutoSSL mismatch on $domain: cert/key do not match. Apache WILL fail to restart. AutoSSL re-run triggered." \
        2>/dev/null || true
    ((UNFIXABLE++))
done

log "=== Watchdog complete: fixed=$FIXED unfixable=$UNFIXABLE ==="

# If any were fixed, do a safe Apache reload to pick up new certs
if [[ $FIXED -gt 0 ]]; then
    log "Certs fixed — graceful Apache reload"
    apachectl graceful 2>/dev/null || true
fi

exit 0
