#!/usr/bin/env bash

# WHP Security IP Manager - CLI tool for managing IP exemption and block lists
# This script provides runtime management of IP blocking and exemption lists

set -euo pipefail

# Script configuration
SCRIPT_NAME="security-ip-manager"
LOG_FILE="/var/log/whp-security.log"

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

# Function to display usage
show_usage() {
    cat << EOF
WHP Security IP Manager

Usage: $0 [COMMAND] [OPTIONS]

COMMANDS:
  block <IP>              Block an IP address from all services
  unblock <IP>            Remove IP address from block lists
  block-ssh <IP>          Block IP from SSH service only
  unblock-ssh <IP>        Remove IP from SSH block list
  block-ftp <IP>          Block IP from FTP service only
  unblock-ftp <IP>        Remove IP from FTP block list
  exempt <IP> [DESC]      Add IP to exemption list (never blocked)
  unexempt <IP>           Remove IP from exemption list
  list-blocked            Show all currently blocked IPs
  list-exempted           Show all exempted IPs
  status <IP>             Check status of specific IP
  stats                   Show blocking statistics
  cleanup                 Remove expired blocks and old data

OPTIONS:
  -h, --help             Show this help message
  -v, --verbose          Verbose output
  -f, --force            Force operation without confirmation

EXAMPLES:
  $0 block 192.168.1.100
  $0 exempt 192.168.1.50 "Office IP"
  $0 status 192.168.1.100
  $0 list-blocked
  $0 cleanup

EOF
}

# Function to validate IP address
validate_ip() {
    local ip="$1"
    if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        echo "ERROR: Invalid IP address format: $ip" >&2
        exit 1
    fi
    
    # Additional validation for each octet
    IFS='.' read -ra ADDR <<< "$ip"
    for i in "${ADDR[@]}"; do
        if [[ $i -lt 0 || $i -gt 255 ]]; then
            echo "ERROR: Invalid IP address: $ip" >&2
            exit 1
        fi
    done
}

# Function to run PHP script with log monitor manager
run_php_command() {
    local php_script
    php_script=$(mktemp -t security_manager.XXXXXX)
    chmod 600 "$php_script"
    
    cat > "$php_script" << EOF
<?php
chdir('/docker/whp/web');
require_once('/docker/whp/web/libs/log_monitor_manager.php');
require_once('/docker/whp/web/libs/security_manager.php');

try {
    \$monitor = new log_monitor_manager();
    \$security = new security_manager();
    
    $1
    
} catch (Exception \$e) {
    echo "ERROR: " . \$e->getMessage() . "\\n";
    exit(1);
}
?>
EOF
    
    php "$php_script" 2>&1
    local exit_code=$?
    rm -f "$php_script"
    return $exit_code
}

# Function to block IP from all services
block_ip() {
    local ip="$1"
    validate_ip "$ip"
    
    echo "Blocking IP $ip from all services..."
    log_message "Blocking IP $ip from all services"
    
    local php_code="
    // Block via security manager (web)
    \$result1 = \$security->block_ip('$ip', 'Manual CLI block');
    
    // Block via service-level blocking (SSH/FTP)
    \$result2 = \$monitor->block_service_ip('ssh', '$ip', 'Manual CLI block');
    \$result3 = \$monitor->block_service_ip('ftp', '$ip', 'Manual CLI block');
    
    if (\$result1 && \$result2 && \$result3) {
        echo \"IP $ip blocked successfully from all services\\n\";
    } else {
        echo \"WARNING: Some services may not have been blocked properly\\n\";
    }
    "
    
    if run_php_command "$php_code"; then
        echo "✓ IP $ip blocked from all services"
        log_message "Successfully blocked IP $ip from all services"
    else
        echo "✗ Failed to block IP $ip"
        log_message "Failed to block IP $ip"
        exit 1
    fi
}

# Function to unblock IP from all services
unblock_ip() {
    local ip="$1"
    validate_ip "$ip"
    
    echo "Unblocking IP $ip from all services..."
    log_message "Unblocking IP $ip from all services"
    
    local php_code="
    // Unblock via security manager (web)
    \$result1 = \$security->unblock_ip('$ip');
    
    // Unblock via service-level blocking (SSH/FTP)
    \$result2 = \$monitor->unblock_service_ip('ssh', '$ip');
    \$result3 = \$monitor->unblock_service_ip('ftp', '$ip');
    
    if (\$result1 && \$result2 && \$result3) {
        echo \"IP $ip unblocked successfully from all services\\n\";
    } else {
        echo \"WARNING: Some services may not have been unblocked properly\\n\";
    }
    "
    
    if run_php_command "$php_code"; then
        echo "✓ IP $ip unblocked from all services"
        log_message "Successfully unblocked IP $ip from all services"
    else
        echo "✗ Failed to unblock IP $ip"
        log_message "Failed to unblock IP $ip"
        exit 1
    fi
}

