#!/bin/bash

# Email Deliverability Monitoring Script
#
# Monitors email deliverability health:
# - Blacklist checking (Spamhaus, SURBL, SpamCop, Barracuda)
# - DNS record verification (SPF/DKIM/DMARC)
# - Bounce rate monitoring (<5% threshold)
# - Email queue health (<100 jobs threshold)
# - Sends alert emails if critical issues detected
#
# Designed to run via cron (daily/weekly):
#   0 9 * * * /path/to/showprima/scripts/cron/email-deliverability-monitor.sh
#
# Usage:
#   ./scripts/cron/email-deliverability-monitor.sh
#
# Logs to: storage/logs/deliverability-monitor.log
#
# Story: 1.5 - Email Deliverability Testing & Monitoring
# Epic: 1 - Email System & Campaign Management

# Get script directory (scripts/cron/)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"

# Load atomic functions (from parent directory)
source "$SCRIPT_DIR/../_deploy-atoms.sh"

# Load database helper
source "$SCRIPT_DIR/../_db-helper.sh"

# ==============================================================================
# CONFIGURATION
# ==============================================================================

LOG_FILE="$PROJECT_ROOT/storage/logs/deliverability-monitor.log"
ALERT_TIMESTAMP_FILE="$PROJECT_ROOT/storage/logs/.last_deliverability_alert"

# Ensure log directory exists
mkdir -p "$PROJECT_ROOT/storage/logs"

# Get domain from .env
if [ -f "$PROJECT_ROOT/.env" ]; then
    MAIL_FROM_ADDRESS=$(grep "^MAIL_FROM_ADDRESS=" "$PROJECT_ROOT/.env" | cut -d= -f2-)
    DOMAIN=$(echo "$MAIL_FROM_ADDRESS" | cut -d@ -f2)

    # Get mail server IP (optional - for blacklist checking)
    MAIL_HOST=$(grep "^MAIL_HOST=" "$PROJECT_ROOT/.env" | cut -d= -f2-)
else
    log_error ".env file not found at $PROJECT_ROOT/.env" | tee -a "$LOG_FILE"
    exit 1
fi

# If domain not found, use default
if [ -z "$DOMAIN" ]; then
    DOMAIN="globalgalashow.com"
fi

# Thresholds
BOUNCE_RATE_THRESHOLD=5.0
QUEUE_SIZE_THRESHOLD=100
FAILED_JOBS_THRESHOLD=10
ALERT_COOLDOWN_HOURS=24

# Tracking
ISSUES_FOUND=0

# ==============================================================================
# LOGGING FUNCTIONS
# ==============================================================================

# Log to file with timestamp
log_to_file() {
    local level="$1"
    shift
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" >> "$LOG_FILE"
}

# Log info to file
log_monitor_info() {
    log_to_file "INFO" "$*"
}

# Log success to file
log_monitor_success() {
    log_to_file "SUCCESS" "$*"
}

# Log warning to file
log_monitor_warning() {
    log_to_file "WARNING" "$*"
    ((ISSUES_FOUND++))
}

# Log error to file
log_monitor_error() {
    log_to_file "ERROR" "$*"
    ((ISSUES_FOUND++))
}

# ==============================================================================
# ALERT FUNCTIONS
# ==============================================================================

# Check if alert was sent recently (prevent spam)
should_send_alert() {
    if [ ! -f "$ALERT_TIMESTAMP_FILE" ]; then
        return 0  # No previous alert, send it
    fi

    local last_alert=$(cat "$ALERT_TIMESTAMP_FILE")
    local current_time=$(date +%s)
    local cooldown_seconds=$((ALERT_COOLDOWN_HOURS * 3600))

    if [ $((current_time - last_alert)) -gt $cooldown_seconds ]; then
        return 0  # Cooldown expired, send alert
    else
        return 1  # Cooldown active, skip alert
    fi
}

# Update last alert timestamp
update_last_alert_timestamp() {
    date +%s > "$ALERT_TIMESTAMP_FILE"
}

