#!/bin/bash
#
# configure-miab-metrics.sh - Enable extended metrics logging on Mail-in-a-Box
#
# Enables SpamAssassin rules logging and/or TLS cipher logging for
# postfix-metrics.sh to collect detailed metrics.
#

set -euo pipefail

SCRIPT_NAME=$(basename "$0")
VERSION="1.0.0"

# Defaults
DRY_RUN=false
VERBOSE=false
ENABLE_SPAMASSASSIN=false
ENABLE_TLS=false
BACKUP=true
FORCE=false
STATUS_ONLY=false

# Colors (disabled if not a terminal)
if [[ -t 1 ]]; then
    RED='\033[0;31m'
    GREEN='\033[0;32m'
    YELLOW='\033[1;33m'
    BLUE='\033[0;34m'
    NC='\033[0m'
else
    RED='' GREEN='' YELLOW='' BLUE='' NC=''
fi

usage() {
    cat <<EOF
Usage: $SCRIPT_NAME [OPTIONS]

Configure Mail-in-a-Box for extended metrics collection.

OPTIONS:
    -s, --spamassassin    Enable SpamAssassin rules logging (spampd debug mode)
    -t, --tls             Enable TLS cipher logging in Postfix
    -a, --all             Enable both (default if no -s or -t specified)
    
    -n, --dry-run         Show what would be done without making changes
    -f, --force           Skip confirmation prompts
    -v, --verbose         Show detailed output
    --no-backup           Don't create backups before modifying files
    --status              Show current configuration status and exit
    
    -h, --help            Show this help message
    --version             Show version

EXAMPLES:
    $SCRIPT_NAME                    # Enable both (interactive)
    $SCRIPT_NAME -a                 # Enable both (interactive)
    $SCRIPT_NAME -s                 # SpamAssassin only
    $SCRIPT_NAME -t                 # TLS cipher logging only
    $SCRIPT_NAME -a -n              # Dry run, show all changes
    $SCRIPT_NAME -a -f              # Enable both, no prompts
    
WHAT THIS SCRIPT DOES:

  SpamAssassin (-s):
    - Appends --debug to ADDOPTS in /etc/default/spampd
    - Creates rsyslog config to log to /var/log/spamassassin.log
    - Sets up log file with correct permissions
    - Creates logrotate config
    - Restarts spampd and rsyslog

  TLS Cipher (-t):
    - Adds smtpd_tls_loglevel=1 and smtp_tls_loglevel=1 to /etc/postfix/main.cf
    - Restarts Postfix

REQUIREMENTS:
    - Must be run as root (or with sudo)
    - Mail-in-a-Box installation
    - spampd service (for -s option)
    - postfix service (for -t option)

EOF
    exit 0
}

version() {
    echo "$SCRIPT_NAME version $VERSION"
    exit 0
}

log_info() {
    echo -e "${BLUE}[INFO]${NC} $*"
}

log_ok() {
    echo -e "${GREEN}[OK]${NC} $*"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $*"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $*" >&2
}

log_dry() {
    echo -e "${YELLOW}[DRY-RUN]${NC} $*"
}

log_verbose() {
    if $VERBOSE; then
        echo -e "${BLUE}[VERBOSE]${NC} $*"
    fi
}

run_cmd() {
    local desc="$1"
    shift
    if $DRY_RUN; then
        log_dry "$desc: $*"
        return 0
    fi
    log_verbose "Running: $*"
    if ! "$@"; then
        log_error "Failed: $desc"
        return 1
    fi
    return 0
}

write_file() {
    local file="$1"
    local content="$2"
    local desc="${3:-$file}"
    
    if $DRY_RUN; then
        log_dry "Would create $desc:"
        echo "$content" | sed 's/^/    /'
        return 0
    fi
    
    if [[ -f "$file" ]] && $BACKUP; then
        local backup="${file}.bak.$(date +%Y%m%d%H%M%S)"
        log_verbose "Backing up $file to $backup"
        cp "$file" "$backup"
    fi
    
    echo "$content" > "$file"
    log_ok "Created $desc"
}

check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "This script must be run as root (use sudo)"
        exit 1
    fi
}

check_miab() {
    if [[ ! -d /home/user-data ]] && [[ ! -f /etc/mailinabox.conf ]]; then
        log_warn "This doesn't appear to be a Mail-in-a-Box installation"
        if ! $FORCE; then
            read -rp "Continue anyway? [y/N] " response
            if [[ ! "$response" =~ ^[Yy] ]]; then
                exit 1
            fi
        fi
    fi
}