# Function to block IP from specific service
block_service_ip() {
    local service="$1"
    local ip="$2"
    validate_ip "$ip"
    
    echo "Blocking IP $ip from $service service..."
    log_message "Blocking IP $ip from $service service"
    
    local php_code="
    \$result = \$monitor->block_service_ip('$service', '$ip', 'Manual CLI block');
    
    if (\$result) {
        echo \"IP $ip blocked successfully from $service service\\n\";
    } else {
        echo \"Failed to block IP $ip from $service service\\n\";
        exit(1);
    }
    "
    
    if run_php_command "$php_code"; then
        echo "✓ IP $ip blocked from $service service"
        log_message "Successfully blocked IP $ip from $service service"
    else
        echo "✗ Failed to block IP $ip from $service service"
        log_message "Failed to block IP $ip from $service service"
        exit 1
    fi
}

# Function to unblock IP from specific service
unblock_service_ip() {
    local service="$1"
    local ip="$2"
    validate_ip "$ip"
    
    echo "Unblocking IP $ip from $service service..."
    log_message "Unblocking IP $ip from $service service"
    
    local php_code="
    \$result = \$monitor->unblock_service_ip('$service', '$ip');
    
    if (\$result) {
        echo \"IP $ip unblocked successfully from $service service\\n\";
    } else {
        echo \"Failed to unblock IP $ip from $service service\\n\";
        exit(1);
    }
    "
    
    if run_php_command "$php_code"; then
        echo "✓ IP $ip unblocked from $service service"
        log_message "Successfully unblocked IP $ip from $service service"
    else
        echo "✗ Failed to unblock IP $ip from $service service"
        log_message "Failed to unblock IP $ip from $service service"
        exit 1
    fi
}

# Function to add IP to exemption list
exempt_ip() {
    local ip="$1"
    local description="${2:-Manual CLI exemption}"
    validate_ip "$ip"
    
    echo "Adding IP $ip to exemption list..."
    log_message "Adding IP $ip to exemption list: $description"
    
    local php_code="
    \$result = \$security->add_exemption_ip('$ip', '$description');
    
    if (\$result) {
        echo \"IP $ip added to exemption list\\n\";
    } else {
        echo \"Failed to add IP $ip to exemption list\\n\";
        exit(1);
    }
    "
    
    if run_php_command "$php_code"; then
        echo "✓ IP $ip added to exemption list"
        log_message "Successfully added IP $ip to exemption list"
    else
        echo "✗ Failed to add IP $ip to exemption list"
        log_message "Failed to add IP $ip to exemption list"
        exit 1
    fi
}

# Function to remove IP from exemption list
unexempt_ip() {
    local ip="$1"
    validate_ip "$ip"
    
    echo "Removing IP $ip from exemption list..."
    log_message "Removing IP $ip from exemption list"
    
    local php_code="
    \$result = \$security->remove_exemption_ip('$ip');
    
    if (\$result) {
        echo \"IP $ip removed from exemption list\\n\";
    } else {
        echo \"Failed to remove IP $ip from exemption list\\n\";
        exit(1);
    }
    "
    
    if run_php_command "$php_code"; then
        echo "✓ IP $ip removed from exemption list"
        log_message "Successfully removed IP $ip from exemption list"
    else
        echo "✗ Failed to remove IP $ip from exemption list"
        log_message "Failed to remove IP $ip from exemption list"
        exit 1
    fi
}

# Function to list blocked IPs
list_blocked() {
    echo "Currently Blocked IPs:"
    echo "====================="
    
    local php_code="
    // Get web blocked IPs
    \$web_blocked = \$security->get_blocked_ips();
    
    // Get service blocked IPs
    \$service_blocked = \$monitor->get_service_blocked_ips();
    
    echo \"Web Service Blocked IPs:\\n\";
    if (empty(\$web_blocked)) {
        echo \"  None\\n\";
    } else {
        foreach (\$web_blocked as \$block) {
            \$time_left = \$block['unblock_time'] - time();
            \$hours = floor(\$time_left / 3600);
            \$minutes = floor((\$time_left % 3600) / 60);
            echo \"  \" . \$block['ip_address'] . \" - \" . \$block['reason'] . \" (expires in {$hours}h {$minutes}m)\\n\";
        }
    }
    
    echo \"\\nSSH/FTP Service Blocked IPs:\\n\";
    if (empty(\$service_blocked)) {
        echo \"  None\\n\";
    } else {
        foreach (\$service_blocked as \$block) {
            \$time_left = \$block['unblock_time'] - time();
            \$hours = floor(\$time_left / 3600);
            \$minutes = floor((\$time_left % 3600) / 60);
            echo \"  \" . \$block['ip_address'] . \" (\" . \$block['service_type'] . \") - \" . \$block['reason'] . \" (expires in {$hours}h {$minutes}m)\\n\";
        }
    }
    "
    
    run_php_command "$php_code"
}