# Send alert email (if configured and cooldown allows)
send_alert_email() {
    local subject="$1"
    local body="$2"

    if ! should_send_alert; then
        log_monitor_info "Alert cooldown active, skipping email alert"
        return 0
    fi

    # Only send if mail is configured (not in development)
    if [ "$MAIL_HOST" != "localhost" ] && [ "$MAIL_HOST" != "127.0.0.1" ] && [ "$MAIL_HOST" != "mailpit" ]; then
        # Send alert via Laravel artisan command
        cd "$PROJECT_ROOT"
        php artisan tinker --execute="
            try {
                Mail::to('admin@$DOMAIN')->send(new \\App\\Mail\\GenericTemplateMail(
                    '$subject',
                    '$body'
                ));
                echo 'Alert email sent successfully';
            } catch (Exception \$e) {
                echo 'Failed to send alert email: ' . \$e->getMessage();
            }
        " 2>&1 | tee -a "$LOG_FILE"

        update_last_alert_timestamp
        log_monitor_info "Alert email sent: $subject"
    else
        log_monitor_info "Alert would be sent: $subject (skipped - development environment)"
    fi
}

# ==============================================================================
# MONITORING FUNCTIONS
# ==============================================================================

# Check if domain is on any blacklists
check_blacklists() {
    log_monitor_info "Checking blacklists..."

    # Skip if MAIL_HOST is localhost/mailpit (development)
    if [ "$MAIL_HOST" == "localhost" ] || [ "$MAIL_HOST" == "127.0.0.1" ] || [ "$MAIL_HOST" == "mailpit" ]; then
        log_monitor_info "Blacklist check skipped (development environment)"
        return 0
    fi

    # Get mail server IP (if MAIL_HOST is an IP, use it directly)
    local mail_ip="$MAIL_HOST"

    # If MAIL_HOST is a hostname, resolve it to IP
    if ! echo "$mail_ip" | grep -qE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then
        mail_ip=$(dig +short "$MAIL_HOST" | head -n1)
    fi

    if [ -z "$mail_ip" ]; then
        log_monitor_warning "Could not resolve MAIL_HOST to IP address: $MAIL_HOST"
        return 1
    fi

    # Reverse IP for blacklist lookups
    local reversed_ip=$(echo "$mail_ip" | awk -F. '{print $4"."$3"."$2"."$1}')

    # Major blacklists to check
    local blacklists=(
        "zen.spamhaus.org"
        "bl.spamcop.net"
        "b.barracudacentral.org"
    )

    local blacklisted=false

    for bl in "${blacklists[@]}"; do
        local result=$(dig +short "$reversed_ip.$bl" 2>/dev/null)

        if [ -n "$result" ]; then
            log_monitor_error "BLACKLIST_DETECTED: IP $mail_ip listed on $bl (result: $result)"
            send_alert_email "Blacklist Alert" "Mail server IP $mail_ip is blacklisted on $bl. This will prevent emails from being delivered."
            blacklisted=true
        else
            log_monitor_info "BLACKLIST_CHECK_OK: IP $mail_ip clean on $bl"
        fi
    done

    if [ "$blacklisted" = false ]; then
        log_monitor_success "All blacklist checks passed"
    fi
}

# Verify DNS records still valid
verify_dns_records() {
    log_monitor_info "Verifying DNS records for $DOMAIN..."

    # Check SPF
    local spf_record=$(dig TXT "$DOMAIN" +short | grep "v=spf1")
    if [ -n "$spf_record" ]; then
        log_monitor_success "SPF record valid: $spf_record"
    else
        log_monitor_error "SPF record missing or invalid"
    fi

    # Check DKIM (common selector: default._domainkey)
    local dkim_record=$(dig TXT "default._domainkey.$DOMAIN" +short 2>/dev/null)
    if [ -n "$dkim_record" ]; then
        log_monitor_success "DKIM record valid: default._domainkey"
    else
        log_monitor_warning "DKIM record not found (may be handled by SMTP provider)"
    fi

    # Check DMARC
    local dmarc_record=$(dig TXT "_dmarc.$DOMAIN" +short)
    if [ -n "$dmarc_record" ]; then
        log_monitor_success "DMARC record valid: $dmarc_record"
    else
        log_monitor_error "DMARC record missing (required by Gmail/Yahoo)"
        send_alert_email "DMARC Missing" "DMARC record is missing for $DOMAIN. This is required by Gmail and Yahoo for bulk senders."
    fi
}

