#!/bin/bash
# =============================================================================
# 365-domains.sh -- Domain Manager
# =============================================================================
# Category: 365 | Bird: swan | Tier: 3 | Node-aware: yes
#
# Actions:
#   --status         JSON pill (domain + SSL health)
#   --list           List managed domains + SSL expiry
#   --ssl-check      Check SSL certificate expiry for all domains
#   --renew [domain] Renew SSL via certbot (veil-gated)
#   --dns-check      Verify DNS records resolve correctly
#   --dns-add        Add DNS record via PowerDNS API
#   --dns-remove     Remove DNS record via PowerDNS API
#   --verify         Full domain verification
#   --send           Domain health scan
#   --digest         Full report
#   --flush          Truncate log
# =============================================================================

TOOL_NAME="365-domains"
TOOL_VERSION="3.0.0"
TOOL_TIER=3
TOOL_BIRD="swan"
TOOL_LOG="/opt/binary/logs/tools/${TOOL_NAME}.log"

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
if [[ -f "${SCRIPT_DIR}/common.sh" ]]; then source "${SCRIPT_DIR}/common.sh"
elif [[ -f "${SCRIPT_DIR}/../common.sh" ]]; then source "${SCRIPT_DIR}/../common.sh"
else echo "FATAL: common.sh not found" >&2; exit 1; fi
export BIRD_ID="${TOOL_BIRD}"

FLEET_ENV="/etc/binary/fleet.env"
[ -f "$FLEET_ENV" ] && source "$FLEET_ENV" 2>/dev/null
PDNS_HOST="${FLEET_ALPHA_IP:-10.69.69.1}"
PDNS_API="http://${PDNS_HOST}:8081/api/v1"
PDNS_KEY_FILE="/etc/binary/pdns-api.key"
MANAGED_DOMAINS=("365hosting.org" "365email.org" "365entertainment.org")

_get_pdns_key() { cat "$PDNS_KEY_FILE" 2>/dev/null || echo ""; }

