#!/bin/bash
# Desk-Moloni v3.0 Cron Job Setup Script
# 
# Sets up automated cron jobs for queue processing and maintenance tasks.
# Handles different environments and user permissions.

set -euo pipefail

# Script configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MODULE_DIR="$(dirname "$SCRIPT_DIR")"
CLI_DIR="$MODULE_DIR/cli"
LOG_DIR="$MODULE_DIR/logs"
LOCK_DIR="$MODULE_DIR/locks"

# Default configuration
DEFAULT_QUEUE_INTERVAL="*/1"  # Every minute
DEFAULT_MAINTENANCE_HOUR="2"  # 2 AM
DEFAULT_LOG_RETENTION_DAYS="30"
DEFAULT_USER=""

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

# Logging functions
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

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

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

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

# Help function
show_help() {
    cat << EOF
Desk-Moloni v3.0 Cron Setup Script

Usage: $0 [OPTIONS]

Options:
    -h, --help                  Show this help message
    -u, --user USER            User to run cron jobs as (default: current user)
    -i, --interval INTERVAL    Queue processor interval (default: */1 for every minute)
    -m, --maintenance HOUR     Maintenance hour (default: 2 for 2 AM)
    -r, --retention DAYS       Log retention days (default: 30)
    -d, --dry-run             Show what would be done without making changes
    -v, --verbose             Verbose output
    --uninstall               Remove all cron jobs
    --status                  Show current cron job status

Examples:
    $0                        # Setup with defaults
    $0 -u www-data -i "*/5"   # Run as www-data every 5 minutes
    $0 --dry-run              # Preview changes
    $0 --uninstall            # Remove all cron jobs
    $0 --status               # Show current status

Cron Jobs Created:
    1. Queue Processor: Processes synchronization queue
    2. Daily Maintenance: Cleanup logs, update mappings
    3. Health Check: Monitor system health
    4. Token Refresh: Refresh OAuth tokens

EOF
}

# Parse command line arguments
QUEUE_INTERVAL="$DEFAULT_QUEUE_INTERVAL"
MAINTENANCE_HOUR="$DEFAULT_MAINTENANCE_HOUR"
LOG_RETENTION_DAYS="$DEFAULT_LOG_RETENTION_DAYS"
CRON_USER="$DEFAULT_USER"
DRY_RUN=false
VERBOSE=false
UNINSTALL=false
SHOW_STATUS=false

while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_help
            exit 0
            ;;
        -u|--user)
            CRON_USER="$2"
            shift 2
            ;;
        -i|--interval)
            QUEUE_INTERVAL="$2"
            shift 2
            ;;
        -m|--maintenance)
            MAINTENANCE_HOUR="$2"
            shift 2
            ;;
        -r|--retention)
            LOG_RETENTION_DAYS="$2"
            shift 2
            ;;
        -d|--dry-run)
            DRY_RUN=true
            shift
            ;;
        -v|--verbose)
            VERBOSE=true
            shift
            ;;
        --uninstall)
            UNINSTALL=true
            shift
            ;;
        --status)
            SHOW_STATUS=true
            shift
            ;;
        *)
            log_error "Unknown option: $1"
            show_help
            exit 1
            ;;
    esac
done

# Set default user to current user if not specified
if [[ -z "$CRON_USER" ]]; then
    CRON_USER=$(whoami)
fi

# Validate user exists
if ! id "$CRON_USER" &>/dev/null; then
    log_error "User '$CRON_USER' does not exist"
    exit 1
fi

# Check if running as root or target user
CURRENT_USER=$(whoami)
if [[ "$CURRENT_USER" != "root" && "$CURRENT_USER" != "$CRON_USER" ]]; then
    log_error "Must run as root or target user ($CRON_USER)"
    exit 1
fi

# Validate maintenance hour
if [[ ! "$MAINTENANCE_HOUR" =~ ^[0-9]+$ ]] || [[ "$MAINTENANCE_HOUR" -lt 0 ]] || [[ "$MAINTENANCE_HOUR" -gt 23 ]]; then
    log_error "Invalid maintenance hour: $MAINTENANCE_HOUR (must be 0-23)"
    exit 1
fi

# Create required directories
create_directories() {
    local dirs=("$LOG_DIR" "$LOCK_DIR")
    
    for dir in "${dirs[@]}"; do
        if [[ ! -d "$dir" ]]; then
            if [[ "$DRY_RUN" == true ]]; then
                log_info "Would create directory: $dir"
            else
                mkdir -p "$dir"
                chown "$CRON_USER:$CRON_USER" "$dir" 2>/dev/null || true
                log_success "Created directory: $dir"
            fi
        fi
    done
}