# Function to list exempted IPs
list_exempted() {
    echo "Exempted IPs (Never Blocked):"
    echo "============================="
    
    local php_code="
    \$exempted = \$security->get_exemption_ips();
    
    if (empty(\$exempted)) {
        echo \"None\\n\";
    } else {
        foreach (\$exempted as \$exempt) {
            echo \"  \" . \$exempt['ip_address'] . \" - \" . \$exempt['description'] . \"\\n\";
        }
    }
    "
    
    run_php_command "$php_code"
}

# Function to check IP status
check_ip_status() {
    local ip="$1"
    validate_ip "$ip"
    
    echo "IP Status for $ip:"
    echo "=================="
    
    local php_code="
    // Check if exempted
    if (\$security->is_ip_exempted('$ip')) {
        echo \"Status: EXEMPTED (never blocked)\\n\";
        \$exempted = \$security->get_exemption_ips();
        foreach (\$exempted as \$exempt) {
            if (\$exempt['ip_address'] === '$ip') {
                echo \"Description: \" . \$exempt['description'] . \"\\n\";
                break;
            }
        }
    } else {
        // Check if web blocked
        \$web_blocked = \$security->is_ip_blocked('$ip');
        if (\$web_blocked) {
            echo \"Status: BLOCKED (web service)\\n\";
            echo \"Reason: \" . \$web_blocked['reason'] . \"\\n\";
            \$time_left = \$web_blocked['unblock_time'] - time();
            \$hours = floor(\$time_left / 3600);
            \$minutes = floor((\$time_left % 3600) / 60);
            echo \"Expires: {$hours}h {$minutes}m\\n\";
        }
        
        // Check service blocks
        \$ssh_blocked = \$monitor->is_service_ip_blocked('ssh', '$ip');
        \$ftp_blocked = \$monitor->is_service_ip_blocked('ftp', '$ip');
        
        if (\$ssh_blocked) {
            echo \"Status: BLOCKED (SSH service)\\n\";
            echo \"Reason: \" . \$ssh_blocked['reason'] . \"\\n\";
            \$time_left = \$ssh_blocked['unblock_time'] - time();
            \$hours = floor(\$time_left / 3600);
            \$minutes = floor((\$time_left % 3600) / 60);
            echo \"SSH Expires: {$hours}h {$minutes}m\\n\";
        }
        
        if (\$ftp_blocked) {
            echo \"Status: BLOCKED (FTP service)\\n\";
            echo \"Reason: \" . \$ftp_blocked['reason'] . \"\\n\";
            \$time_left = \$ftp_blocked['unblock_time'] - time();
            \$hours = floor(\$time_left / 3600);
            \$minutes = floor((\$time_left % 3600) / 60);
            echo \"FTP Expires: {$hours}h {$minutes}m\\n\";
        }
        
        if (!\$web_blocked && !\$ssh_blocked && !\$ftp_blocked) {
            echo \"Status: ALLOWED (not blocked)\\n\";
        }
        
        // Show recent failed attempts
        \$ssh_attempts = \$monitor->get_service_failed_attempts('ssh', 24);
        \$ftp_attempts = \$monitor->get_service_failed_attempts('ftp', 24);
        
        \$ssh_count = 0;
        \$ftp_count = 0;
        
        foreach (\$ssh_attempts as \$attempt) {
            if (\$attempt['ip_address'] === '$ip') {
                \$ssh_count++;
            }
        }
        
        foreach (\$ftp_attempts as \$attempt) {
            if (\$attempt['ip_address'] === '$ip') {
                \$ftp_count++;
            }
        }
        
        if (\$ssh_count > 0 || \$ftp_count > 0) {
            echo \"\\nRecent Failed Attempts (24h):\\n\";
            if (\$ssh_count > 0) echo \"  SSH: \$ssh_count attempts\\n\";
            if (\$ftp_count > 0) echo \"  FTP: \$ftp_count attempts\\n\";
        }
    }
    "
    
    run_php_command "$php_code"
}