confirm_action() {
    local msg="$1"
    if $FORCE || $DRY_RUN; then
        return 0
    fi
    read -rp "$msg [y/N] " response
    [[ "$response" =~ ^[Yy] ]]
}

# ============================================================================
# SpamAssassin Configuration
# ============================================================================

SPAMPD_DEFAULTS="/etc/default/spampd"

check_spampd() {
    if ! systemctl list-unit-files spampd.service &>/dev/null; then
        log_error "spampd service not found"
        return 1
    fi
    return 0
}

is_spampd_debug_enabled() {
    # Check /etc/default/spampd for --debug in ADDOPTS
    if [[ -f "$SPAMPD_DEFAULTS" ]]; then
        if grep -qE '^ADDOPTS\s*=.*--debug' "$SPAMPD_DEFAULTS" 2>/dev/null; then
            return 0
        fi
    fi
    return 1
}

is_rsyslog_spamassassin_configured() {
    [[ -f /etc/rsyslog.d/50-spamassassin.conf ]]
}

is_logrotate_configured() {
    [[ -f /etc/logrotate.d/spamassassin ]]
}

configure_spamassassin() {
    log_info "Configuring SpamAssassin rules logging..."
    
    if ! check_spampd; then
        return 1
    fi
    
    local changes_made=false
    
    # 1. Enable debug mode via /etc/default/spampd
    if is_spampd_debug_enabled; then
        log_ok "spampd debug mode already enabled"
    else
        log_info "Enabling spampd debug mode..."
        
        if [[ ! -f "$SPAMPD_DEFAULTS" ]]; then
            log_error "$SPAMPD_DEFAULTS not found"
            return 1
        fi
        
        # Get current ADDOPTS value
        local current_addopts=""
        if grep -qE '^ADDOPTS\s*=' "$SPAMPD_DEFAULTS" 2>/dev/null; then
            current_addopts=$(grep -E '^ADDOPTS\s*=' "$SPAMPD_DEFAULTS" | tail -1 | sed 's/^ADDOPTS\s*=\s*//' | tr -d '"'"'")
        fi
        
        # Build new ADDOPTS with --debug appended
        local new_addopts
        if [[ -n "$current_addopts" ]]; then
            new_addopts="${current_addopts} --debug"
        else
            new_addopts="--debug"
        fi
        
        if $DRY_RUN; then
            log_dry "Would update ADDOPTS in $SPAMPD_DEFAULTS:"
            if [[ -n "$current_addopts" ]]; then
                echo "    Current: ADDOPTS=\"$current_addopts\""
            fi
            echo "    New:     ADDOPTS=\"$new_addopts\""
        else
            if $BACKUP; then
                local backup="${SPAMPD_DEFAULTS}.bak.$(date +%Y%m%d%H%M%S)"
                cp "$SPAMPD_DEFAULTS" "$backup"
                log_verbose "Backed up to $backup"
            fi
            
            if grep -qE '^ADDOPTS\s*=' "$SPAMPD_DEFAULTS"; then
                # Update existing ADDOPTS line
                sed -i "s|^ADDOPTS\s*=.*|ADDOPTS=\"$new_addopts\"|" "$SPAMPD_DEFAULTS"
                log_ok "Updated ADDOPTS to include --debug"
            else
                # Add new ADDOPTS line
                cat >> "$SPAMPD_DEFAULTS" <<EOF

# Enable debug logging for metrics collection (added by $SCRIPT_NAME)
ADDOPTS="--debug"
EOF
                log_ok "Added ADDOPTS=\"--debug\" to $SPAMPD_DEFAULTS"
            fi
        fi
        changes_made=true
    fi
    
    # 2. Create rsyslog config
    if is_rsyslog_spamassassin_configured; then
        log_ok "rsyslog spamassassin config already exists"
    else
        log_info "Creating rsyslog configuration..."
        
        local rsyslog_content="# Log spampd/spamd to separate file for metrics collection
:programname, isequal, \"spampd\" /var/log/spamassassin.log
& stop

:programname, isequal, \"spamd\" /var/log/spamassassin.log
& stop"
        
        write_file "/etc/rsyslog.d/50-spamassassin.conf" "$rsyslog_content" "rsyslog spamassassin config"
        changes_made=true
    fi
    
    # 3. Create log file with correct permissions
    if [[ -f /var/log/spamassassin.log ]]; then
        log_ok "Log file /var/log/spamassassin.log already exists"
    else
        log_info "Creating log file..."
        if ! $DRY_RUN; then
            touch /var/log/spamassassin.log
            chown syslog:adm /var/log/spamassassin.log
            chmod 640 /var/log/spamassassin.log
            log_ok "Created /var/log/spamassassin.log"
        else
            log_dry "Would create /var/log/spamassassin.log with syslog:adm ownership"
        fi
        changes_made=true
    fi
    
    # 4. Create logrotate config
    if is_logrotate_configured; then
        log_ok "Logrotate config already exists"
    else
        log_info "Creating logrotate configuration..."
        
        local logrotate_content="/var/log/spamassassin.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 640 syslog adm
    postrotate
        systemctl reload rsyslog > /dev/null 2>&1 || true
    endscript
}"
        
        write_file "/etc/logrotate.d/spamassassin" "$logrotate_content" "logrotate spamassassin config"
        changes_made=true
    fi
    
    # 5. Restart services if changes were made
    if $changes_made; then
        log_info "Restarting services..."
        run_cmd "Restart rsyslog" systemctl restart rsyslog
        run_cmd "Restart spampd" systemctl restart spampd
        
        if ! $DRY_RUN; then
            sleep 2
            if systemctl is-active --quiet spampd; then
                log_ok "spampd is running with debug mode"
            else
                log_error "spampd failed to start - check: journalctl -u spampd"
            fi
        fi
    else
        log_ok "SpamAssassin logging already fully configured"
    fi
    
    return 0
}

