#!/bin/bash

# SSL Certificate Renewal Cron Job for WHP
# This script automatically renews SSL certificates that are due for renewal
# It should be run via cron to ensure certificates are renewed before expiry

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Function to print colored output
print_status() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

print_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Function to log messages
log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> /var/log/ssl-renewal.log
}

# Function to send notification (email or webhook)
send_notification() {
    local subject="$1"
    local message="$2"
    
    # Log the notification
    log_message "NOTIFICATION: $subject - $message"
    
    # TODO: Add email notification or webhook here
    # Example: mail -s "$subject" admin@example.com <<< "$message"
}

# Function to get MySQL credentials
get_mysql_credentials() {
    if [ -f "/root/.my.cnf" ]; then
        MYSQL_HOST=$(grep '^host=' /root/.my.cnf | cut -d'=' -f2-)
        MYSQL_USER=$(grep '^user=' /root/.my.cnf | cut -d'=' -f2-)
        MYSQL_PASSWORD=$(grep '^password=' /root/.my.cnf | cut -d'=' -f2-)
    else
        print_error "MySQL configuration file not found at /root/.my.cnf"
        exit 1
    fi
}

# Function to check if a certificate needs renewal
check_certificate_renewal() {
    local domain="$1"
    local last_renewal="$2"
    
    # Convert last renewal date to timestamp
    local last_renewal_timestamp=$(date -d "$last_renewal" +%s 2>/dev/null || echo 0)
    local current_timestamp=$(date +%s)
    
    # Calculate days since last renewal
    local days_since_renewal=$(( (current_timestamp - last_renewal_timestamp) / 86400 ))
    
    # Let's Encrypt certificates are valid for 90 days, renew at 60 days
    if [ $days_since_renewal -ge 60 ]; then
        return 0  # Needs renewal
    else
        return 1  # Does not need renewal
    fi
}

# Function to renew SSL certificate via WHP SSL Manager
renew_certificate() {
    local domain="$1"
    local site_id="$2"
    
    print_status "Renewing SSL certificate for domain: $domain"
    
    # Create temporary PHP script to renew certificate
    cat > /tmp/renew_ssl.php << 'EOF'
<?php
require_once('/docker/whp/web/configs/config.php');
require_once('/docker/whp/web/libs/ssl_manager.php');

$domain = $argv[1];
$site_id = $argv[2];

try {
    $ssl_manager = new ssl_manager();
    $result = $ssl_manager->renew_ssl($site_id);
    
    if ($result['success']) {
        echo "SUCCESS: SSL certificate renewed for domain: $domain\n";
        exit(0);
    } else {
        echo "ERROR: Failed to renew SSL certificate for domain: $domain - " . $result['error'] . "\n";
        exit(1);
    }
} catch (Exception $e) {
    echo "ERROR: Exception renewing SSL certificate for domain: $domain - " . $e->getMessage() . "\n";
    exit(1);
}
EOF

    # Execute the PHP script
    php /tmp/renew_ssl.php "$domain" "$site_id"
    local exit_code=$?
    
    # Clean up temporary file
    rm -f /tmp/renew_ssl.php
    
    return $exit_code
}

# Function to get sites with SSL certificates that need renewal
get_sites_for_renewal() {
    # Create temporary PHP script to get sites needing renewal
    cat > /tmp/get_renewal_sites.php << 'EOF'
<?php
require_once('/docker/whp/web/configs/config.php');
require_once('/docker/whp/web/libs/ssl_manager.php');

try {
    $ssl_manager = new ssl_manager();
    $domains = $ssl_manager->get_certificates_for_renewal(30); // 30 days before expiry
    
    if (empty($domains)) {
        exit(0);
    }
    
    // Output domains that need renewal
    foreach ($domains as $domain) {
        echo "$domain\n";
    }
    
    exit(0);
} catch (Exception $e) {
    echo "ERROR: " . $e->getMessage() . "\n";
    exit(1);
}
EOF

    # Execute the PHP script and capture output
    php /tmp/get_renewal_sites.php 2>&1
    local exit_code=$?
    
    # Clean up temporary file
    rm -f /tmp/get_renewal_sites.php
    
    return $exit_code
}

# Function to get site ID for a domain
get_site_id_for_domain() {
    local domain="$1"
    
    # Query database to get site ID for domain
    mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" -se "
        SELECT s.id 
        FROM whp.sites s 
        JOIN whp.site_domains sd ON s.id = sd.site_id 
        JOIN whp.domains d ON sd.domain_id = d.id 
        WHERE d.domain_name = '$domain' 
        LIMIT 1
    " 2>/dev/null
}