# Function to show statistics
show_stats() {
    echo "Security Statistics:"
    echo "==================="
    
    local php_code="
    \$web_stats = \$security->get_security_stats();
    \$service_stats = \$monitor->get_service_stats();
    
    echo \"Web Service:\\n\";
    echo \"  Blocked IPs: \" . \$web_stats['blocked_ips'] . \"\\n\";
    echo \"  Failed Attempts (24h): \" . \$web_stats['failed_attempts_24h'] . \"\\n\";
    echo \"  Exempted IPs: \" . \$web_stats['exemption_ips'] . \"\\n\";
    
    echo \"\\nSSH Service:\\n\";
    echo \"  Blocked IPs: \" . \$service_stats['ssh']['blocked_ips'] . \"\\n\";
    echo \"  Failed Attempts (24h): \" . \$service_stats['ssh']['failed_attempts_24h'] . \"\\n\";
    echo \"  Monitoring: \" . (\$service_stats['ssh']['monitoring_enabled'] ? 'Enabled' : 'Disabled') . \"\\n\";
    
    echo \"\\nFTP Service:\\n\";
    echo \"  Blocked IPs: \" . \$service_stats['ftp']['blocked_ips'] . \"\\n\";
    echo \"  Failed Attempts (24h): \" . \$service_stats['ftp']['failed_attempts_24h'] . \"\\n\";
    echo \"  Monitoring: \" . (\$service_stats['ftp']['monitoring_enabled'] ? 'Enabled' : 'Disabled') . \"\\n\";
    "
    
    run_php_command "$php_code"
}

# Function to cleanup expired data
cleanup() {
    echo "Cleaning up expired blocks and old data..."
    log_message "Running cleanup of expired blocks and old data"
    
    local php_code="
    \$security->cleanup_expired_blocks();
    \$monitor->cleanup_expired_service_blocks();
    echo \"Cleanup completed successfully\\n\";
    "
    
    if run_php_command "$php_code"; then
        echo "✓ Cleanup completed"
        log_message "Cleanup completed successfully"
    else
        echo "✗ Cleanup failed"
        log_message "Cleanup failed"
        exit 1
    fi
}

# Main script logic
main() {
    # Check if running as root
    if [[ $EUID -ne 0 ]]; then
        echo "ERROR: This script must be run as root" >&2
        exit 1
    fi
    
    # Check for minimum arguments
    if [[ $# -eq 0 ]]; then
        show_usage
        exit 1
    fi
    
    # Parse command
    case "$1" in
        block)
            [[ $# -ge 2 ]] || { echo "ERROR: IP address required"; exit 1; }
            block_ip "$2"
            ;;
        unblock)
            [[ $# -ge 2 ]] || { echo "ERROR: IP address required"; exit 1; }
            unblock_ip "$2"
            ;;
        block-ssh)
            [[ $# -ge 2 ]] || { echo "ERROR: IP address required"; exit 1; }
            block_service_ip "ssh" "$2"
            ;;
        unblock-ssh)
            [[ $# -ge 2 ]] || { echo "ERROR: IP address required"; exit 1; }
            unblock_service_ip "ssh" "$2"
            ;;
        block-ftp)
            [[ $# -ge 2 ]] || { echo "ERROR: IP address required"; exit 1; }
            block_service_ip "ftp" "$2"
            ;;
        unblock-ftp)
            [[ $# -ge 2 ]] || { echo "ERROR: IP address required"; exit 1; }
            unblock_service_ip "ftp" "$2"
            ;;
        exempt)
            [[ $# -ge 2 ]] || { echo "ERROR: IP address required"; exit 1; }
            exempt_ip "$2" "${3:-}"
            ;;
        unexempt)
            [[ $# -ge 2 ]] || { echo "ERROR: IP address required"; exit 1; }
            unexempt_ip "$2"
            ;;
        list-blocked)
            list_blocked
            ;;
        list-exempted)
            list_exempted
            ;;
        status)
            [[ $# -ge 2 ]] || { echo "ERROR: IP address required"; exit 1; }
            check_ip_status "$2"
            ;;
        stats)
            show_stats
            ;;
        cleanup)
            cleanup
            ;;
        -h|--help)
            show_usage
            ;;
        *)
            echo "ERROR: Unknown command: $1" >&2
            echo "Use '$0 --help' for usage information." >&2
            exit 1
            ;;
    esac
}

# Execute main function with all arguments
main "$@"