# Generate cron job entries
generate_cron_jobs() {
    cat << EOF
# Desk-Moloni v3.0 Cron Jobs
# Generated on $(date)
# User: $CRON_USER

# Queue Processor - Process synchronization queue
$QUEUE_INTERVAL * * * * /usr/bin/flock -n $LOCK_DIR/queue_processor.lock php $CLI_DIR/queue_processor.php >> $LOG_DIR/queue_processor.log 2>&1

# Daily Maintenance - Cleanup and optimization
0 $MAINTENANCE_HOUR * * * /usr/bin/flock -n $LOCK_DIR/maintenance.lock $SCRIPT_DIR/maintenance.sh >> $LOG_DIR/maintenance.log 2>&1

# Health Check - System monitoring
*/15 * * * * /usr/bin/flock -n $LOCK_DIR/health_check.lock php $CLI_DIR/sync_commands.php health >> $LOG_DIR/health_check.log 2>&1

# Token Refresh - OAuth token maintenance
0 */6 * * * /usr/bin/flock -n $LOCK_DIR/token_refresh.lock $SCRIPT_DIR/token_refresh.sh >> $LOG_DIR/token_refresh.log 2>&1

# Log Rotation - Cleanup old logs
0 1 * * 0 /usr/bin/find $LOG_DIR -name "*.log" -mtime +$LOG_RETENTION_DAYS -delete

EOF
}

# Get current cron jobs for the user
get_current_crontab() {
    if [[ "$CURRENT_USER" == "root" ]]; then
        crontab -u "$CRON_USER" -l 2>/dev/null || true
    else
        crontab -l 2>/dev/null || true
    fi
}

# Remove existing Desk-Moloni cron jobs
remove_existing_jobs() {
    local current_crontab
    current_crontab=$(get_current_crontab)
    
    if [[ -n "$current_crontab" ]]; then
        # Remove lines between Desk-Moloni markers
        local new_crontab
        new_crontab=$(echo "$current_crontab" | sed '/# Desk-Moloni v3.0 Cron Jobs/,/^$/d')
        
        if [[ "$DRY_RUN" == true ]]; then
            log_info "Would remove existing Desk-Moloni cron jobs"
        else
            if [[ "$CURRENT_USER" == "root" ]]; then
                echo "$new_crontab" | crontab -u "$CRON_USER" -
            else
                echo "$new_crontab" | crontab -
            fi
            log_success "Removed existing Desk-Moloni cron jobs"
        fi
        
        return 0
    fi
    
    return 1
}

# Install cron jobs
install_cron_jobs() {
    local current_crontab new_crontab cron_jobs
    current_crontab=$(get_current_crontab)
    cron_jobs=$(generate_cron_jobs)
    
    # Combine existing crontab with new jobs
    if [[ -n "$current_crontab" ]]; then
        new_crontab="$current_crontab"$'\n'"$cron_jobs"
    else
        new_crontab="$cron_jobs"
    fi
    
    if [[ "$DRY_RUN" == true ]]; then
        log_info "Would install the following cron jobs:"
        echo "$cron_jobs"
    else
        if [[ "$CURRENT_USER" == "root" ]]; then
            echo "$new_crontab" | crontab -u "$CRON_USER" -
        else
            echo "$new_crontab" | crontab -
        fi
        log_success "Installed Desk-Moloni cron jobs for user: $CRON_USER"
    fi
}