# ============================================================================
# TLS Cipher Configuration
# ============================================================================

POSTFIX_MAIN_CF="/etc/postfix/main.cf"

is_tls_logging_enabled() {
    if [[ ! -f "$POSTFIX_MAIN_CF" ]]; then
        return 1
    fi
    
    local smtpd_level smtp_level
    smtpd_level=$(grep -E '^smtpd_tls_loglevel\s*=' "$POSTFIX_MAIN_CF" 2>/dev/null | tail -1 | awk -F= '{print $2}' | tr -d ' ')
    smtp_level=$(grep -E '^smtp_tls_loglevel\s*=' "$POSTFIX_MAIN_CF" 2>/dev/null | tail -1 | awk -F= '{print $2}' | tr -d ' ')
    
    [[ "$smtpd_level" -ge 1 ]] 2>/dev/null && [[ "$smtp_level" -ge 1 ]] 2>/dev/null
}

configure_tls() {
    log_info "Configuring TLS cipher logging..."
    
    if [[ ! -f "$POSTFIX_MAIN_CF" ]]; then
        log_error "Postfix main.cf not found at $POSTFIX_MAIN_CF"
        return 1
    fi
    
    if is_tls_logging_enabled; then
        log_ok "TLS logging already enabled in Postfix"
        return 0
    fi
    
    log_info "Adding TLS log level settings to $POSTFIX_MAIN_CF..."
    
    if $DRY_RUN; then
        log_dry "Would add to $POSTFIX_MAIN_CF:"
        echo "    smtpd_tls_loglevel = 1"
        echo "    smtp_tls_loglevel = 1"
    else
        if $BACKUP; then
            local backup="${POSTFIX_MAIN_CF}.bak.$(date +%Y%m%d%H%M%S)"
            cp "$POSTFIX_MAIN_CF" "$backup"
            log_verbose "Backed up to $backup"
        fi
        
        # Remove any existing settings first (to avoid duplicates)
        sed -i '/^smtpd_tls_loglevel\s*=/d' "$POSTFIX_MAIN_CF"
        sed -i '/^smtp_tls_loglevel\s*=/d' "$POSTFIX_MAIN_CF"
        
        # Add new settings
        cat >> "$POSTFIX_MAIN_CF" <<EOF

# TLS cipher logging for metrics collection (added by $SCRIPT_NAME)
smtpd_tls_loglevel = 1
smtp_tls_loglevel = 1
EOF
        log_ok "Added TLS log level settings"
    fi
    
    # Restart Postfix
    log_info "Restarting Postfix..."
    run_cmd "Restart Postfix" systemctl restart postfix
    
    if ! $DRY_RUN; then
        sleep 2
        if systemctl is-active --quiet postfix; then
            log_ok "Postfix is running with TLS logging enabled"
        else
            log_error "Postfix failed to start - check: journalctl -u postfix"
            return 1
        fi
    fi
    
    return 0
}

# ============================================================================
# Status Check
# ============================================================================