# Function to update renewal statistics
update_renewal_stats() {
    local total_domains="$1"
    local successful_renewals="$2"
    local failed_renewals="$3"
    
    # Create temporary PHP script to update renewal stats
    cat > /tmp/update_stats.php << 'EOF'
<?php
require_once('/docker/whp/web/configs/config.php');
require_once('/docker/whp/web/libs/mysqlmgmt.php');

$total = $argv[1];
$successful = $argv[2];
$failed = $argv[3];

try {
    $MySQLMgmt = new mysqlmgmt();
    $db = $MySQLMgmt->getMySQLConnection();
    
    // Insert renewal statistics
    $stmt = $db->prepare("
        INSERT INTO whp.ssl_renewal_log 
        (domain_name, renewal_status, error_message, renewal_date) 
        VALUES (?, ?, ?, NOW())
    ");
    
    $message = "Renewal batch completed: $successful successful, $failed failed out of $total total domains";
    $stmt->execute(['system', $failed > 0 ? 'failed' : 'success', $message]);
    
    echo "Statistics updated successfully\n";
} catch (Exception $e) {
    echo "ERROR: Failed to update statistics - " . $e->getMessage() . "\n";
}
EOF

    php /tmp/update_stats.php "$total_domains" "$successful_renewals" "$failed_renewals"
    rm -f /tmp/update_stats.php
}

# Main renewal function
main() {
    print_status "Starting SSL certificate renewal process"
    log_message "SSL renewal cron job started"
    
    # Get MySQL credentials
    get_mysql_credentials
    
    # Get domains that need renewal
    print_status "Checking for certificates that need renewal..."
    domains_output=$(get_sites_for_renewal)
    
    if [ $? -ne 0 ]; then
        print_error "Failed to get domains for renewal: $domains_output"
        log_message "ERROR: Failed to get domains for renewal"
        exit 1
    fi
    
    # Convert output to array
    readarray -t domains_to_renew <<< "$domains_output"
    
    # Remove empty elements
    domains_to_renew=($(printf '%s\n' "${domains_to_renew[@]}" | grep -v '^$'))
    
    if [ ${#domains_to_renew[@]} -eq 0 ]; then
        print_success "No certificates need renewal at this time"
        log_message "No certificates need renewal"
        exit 0
    fi
    
    print_status "Found ${#domains_to_renew[@]} certificate(s) that need renewal"
    log_message "Found ${#domains_to_renew[@]} certificates for renewal"
    
    # Renew each certificate
    local successful_renewals=0
    local failed_renewals=0
    local renewal_errors=()
    
    for domain in "${domains_to_renew[@]}"; do
        if [ -z "$domain" ]; then
            continue
        fi
        
        print_status "Processing domain: $domain"
        
        # Get site ID for domain
        site_id=$(get_site_id_for_domain "$domain")
        
        if [ -z "$site_id" ]; then
            print_error "Could not find site ID for domain: $domain"
            log_message "ERROR: Could not find site ID for domain: $domain"
            failed_renewals=$((failed_renewals + 1))
            renewal_errors+=("$domain: Site ID not found")
            continue
        fi
        
        # Attempt renewal
        if renew_certificate "$domain" "$site_id"; then
            print_success "Successfully renewed certificate for: $domain"
            log_message "SUCCESS: Renewed certificate for domain: $domain"
            successful_renewals=$((successful_renewals + 1))
        else
            print_error "Failed to renew certificate for: $domain"
            log_message "ERROR: Failed to renew certificate for domain: $domain"
            failed_renewals=$((failed_renewals + 1))
            renewal_errors+=("$domain: Renewal failed")
        fi
        
        # Small delay between renewals to avoid rate limiting
        sleep 5
    done
    
    # Update renewal statistics
    update_renewal_stats ${#domains_to_renew[@]} $successful_renewals $failed_renewals
    
    # Generate summary
    print_status "Renewal Summary:"
    print_status "  Total domains processed: ${#domains_to_renew[@]}"
    print_success "  Successful renewals: $successful_renewals"
    
    if [ $failed_renewals -gt 0 ]; then
        print_error "  Failed renewals: $failed_renewals"
        
        # Send notification about failures
        local error_message="SSL certificate renewal failures:\n"
        for error in "${renewal_errors[@]}"; do
            error_message="$error_message- $error\n"
        done
        
        send_notification "SSL Certificate Renewal Failures" "$error_message"
    fi
    
    log_message "SSL renewal cron job completed: $successful_renewals successful, $failed_renewals failed"
    
    if [ $failed_renewals -eq 0 ]; then
        print_success "All SSL certificate renewals completed successfully"
        exit 0
    else
        print_warning "SSL certificate renewal completed with some failures"
        exit 1
    fi
}

# Help function
show_help() {
    echo "SSL Certificate Renewal Cron Job for WHP"
    echo ""
    echo "Usage: $0 [OPTIONS]"
    echo ""
    echo "Options:"
    echo "  --help          Show this help message"
    echo "  --test          Run in test mode (show what would be renewed)"
    echo "  --force         Force renewal of all SSL certificates"
    echo "  --domain <name> Renew certificate for specific domain only"
    echo ""
    echo "Examples:"
    echo "  $0                       # Run normal renewal check"
    echo "  $0 --test               # Test mode (dry run)"
    echo "  $0 --domain example.com # Renew specific domain"
    echo ""
    echo "This script should be run via cron to automatically renew SSL certificates."
    echo "Recommended cron entry (daily at 2 AM):"
    echo "0 2 * * * /root/whp/scripts/ssl-renewal-cron.sh >> /var/log/ssl-renewal.log 2>&1"
}

# Handle command line arguments
case "${1:-run}" in
    "--help"|"help")
        show_help
        exit 0
        ;;
    "--test"|"test")
        echo "TEST MODE: Would check the following domains for renewal:"
        get_sites_for_renewal
        exit 0
        ;;
    "--force"|"force")
        # TODO: Implement force renewal
        echo "Force renewal not yet implemented"
        exit 1
        ;;
    "--domain")
        if [ -z "$2" ]; then
            echo "Error: Domain name required"
            exit 1
        fi
        # TODO: Implement single domain renewal
        echo "Single domain renewal not yet implemented"
        exit 1
        ;;
    "run"|*)
        main
        ;;
esac 