# Show current status
show_status() {
    log_info "Desk-Moloni Cron Job Status"
    echo "================================"
    
    local current_crontab
    current_crontab=$(get_current_crontab)
    
    if [[ -n "$current_crontab" ]]; then
        local desk_moloni_jobs
        desk_moloni_jobs=$(echo "$current_crontab" | sed -n '/# Desk-Moloni v3.0 Cron Jobs/,/^$/p')
        
        if [[ -n "$desk_moloni_jobs" ]]; then
            log_success "Desk-Moloni cron jobs are installed for user: $CRON_USER"
            echo "$desk_moloni_jobs"
        else
            log_warning "No Desk-Moloni cron jobs found for user: $CRON_USER"
        fi
    else
        log_warning "No crontab found for user: $CRON_USER"
    fi
    
    # Check if cron daemon is running
    if systemctl is-active --quiet cron 2>/dev/null || systemctl is-active --quiet crond 2>/dev/null; then
        log_success "Cron daemon is running"
    else
        log_warning "Cron daemon may not be running"
    fi
    
    # Check log files
    echo -e "\nLog Files Status:"
    for log_file in "queue_processor.log" "maintenance.log" "health_check.log" "token_refresh.log"; do
        local log_path="$LOG_DIR/$log_file"
        if [[ -f "$log_path" ]]; then
            local size=$(du -h "$log_path" | cut -f1)
            local modified=$(stat -c %y "$log_path" 2>/dev/null | cut -d' ' -f1,2 | cut -d'.' -f1)
            log_info "$log_file: $size (modified: $modified)"
        else
            log_warning "$log_file: Not found"
        fi
    done
    
    # Check lock files
    echo -e "\nActive Processes:"
    for lock_file in "$LOCK_DIR"/*.lock; do
        if [[ -f "$lock_file" ]]; then
            local lock_name=$(basename "$lock_file" .lock)
            log_warning "$lock_name: Process may be running (lock file exists)"
        fi
    done
}

# Validate PHP and dependencies
validate_dependencies() {
    log_info "Validating dependencies..."
    
    # Check PHP
    if ! command -v php &> /dev/null; then
        log_error "PHP is not installed or not in PATH"
        exit 1
    fi
    
    local php_version
    php_version=$(php -r "echo PHP_VERSION;" 2>/dev/null)
    log_success "PHP version: $php_version"
    
    # Check flock
    if ! command -v flock &> /dev/null; then
        log_error "flock is not installed (required for preventing concurrent execution)"
        exit 1
    fi
    
    # Check CLI files exist
    local cli_files=("$CLI_DIR/queue_processor.php" "$CLI_DIR/sync_commands.php")
    for cli_file in "${cli_files[@]}"; do
        if [[ ! -f "$cli_file" ]]; then
            log_error "CLI file not found: $cli_file"
            exit 1
        fi
    done
    
    log_success "All dependencies validated"
}

# Test cron job syntax
test_cron_syntax() {
    log_info "Testing cron job syntax..."
    
    local cron_jobs
    cron_jobs=$(generate_cron_jobs)
    
    # Basic validation of cron expressions
    while IFS= read -r line; do
        if [[ "$line" =~ ^[^#].* ]]; then
            local cron_expr
            cron_expr=$(echo "$line" | cut -d' ' -f1-5)
            
            # Very basic validation - just check field count
            local field_count
            field_count=$(echo "$cron_expr" | wc -w)
            
            if [[ "$field_count" -ne 5 ]]; then
                log_error "Invalid cron expression: $cron_expr"
                exit 1
            fi
        fi
    done <<< "$cron_jobs"
    
    log_success "Cron job syntax validated"
}

# Main execution
main() {
    log_info "Desk-Moloni v3.0 Cron Setup"
    log_info "User: $CRON_USER"
    log_info "Queue Interval: $QUEUE_INTERVAL"
    log_info "Maintenance Hour: $MAINTENANCE_HOUR"
    
    if [[ "$DRY_RUN" == true ]]; then
        log_warning "DRY RUN MODE - No changes will be made"
    fi
    
    if [[ "$SHOW_STATUS" == true ]]; then
        show_status
        exit 0
    fi
    
    if [[ "$UNINSTALL" == true ]]; then
        log_info "Uninstalling Desk-Moloni cron jobs..."
        if remove_existing_jobs; then
            log_success "Cron jobs removed successfully"
        else
            log_warning "No existing cron jobs found"
        fi
        exit 0
    fi
    
    # Installation process
    validate_dependencies
    test_cron_syntax
    create_directories
    
    # Remove existing jobs first
    remove_existing_jobs || true
    
    # Install new jobs
    install_cron_jobs
    
    if [[ "$DRY_RUN" == false ]]; then
        log_info ""
        log_success "Cron jobs have been installed successfully!"
        log_info "Monitor logs in: $LOG_DIR"
        log_info "Check status with: $0 --status"
        log_info ""
        log_info "Next steps:"
        log_info "1. Verify cron daemon is running: systemctl status cron"
        log_info "2. Monitor queue processor: tail -f $LOG_DIR/queue_processor.log"
        log_info "3. Check health status: php $CLI_DIR/sync_commands.php health"
    fi
}

# Run main function
main "$@"