# --list / --ssl-check
_do_ssl_check_impl() {
    echo "=== SSL Check: ${NODE_ID} ==="
    local ok=0 warn=0 fail=0
    # Check managed domains
    for domain in "${MANAGED_DOMAINS[@]}"; do
        local expiry days_left status
        expiry=$(echo | timeout 5 openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
        if [ -n "$expiry" ]; then
            days_left=$(( ($(date -d "$expiry" +%s 2>/dev/null) - $(date +%s)) / 86400 ))
            if [ "$days_left" -le 0 ]; then
                status="EXPIRED"; fail=$((fail+1))
            elif [ "$days_left" -le 14 ]; then
                status="EXPIRING (${days_left}d)"; warn=$((warn+1))
            else
                status="OK (${days_left}d)"; ok=$((ok+1))
            fi
            echo "  ${domain}: ${status}"
        else
            echo "  ${domain}: UNREACHABLE"
            fail=$((fail+1))
        fi
    done
    # Also check nginx vhosts for certbot-managed certs
    for cert_dir in /etc/letsencrypt/live/*/; do
        local cn; cn=$(basename "$cert_dir")
        [ "$cn" = "README" ] && continue
        local cert="${cert_dir}cert.pem"
        [ -f "$cert" ] || continue
        local exp; exp=$(openssl x509 -noout -enddate -in "$cert" 2>/dev/null | cut -d= -f2)
        local dl=$(( ($(date -d "$exp" +%s 2>/dev/null) - $(date +%s)) / 86400 ))
        if [ "$dl" -le 14 ]; then
            echo "  [CERT] ${cn}: ${dl}d remaining"
        fi
    done
    echo ""
    echo "  OK: ${ok}  Warning: ${warn}  Expired: ${fail}"
    tool_audit "ssl_check" "ok=${ok} warn=${warn} fail=${fail} node=${NODE_ID}"
}

# --renew (certbot renewal — veil-gated)
_do_renew_impl() {
    local domain="${1:-}"
    echo "=== SSL Renewal: ${NODE_ID} ==="
    if ! command -v certbot &>/dev/null; then
        echo "  [FAIL] certbot not installed"
        return 1
    fi
    if [ -n "$domain" ]; then
        echo "  Renewing: ${domain}"
        certbot renew --cert-name "$domain" --non-interactive 2>&1 | tail -10 | sed 's/^/  /'
    else
        echo "  Renewing all eligible certificates..."
        certbot renew --non-interactive 2>&1 | tail -15 | sed 's/^/  /'
    fi
    local rc=$?
    # Reload web server after renewal
    if [ "$rc" -eq 0 ]; then
        if systemctl is-active nginx &>/dev/null; then
            systemctl reload nginx 2>/dev/null && echo "  [OK] nginx reloaded"
        elif systemctl is-active caddy &>/dev/null; then
            systemctl reload caddy 2>/dev/null && echo "  [OK] caddy reloaded"
        fi
    fi
    tool_audit "renew" "domain=${domain:-all} exit_code=${rc} node=${NODE_ID}"
    return $rc
}

# --dns-check
_do_dns_check_impl() {
    echo "=== DNS Check: ${NODE_ID} ==="
    for domain in "${MANAGED_DOMAINS[@]}"; do
        local a_rec; a_rec=$(dig +short A "$domain" 2>/dev/null | head -1)
        local mx_rec; mx_rec=$(dig +short MX "$domain" 2>/dev/null | head -1)
        local ns_rec; ns_rec=$(dig +short NS "$domain" 2>/dev/null | head -1)
        echo "  ${domain}:"
        echo "    A:  ${a_rec:-NONE}"
        echo "    MX: ${mx_rec:-NONE}"
        echo "    NS: ${ns_rec:-NONE}"
    done
    tool_audit "dns_check" "node=${NODE_ID}"
}

# --dns-add / --dns-remove (PowerDNS API)
_do_dns_modify_impl() {
    local action="$1" domain="$2" record_type="${3:-A}" record_value="$4"
    [ -z "$domain" ] || [ -z "$record_value" ] && { echo "Usage: --dns-${action} <domain> <type> <value>"; return 1; }
    local key; key=$(_get_pdns_key)
    [ -z "$key" ] && { echo "  [FAIL] No PowerDNS API key"; return 1; }
    echo "=== DNS ${action}: ${NODE_ID} ==="
    echo "  ${action}: ${record_type} ${domain} -> ${record_value}"
    # PowerDNS PATCH request
    local changetype="REPLACE"; [ "$action" = "remove" ] && changetype="DELETE"
    local zone; zone=$(echo "$domain" | awk -F. '{print $(NF-1)"."$NF}')
    local j_domain j_rtype j_rval j_ctype
    j_domain="$(json_escape "$domain")"
    j_rtype="$(json_escape "$record_type")"
    j_rval="$(json_escape "$record_value")"
    j_ctype="$(json_escape "$changetype")"
    curl -sf -X PATCH "${PDNS_API}/servers/localhost/zones/${zone}." \
        -H "X-API-Key: ${key}" \
        -H "Content-Type: application/json" \
        -d "{\"rrsets\":[{\"name\":\"${j_domain}.\",\"type\":\"${j_rtype}\",\"changetype\":\"${j_ctype}\",\"ttl\":300,\"records\":[{\"content\":\"${j_rval}\",\"disabled\":false}]}]}" 2>/dev/null
    local rc=$?
    [ "$rc" -eq 0 ] && echo "  [OK] ${action} complete" || echo "  [FAIL] ${action} failed"
    tool_audit "dns_${action}" "domain=${domain} type=${record_type} value=${record_value} node=${NODE_ID}"
    return $rc
}

# --verify
_do_verify_impl() {
    echo "=== Domain Verification: ${NODE_ID} ==="
    local pass=0 fail=0
    for domain in "${MANAGED_DOMAINS[@]}"; do
        # DNS resolves
        if dig +short A "$domain" 2>/dev/null | grep -q '.'; then
            echo "  [OK] ${domain}: DNS resolves"; pass=$((pass+1))
        else
            echo "  [FAIL] ${domain}: DNS fails"; fail=$((fail+1))
        fi
        # SSL valid
        local exp; exp=$(echo | timeout 5 openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
        if [ -n "$exp" ]; then
            local dl=$(( ($(date -d "$exp" +%s 2>/dev/null) - $(date +%s)) / 86400 ))
            if [ "$dl" -gt 0 ]; then echo "  [OK] ${domain}: SSL ${dl}d"; pass=$((pass+1))
            else echo "  [FAIL] ${domain}: SSL expired"; fail=$((fail+1)); fi
        fi
    done
    echo ""; echo "  Passed: ${pass}  Failed: ${fail}"
    tool_audit "verify" "pass=${pass} fail=${fail} node=${NODE_ID}"
    return $fail
}

_do_send_impl() {
    echo "=== Domains: ${NODE_ID} ==="
    _do_ssl_check_impl; echo ""
    _do_dns_check_impl
}

_do_status_impl() {
    local s="healthy" exp_count=0
    for domain in "${MANAGED_DOMAINS[@]}"; do
        local exp; exp=$(echo | timeout 3 openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
        if [ -n "$exp" ]; then
            local dl=$(( ($(date -d "$exp" +%s 2>/dev/null) - $(date +%s)) / 86400 ))
            [ "$dl" -le 14 ] && exp_count=$((exp_count+1))
        fi
    done
    [ "$exp_count" -gt 0 ] && s="degraded"
    echo "{\"tool\":\"${TOOL_NAME}\",\"node\":\"${NODE_ID}\",\"status\":\"${s}\",\"expiring\":${exp_count},\"domains\":${#MANAGED_DOMAINS[@]},\"checked_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
}

_do_digest_impl() { echo "=== Domain Report: ${NODE_ID} ==="; _do_send_impl; echo ""; _do_verify_impl; }
_do_flush_impl() { [ -f "$TOOL_LOG" ] && truncate -s 0 "$TOOL_LOG"; echo "Flush complete"; }

tool_help() {
    echo "${TOOL_NAME} v${TOOL_VERSION} -- Domain Manager"
    echo ""
    echo "Status:"
    echo "  --list / --ssl-check   SSL expiry for all domains"
    echo "  --dns-check            DNS record verification"
    echo "  --verify               Full domain verification"
    echo "  --status               JSON pill"
    echo ""
    echo "Actions (veil-gated):"
    echo "  --renew [domain]       SSL renewal via certbot"
    echo "  --dns-add <domain> <type> <value>    Add DNS record"
    echo "  --dns-remove <domain> <type> <value> Remove DNS record"
    echo ""
    echo "Standard: --send|--digest|--flush"
}

do_send()   { tool_wrap "send"   _do_send_impl "$@"; }
do_status() { tool_wrap "status" _do_status_impl "$@"; }
do_digest() { tool_wrap "digest" _do_digest_impl "$@"; }
do_flush()  { tool_wrap "flush"  _do_flush_impl "$@"; }

tool_init; trap 'tool_complete' EXIT
case "${1:---help}" in
    --send) shift; do_send "$@" ;; --status) shift; do_status "$@" ;;
    --digest) shift; do_digest "$@" ;; --flush) shift; do_flush "$@" ;;
    --list|--ssl-check) tool_wrap "ssl_check" _do_ssl_check_impl ;;
    --renew) shift; tool_wrap "renew" _do_renew_impl "$@" ;;
    --dns-check) tool_wrap "dns_check" _do_dns_check_impl ;;
    --dns-add) shift; tool_wrap "dns_add" _do_dns_modify_impl "add" "$@" ;;
    --dns-remove) shift; tool_wrap "dns_remove" _do_dns_modify_impl "remove" "$@" ;;
    --verify) tool_wrap "verify" _do_verify_impl ;;
    --help) tool_help ;; *) handle_standard_command "$@" ;;
esac