show_status() {
    echo ""
    echo "Current Configuration Status:"
    echo "=============================="
    
    # Find spampd service file
    local service_file=""
    for f in /var/lib/systemd/system/spampd.service /lib/systemd/system/spampd.service /etc/systemd/system/spampd.service; do
        [[ -f "$f" ]] && service_file="$f" && break
    done
    
    echo -n "SpamAssassin debug mode: "
    if is_spampd_debug_enabled; then
        echo -e "${GREEN}ENABLED${NC}"
    else
        echo -e "${YELLOW}DISABLED${NC}"
    fi
    
    if $VERBOSE && [[ -n "$service_file" ]]; then
        echo "  Service file: $service_file"
        echo "  Defaults file: $SPAMPD_DEFAULTS"
    fi
    
    echo -n "SpamAssassin rsyslog:    "
    if is_rsyslog_spamassassin_configured; then
        echo -e "${GREEN}CONFIGURED${NC}"
    else
        echo -e "${YELLOW}NOT CONFIGURED${NC}"
    fi
    
    echo -n "SpamAssassin log file:   "
    if [[ -f /var/log/spamassassin.log ]]; then
        local size
        size=$(du -h /var/log/spamassassin.log 2>/dev/null | cut -f1)
        echo -e "${GREEN}EXISTS${NC} ($size)"
    else
        echo -e "${YELLOW}MISSING${NC}"
    fi
    
    echo -n "SpamAssassin logrotate:  "
    if is_logrotate_configured; then
        echo -e "${GREEN}CONFIGURED${NC}"
    else
        echo -e "${YELLOW}NOT CONFIGURED${NC}"
    fi
    
    echo -n "Postfix TLS logging:     "
    if is_tls_logging_enabled; then
        echo -e "${GREEN}ENABLED${NC}"
    else
        echo -e "${YELLOW}DISABLED${NC}"
    fi
    
    # Show service status
    echo ""
    echo -n "spampd service:          "
    if systemctl is-active --quiet spampd 2>/dev/null; then
        echo -e "${GREEN}RUNNING${NC}"
    else
        echo -e "${YELLOW}STOPPED${NC}"
    fi
    
    echo -n "postfix service:         "
    if systemctl is-active --quiet postfix 2>/dev/null; then
        echo -e "${GREEN}RUNNING${NC}"
    else
        echo -e "${YELLOW}STOPPED${NC}"
    fi
    
    echo ""
}

# ============================================================================
# Main
# ============================================================================

main() {
    # Parse arguments
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -s|--spamassassin)
                ENABLE_SPAMASSASSIN=true
                shift
                ;;
            -t|--tls)
                ENABLE_TLS=true
                shift
                ;;
            -a|--all)
                ENABLE_SPAMASSASSIN=true
                ENABLE_TLS=true
                shift
                ;;
            -n|--dry-run)
                DRY_RUN=true
                shift
                ;;
            -f|--force)
                FORCE=true
                shift
                ;;
            -v|--verbose)
                VERBOSE=true
                shift
                ;;
            --no-backup)
                BACKUP=false
                shift
                ;;
            --status)
                STATUS_ONLY=true
                shift
                ;;
            -h|--help)
                usage
                ;;
            --version)
                version
                ;;
            *)
                log_error "Unknown option: $1"
                echo "Use --help for usage information"
                exit 1
                ;;
        esac
    done
    
    # Default to both if neither specified
    if ! $ENABLE_SPAMASSASSIN && ! $ENABLE_TLS; then
        ENABLE_SPAMASSASSIN=true
        ENABLE_TLS=true
    fi
    
    # Check root (skip for dry-run or status-only)
    if ! $DRY_RUN && ! $STATUS_ONLY; then
        check_root
    fi
    
    check_miab
    
    # Show current status
    show_status
    
    # Exit if status-only mode
    if $STATUS_ONLY; then
        exit 0
    fi
    
    # Build action summary
    local actions=""
    if $ENABLE_SPAMASSASSIN; then
        actions+="SpamAssassin rules logging"
    fi
    if $ENABLE_TLS; then
        [[ -n "$actions" ]] && actions+=", "
        actions+="TLS cipher logging"
    fi
    
    if $DRY_RUN; then
        log_info "DRY RUN - showing changes that would be made for: $actions"
        echo ""
    else
        if ! confirm_action "Enable $actions?"; then
            log_info "Aborted"
            exit 0
        fi
        echo ""
    fi
    
    local exit_code=0
    
    if $ENABLE_SPAMASSASSIN; then
        if ! configure_spamassassin; then
            exit_code=1
        fi
        echo ""
    fi
    
    if $ENABLE_TLS; then
        if ! configure_tls; then
            exit_code=1
        fi
        echo ""
    fi
    
    if [[ $exit_code -eq 0 ]]; then
        if $DRY_RUN; then
            log_info "Dry run complete - no changes made"
        else
            log_ok "Configuration complete!"
            echo ""
            echo "Metrics should now be available after some mail traffic."
            echo "Run your postfix-metrics.sh script to verify."
        fi
    else
        log_error "Some configurations failed"
    fi
    
    exit $exit_code
}

main "$@"