# Check bounce rate from database
check_bounce_rate() {
    log_monitor_info "Checking bounce rate (last 7 days)..."

    # Calculate bounce rate from account_setup_invitations table
    local bounce_data=$(db_query "
        SELECT
            COUNT(*) as total_sent,
            SUM(CASE WHEN bounce_type IS NOT NULL THEN 1 ELSE 0 END) as bounced,
            ROUND((SUM(CASE WHEN bounce_type IS NOT NULL THEN 1 ELSE 0 END) / COUNT(*)) * 100, 2) as bounce_rate
        FROM account_setup_invitations
        WHERE invitation_email_sent_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
        AND invitation_email_sent_at IS NOT NULL
    ")

    if [ -z "$bounce_data" ]; then
        log_monitor_info "No emails sent in last 7 days (bounce rate: N/A)"
        return 0
    fi

    local total_sent=$(echo "$bounce_data" | awk '{print $1}')
    local bounced=$(echo "$bounce_data" | awk '{print $2}')
    local bounce_rate=$(echo "$bounce_data" | awk '{print $3}')

    # Handle null bounce rate (if no emails sent)
    if [ "$bounce_rate" == "NULL" ] || [ -z "$bounce_rate" ]; then
        bounce_rate=0.00
    fi

    log_monitor_info "Emails sent (7d): $total_sent, Bounced: $bounced, Bounce rate: ${bounce_rate}%"

    # Check threshold
    if (( $(echo "$bounce_rate > $BOUNCE_RATE_THRESHOLD" | bc -l) )); then
        log_monitor_warning "BOUNCE_RATE_HIGH: ${bounce_rate}% (threshold: ${BOUNCE_RATE_THRESHOLD}%)"
        send_alert_email "High Bounce Rate Alert" "Bounce rate is ${bounce_rate}% (threshold: ${BOUNCE_RATE_THRESHOLD}%). Review email list quality and remove invalid addresses."
    else
        log_monitor_success "Bounce rate OK: ${bounce_rate}%"
    fi
}

# Check email queue health
check_queue_size() {
    log_monitor_info "Checking email queue health..."

    # Check pending jobs
    local pending=$(db_count "jobs" 2>/dev/null || echo "0")
    log_monitor_info "Pending jobs in queue: $pending"

    if [ "$pending" -gt "$QUEUE_SIZE_THRESHOLD" ]; then
        log_monitor_warning "QUEUE_SIZE_HIGH: $pending pending jobs (threshold: $QUEUE_SIZE_THRESHOLD)"
        send_alert_email "High Queue Size Alert" "Email queue has $pending pending jobs (threshold: $QUEUE_SIZE_THRESHOLD). Queue worker may be overloaded or stopped."
    else
        log_monitor_success "Queue size OK: $pending jobs"
    fi

    # Check failed jobs (last 24 hours)
    local failed=$(db_query "
        SELECT COUNT(*)
        FROM failed_jobs
        WHERE failed_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
    " 2>/dev/null || echo "0")

    log_monitor_info "Failed jobs (24h): $failed"

    if [ "$failed" -gt "$FAILED_JOBS_THRESHOLD" ]; then
        log_monitor_error "FAILED_JOBS_HIGH: $failed failed jobs in 24h (threshold: $FAILED_JOBS_THRESHOLD)"
        send_alert_email "Failed Jobs Alert" "$failed email jobs failed in the last 24 hours (threshold: $FAILED_JOBS_THRESHOLD). Review error logs."
    else
        log_monitor_success "Failed jobs OK: $failed in 24h"
    fi

    # Check if queue worker is running (optional - may not apply on all systems)
    if pgrep -f "queue:work" > /dev/null; then
        log_monitor_success "Queue worker is running"
    else
        log_monitor_warning "Queue worker may not be running (check process list)"
    fi
}

# ==============================================================================
# MAIN EXECUTION
# ==============================================================================

main() {
    log_monitor_info "=========================================="
    log_monitor_info "Email Deliverability Monitor - Starting"
    log_monitor_info "Domain: $DOMAIN"
    log_monitor_info "=========================================="

    # Run all checks
    check_blacklists
    verify_dns_records
    check_bounce_rate
    check_queue_size

    # Summary
    log_monitor_info "=========================================="
    if [ $ISSUES_FOUND -eq 0 ]; then
        log_monitor_success "Monitoring complete - No issues found"
    else
        log_monitor_warning "Monitoring complete - $ISSUES_FOUND issue(s) found (see log above)"
    fi
    log_monitor_info "=========================================="

    # Always exit 0 (monitoring scripts don't fail the system)
    exit 0
}

# Run main function
main "$@"
