#!/bin/bash

install_hops() {
    # Clear terminal at startup
    clear

    # Exit on any error
    set -e

    # Script version for update tracking
    local SCRIPT_VERSION="3.1.0-beta"
    local SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

    # Load system utilities
    source "$SCRIPT_DIR/lib/common.sh"
    source "$SCRIPT_DIR/lib/system.sh"

    # --------------------------------------------
    # LOGGING SETUP
    # --------------------------------------------
    setup_logging "homelab-setup"

    local_error_exit() {
        error_exit "$1"
    }

    # Enhanced error handling with rollback
    DEPLOYMENT_STEPS_COMPLETED=()

    track_step() {
        DEPLOYMENT_STEPS_COMPLETED+=("$1")
        log "✅ Step completed: $1"
    }

    rollback_deployment() {
        log "🔄 Rolling back deployment..."
        
        for step in "${DEPLOYMENT_STEPS_COMPLETED[@]}"; do
            case "$step" in
                "containers_started")
                    log "🛑 Stopping containers..."
                    docker compose down --timeout 30 2>/dev/null || true
                    ;;
                "images_pulled")
                    log "🗑️ Removing pulled images..."
                    docker compose down --rmi all 2>/dev/null || true
                    ;;
                "directories_created")
                    log "📁 Cleaning up directories..."
                    [[ -n "$APPDATA_DIR" ]] && rm -rf "$APPDATA_DIR" 2>/dev/null || true
                    ;;
                "compose_generated")
                    log "📝 Removing compose file..."
                    [[ -f "docker-compose.yml" ]] && rm -f docker-compose.yml
                    ;;
            esac
        done
        
        log "🔄 Rollback completed"
    }

    error_exit_with_rollback() {
        log "❌ ERROR: $1"
        rollback_deployment
        log "❌ Installation failed and rolled back. Check logs at: $LOG_FILE"
        exit 1
    }

    # --------------------------------------------
    # HEADER
    # --------------------------------------------
    cat << "EOF"

  _    _  ____  ____  ____  
 | |  | ||  _ \|  _ \/ ___| 
 | |__| || |_) | |_) \___ \ 
 |  __  ||  __/|  __/ ___) |
 |_|  |_||_|   |_|   |____/ 

EOF
    echo -e "🚀 Homelab Orchestration Provisioning Script v${SCRIPT_VERSION}\n"
    log "🚀 Starting HOPS Deployment v${SCRIPT_VERSION}"

    # --------------------------------------------
    # SYSTEM REQUIREMENTS CHECK
    # --------------------------------------------
    validate_system_requirements() {
        local MIN_RAM_GB=2
        local MIN_DISK_GB=10
        local MIN_CORES=2
        
        info "🔍 Validating system requirements..."
        
        # Detect OS first
        detect_os
        
        # Check system requirements using new abstraction
        check_system_requirements $MIN_RAM_GB $MIN_DISK_GB
        
        return 0
    }

    # --------------------------------------------
    # REQUIRED PACKAGES CHECK
    # --------------------------------------------
    check_required_packages() {
        local missing_packages=()
        local required_packages=("curl" "wget" "openssl" "lsof")
        
        # Add OS-specific packages
        if [[ "$OS_NAME_LOWER" == "macos" ]]; then
            required_packages+=("httpd")  # Apache on macOS (for htpasswd)
        else
            required_packages+=("apache2-utils")  # Apache utils on Linux
        fi
        
        info "📦 Checking required packages..."
        
        for package in "${required_packages[@]}"; do
            local check_cmd="${package%%-*}"
            if [[ "$package" == "httpd" ]]; then
                check_cmd="htpasswd"  # Check for htpasswd command on macOS
            fi
            
            if ! command -v "$check_cmd" &>/dev/null; then
                missing_packages+=("$package")
            fi
        done
        
        if [[ ${#missing_packages[@]} -gt 0 ]]; then
            info "📦 Installing missing packages: ${missing_packages[*]}"
            
            for package in "${missing_packages[@]}"; do
                install_package "$package"
            done
        fi
        
        success "✅ All required packages are installed"
    }

    # --------------------------------------------
    # ROOT CHECK
    # --------------------------------------------
    if [[ $EUID -ne 0 ]]; then
        error_exit "This script must be run as root or with sudo."
    fi

    # OS detection is handled by the lib/system.sh functions

    # --------------------------------------------
    # USER CONFIGURATION COLLECTION
    # --------------------------------------------
    collect_user_configuration() {
        log "🔧 Collecting user configuration..."
        
        # Get running user info
        if [[ -n "$SUDO_USER" ]]; then
            RUNNING_USER="$SUDO_USER"
            PUID=$(id -u "$SUDO_USER")
            PGID=$(id -g "$SUDO_USER")
        else
            RUNNING_USER="root"
            PUID=1000
            PGID=1000
            log "⚠️ Running as root, defaulting to PUID=1000, PGID=1000"
        fi
        
        # Timezone configuration
        echo -e "\n🌍 Timezone Configuration"
        echo "Current timezone: $(timedatectl show --property=Timezone --value 2>/dev/null || echo "Unknown")"
        echo -e "Keep current timezone? [Y/n]: "
        read -r keep_tz
        
        if [[ "$keep_tz" =~ ^[Nn]$ ]]; then
            echo -e "Enter timezone (e.g., America/New_York, Europe/London): "
            read -r user_timezone
            validate_timezone "$user_timezone"
            TIMEZONE="$user_timezone"
        else
            TIMEZONE=$(timedatectl show --property=Timezone --value 2>/dev/null || echo "America/New_York")
        fi
        
        # Directory configuration
        echo -e "\n📁 Directory Configuration"
        local default_media_path=$(get_default_media_path)
        local default_config_path=$(get_default_config_path)
        
        echo -e "Media directory [$default_media_path]: "
        read -r media_dir
        MEDIA_DIR="${media_dir:-$default_media_path}"
        
        echo -e "Application data directory [$default_config_path]: "
        read -r appdata_dir
        APPDATA_DIR="${appdata_dir:-$default_config_path}"
        
        # Create directories
        mkdir -p "$MEDIA_DIR"/{movies,tv,music,books,downloads}
        mkdir -p "$APPDATA_DIR"
        
        # Set ownership if not root
        if [[ "$RUNNING_USER" != "root" ]]; then
            chown -R "$PUID:$PGID" "$MEDIA_DIR" "$APPDATA_DIR" 2>/dev/null || true
        fi
        
        log "✅ User configuration collected"
        log "   User: $RUNNING_USER ($PUID:$PGID)"
        log "   Timezone: $TIMEZONE"
        log "   Media: $MEDIA_DIR"
        log "   AppData: $APPDATA_DIR"
    }

    # --------------------------------------------
    # VALIDATION FUNCTIONS
    # --------------------------------------------
    validate_timezone() {
        if ! timedatectl list-timezones | grep -qx "$1" 2>/dev/null; then
            log "⚠️ Timezone '$1' invalid, defaulting to 'America/New_York'"
            TIMEZONE="America/New_York"
        fi
    }

    validate_password() {
        local password="$1"
        local min_length="${2:-12}"
        
        if [[ -z "$password" ]]; then
            echo -e "\n🔐 Password must meet these requirements:"
            echo "   • Minimum $min_length characters"
            echo "   • At least one uppercase letter"
            echo "   • At least one lowercase letter"
            echo "   • At least one number"
            echo "   • At least one special character"
            return 3
        fi
        
        if [[ ${#password} -lt $min_length ]]; then
            return 1
        fi
        
        if [[ ! "$password" =~ [A-Z] ]] || [[ ! "$password" =~ [a-z] ]] || \
           [[ ! "$password" =~ [0-9] ]] || [[ ! "$password" =~ [^A-Za-z0-9] ]]; then
            return 2
        fi
        
        return 0
    }

    check_port() {
        local PORT=$1
        local SERVICE=$2
        if lsof -i :"$PORT" >/dev/null 2>&1; then
            local PROCESS=$(lsof -ti :"$PORT" | head -1)
            local PROCESS_NAME=$(ps -p "$PROCESS" -o comm= 2>/dev/null || echo "unknown")
            log "⚠️ Port $PORT is already in use by $PROCESS_NAME. $SERVICE may fail to start."
            return 1
        fi
        return 0
    }

    check_all_ports() {
        local SERVICES=("$@")
        local CONFLICTS=()
        
        # Source service definitions to get port mappings
        if [[ -f "$SCRIPT_DIR/services" ]]; then
            source "$SCRIPT_DIR/services"
        fi
        
        for svc in "${SERVICES[@]}"; do
            local ports=$(get_service_ports "$svc")
            for port in $ports; do
                if ! check_port "$port" "$svc"; then
                    CONFLICTS+=("Port $port ($svc)")
                fi
            done
        done
        
        if [[ ${#CONFLICTS[@]} -gt 0 ]]; then
            log "⚠️ Found ${#CONFLICTS[@]} port conflicts:"
            for conflict in "${CONFLICTS[@]}"; do
                log "   • $conflict"
            done
            
            echo -e "\n⚠️ Port conflicts detected! Continue anyway? (y/N): "
            read -r continue_choice
            if [[ ! "$continue_choice" =~ ^[Yy]$ ]]; then
                error_exit "Installation cancelled due to port conflicts."
            fi
            return 1
        fi
        return 0
    }

    # --------------------------------------------
    # DOCKER COMPOSE VERSION CHECK
    # --------------------------------------------
    check_docker_compose_version() {
        # Check for Docker Compose plugin (v2)
        if docker compose version &>/dev/null; then
            log "✅ Docker Compose plugin detected ($(docker compose version --short))"
            return 0
        fi
        
        # Check for standalone docker-compose (v1)
        if command -v docker-compose &>/dev/null; then
            log "⚠️ Found legacy docker-compose (v1). Installing Docker Compose plugin..."
            if ! apt-get install -y docker-compose-plugin 2>&1 | tee -a "$LOG_FILE"; then
                error_exit "Failed to install Docker Compose plugin."
            fi
            return 0
        fi
        
        # Neither found
        error_exit "No Docker Compose detected. Please install Docker first."
    }

    # --------------------------------------------
    # IMPROVED PASSWORD GENERATION
    # --------------------------------------------
    generate_secure_password() {
        local length="${1:-16}"
        local max_attempts=5
        local attempt=1
        
        while [[ $attempt -le $max_attempts ]]; do
            # Generate password with mixed case, numbers, and symbols
            local password=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-${length})
            
            # Ensure it meets complexity requirements
            if validate_password "$password" "$length"; then
                echo "$password"
                return 0
            fi
            
            ((attempt++))
        done
        
        # Fallback: construct a guaranteed compliant password
        local upper=$(tr -dc 'A-Z' < /dev/urandom | head -c2)
        local lower=$(tr -dc 'a-z' < /dev/urandom | head -c4)
        local digits=$(tr -dc '0-9' < /dev/urandom | head -c2)
        local symbols=$(tr -dc '!@#$%^&*' < /dev/urandom | head -c2)
        local remaining_length=$((length - 10))
        
        if [[ $remaining_length -gt 0 ]]; then
            local remaining=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c$remaining_length)
            echo "${upper}${lower}${digits}${symbols}${remaining}" | fold -w1 | shuf | tr -d '\n'
        else
            echo "${upper}${lower}${digits}${symbols}"
        fi
    }

    # --------------------------------------------
    # ENVIRONMENT FILE GENERATION
    # --------------------------------------------
    create_env_file() {
        local homelab_dir="$1"
        
        log "📝 Creating environment file..."
        
        cat > "$homelab_dir/.env" <<EOF
# HOPS Environment Configuration
# Generated on $(date)

# ==============================================
# CORE CONFIGURATION
# ==============================================

# User Configuration
PUID=$PUID
PGID=$PGID
TZ=$TIMEZONE

# Directory Configuration
DATA_ROOT=$MEDIA_DIR
CONFIG_ROOT=$APPDATA_DIR
HOMELAB_DIR=$homelab_dir

# Network Configuration
DOCKER_SUBNET=172.20.0.0/16

# ==============================================
# SECURITY & AUTHENTICATION
# ==============================================

# Default Passwords (CHANGE THESE IMMEDIATELY!)
DEFAULT_ADMIN_PASSWORD=$(generate_secure_password 16)
DEFAULT_DB_PASSWORD=$(generate_secure_password 20)

# Optional: Custom domain for reverse proxy
# DOMAIN=yourdomain.com

# Optional: Email for Let's Encrypt
# ACME_EMAIL=admin@yourdomain.com

# ==============================================
# SERVICE-SPECIFIC CONFIGURATION
# ==============================================

# Plex Configuration (Get token from: https://www.plex.tv/claim/)
PLEX_CLAIM_TOKEN=

# Watchtower Email Notifications (Optional)
WATCHTOWER_EMAIL_FROM=
WATCHTOWER_EMAIL_TO=
WATCHTOWER_EMAIL_SERVER=
WATCHTOWER_EMAIL_PORT=587
WATCHTOWER_EMAIL_USER=
WATCHTOWER_EMAIL_PASSWORD=

# Traefik Let's Encrypt Email
ACME_EMAIL=admin@localhost
EOF
        
        chmod 600 "$homelab_dir/.env"
        log "✅ Environment file created with secure permissions"
    }

    # --------------------------------------------
    # SERVICE SELECTION
    # --------------------------------------------
    select_services() {
        echo -e "\n📺 CORE MEDIA TOOLS"
        echo "1) Sonarr      2) Radarr      3) Lidarr      4) Readarr"
        echo "5) Bazarr      6) Prowlarr    7) Tdarr       8) Huntarr"

        echo -e "\n⬇️  DOWNLOAD CLIENTS"
        echo "9) NZBGet      10) SABnzbd    11) Transmission  12) qBittorrent"

        echo -e "\n🎞️  MEDIA SERVERS"
        echo "13) Plex       14) Jellyfin   15) Jellystat     16) Emby"

        echo -e "\n🎛️  REQUEST MANAGEMENT"
        echo "17) Overseerr  18) Jellyseerr 19) Ombi"

        echo -e "\n🔒 NETWORK & SECURITY"
        echo "20) Traefik    21) Nginx Proxy Manager  22) Authelia"

        echo -e "\n📈 MONITORING"
        echo "23) Portainer  24) Watchtower  25) Uptime Kuma"

        echo -e "\n📝 Select services (space-separated numbers, or 'all' for everything): "
        read -a service_choices

        # Function to map service numbers to names (bash 3.2 compatible)
        get_service_name() {
            case "$1" in
                1) echo "sonarr" ;;
                2) echo "radarr" ;;
                3) echo "lidarr" ;;
                4) echo "readarr" ;;
                5) echo "bazarr" ;;
                6) echo "prowlarr" ;;
                7) echo "tdarr" ;;
                8) echo "huntarr" ;;
                9) echo "nzbget" ;;
                10) echo "sabnzbd" ;;
                11) echo "transmission" ;;
                12) echo "qbittorrent" ;;
                13) echo "plex" ;;
                14) echo "jellyfin" ;;
                15) echo "jellystat" ;;
                16) echo "emby" ;;
                17) echo "overseerr" ;;
                18) echo "jellyseerr" ;;
                19) echo "ombi" ;;
                20) echo "traefik" ;;
                21) echo "nginx-proxy-manager" ;;
                22) echo "authelia" ;;
                23) echo "portainer" ;;
                24) echo "watchtower" ;;
                25) echo "uptime-kuma" ;;
                *) echo "" ;;
            esac
        }

        SERVICES=()
        if [[ "${service_choices[0]}" == "all" ]]; then
            SERVICES=("sonarr" "radarr" "lidarr" "readarr" "bazarr" "prowlarr" "tdarr" "huntarr" "nzbget" "sabnzbd" "transmission" "qbittorrent" "plex" "jellyfin" "jellystat" "emby" "overseerr" "jellyseerr" "ombi" "traefik" "nginx-proxy-manager" "authelia" "portainer" "watchtower" "uptime-kuma")
            log "🎯 Selected all services"
        else
            for choice in "${service_choices[@]}"; do
                service_name=$(get_service_name "$choice")
                [[ -n "$service_name" ]] && SERVICES+=("$service_name")
            done
        fi

        if [[ ${#SERVICES[@]} -eq 0 ]]; then
            error_exit "No valid services selected."
        fi

        log "✅ Selected services: ${SERVICES[*]}"

        # Check for service dependencies and conflicts
        check_service_dependencies
        check_service_conflicts
    }

    # --------------------------------------------
    # DEPENDENCY AND CONFLICT CHECKING
    # --------------------------------------------
    check_service_dependencies() {
        # Source service definitions for dependency resolution
        if [[ -f "$SCRIPT_DIR/services" ]]; then
            source "$SCRIPT_DIR/services"
            
            # Resolve dependencies
            local all_services=($(resolve_dependencies "${SERVICES[@]}"))
            local deps_added=()
            
            for service in "${all_services[@]}"; do
                if [[ ! " ${SERVICES[*]} " =~ " ${service} " ]]; then
                    deps_added+=("$service")
                fi
            done
            
            if [[ ${#deps_added[@]} -gt 0 ]]; then
                log "📦 Adding dependencies: ${deps_added[*]}"
                SERVICES=("${all_services[@]}")
            fi
        fi
        
        # Check if any *arr services are selected without Prowlarr
        local arr_services=(sonarr radarr lidarr readarr)
        local has_arr=false
        for arr in "${arr_services[@]}"; do
            if [[ "${SERVICES[*]}" =~ $arr ]]; then
                has_arr=true
                break
            fi
        done
        
        if [[ $has_arr == true ]] && [[ ! "${SERVICES[*]}" =~ prowlarr ]]; then
            echo -e "\n💡 Recommendation: You selected *arr services but not Prowlarr."
            echo "Prowlarr manages indexers for all *arr applications."
            echo -e "Add Prowlarr? [Y/n]: "
            read -r add_prowlarr
            if [[ ! "$add_prowlarr" =~ ^[Nn]$ ]]; then
                SERVICES+=("prowlarr")
                log "✅ Added Prowlarr"
            fi
        fi
    }

    check_service_conflicts() {
        local warnings=()
        
        # Check for multiple media servers
        local media_servers=(plex jellyfin emby)
        local selected_media_servers=()
        for server in "${media_servers[@]}"; do
            if [[ "${SERVICES[*]}" =~ $server ]]; then
                selected_media_servers+=("$server")
            fi
        done
        
        if [[ ${#selected_media_servers[@]} -gt 1 ]]; then
            warnings+=("Multiple media servers selected: ${selected_media_servers[*]}")
        fi
        
        # Check for multiple reverse proxies
        local reverse_proxies=(traefik nginx-proxy-manager)
        local selected_proxies=()
        for proxy in "${reverse_proxies[@]}"; do
            if [[ "${SERVICES[*]}" =~ $proxy ]]; then
                selected_proxies+=("$proxy")
            fi
        done
        
        if [[ ${#selected_proxies[@]} -gt 1 ]]; then
            warnings+=("Multiple reverse proxies selected: ${selected_proxies[*]} (may conflict on ports 80/443)")
        fi
        
        # Display warnings if any
        if [[ ${#warnings[@]} -gt 0 ]]; then
            log "⚠️ Configuration warnings:"
            for warning in "${warnings[@]}"; do
                log "   • $warning"
            done
            
            echo -e "\n⚠️ Continue with this configuration? [y/N]: "
            read -r continue_choice
            if [[ ! "$continue_choice" =~ ^[Yy]$ ]]; then
                log "🚫 Installation cancelled by user"
                exit 0
            fi
        fi
    }

    # --------------------------------------------
    # DOCKER COMPOSE FILE GENERATION
    # --------------------------------------------
    generate_docker_compose() {
        local HOMELAB_DIR="$HOME/hops"
        mkdir -p "$HOMELAB_DIR"
        cd "$HOMELAB_DIR"

        if [[ -f docker-compose.yml ]]; then
            local BACKUP_FILE="docker-compose.yml.bak.$(date +%Y%m%d%H%M%S)"
            log "📝 Backing up existing compose file to $BACKUP_FILE"
            mv docker-compose.yml "$BACKUP_FILE"
        fi

        log "📝 Generating Docker Compose configuration..."
        create_env_file "$HOMELAB_DIR"

        # Source the service definitions
        if [[ -f "$SCRIPT_DIR/services" ]]; then
            source "$SCRIPT_DIR/services"
            
            # Export variables for service definitions
            export PUID PGID TIMEZONE MEDIA_DIR APPDATA_DIR
            
            # Generate complete compose file with all services
            generate_complete_compose "${SERVICES[@]}"
            track_step "compose_generated"
            
            # Create service-specific configurations
            create_service_configs "${SERVICES[@]}"
            
            log "✅ Generated Docker Compose with ${#SERVICES[@]} services"
        else
            error_exit "Service definitions file not found: $SCRIPT_DIR/services"
        fi

        # Create networks if they don't exist
        create_docker_networks
    }

    # --------------------------------------------
    # NETWORK CREATION
    # --------------------------------------------
    create_docker_networks() {
        log "🌐 Creating Docker networks..."
        
        # Create traefik network if it doesn't exist
        if ! docker network ls --format "{{.Name}}" | grep -q "^traefik$"; then
            if docker network create traefik 2>/dev/null; then
                log "✅ Created traefik network"
            else
                log "⚠️ Could not create traefik network (may already exist)"
            fi
        fi
    }

    # --------------------------------------------
    # ENHANCED DEPLOYMENT WITH ROLLBACK
    # --------------------------------------------
    deploy_services() {
        log "🚀 Starting deployment..."

        # Set up error trap
        trap 'error_exit_with_rollback "Deployment failed at step: ${BASH_COMMAND}"' ERR

        # Pre-deployment checks
        log "🔍 Running pre-deployment validation..."
        if ! docker info >/dev/null 2>&1; then
            error_exit_with_rollback "Docker daemon is not running or accessible"
        fi

        if ! docker compose config >/dev/null 2>&1; then
            error_exit_with_rollback "Generated docker-compose.yml is invalid"
        fi

        # Create required directories
        log "📁 Creating required directories..."
        for svc in "${SERVICES[@]}"; do
            mkdir -p "${APPDATA_DIR}/${svc}"
            chown -R "$PUID:$PGID" "${APPDATA_DIR}/${svc}" 2>/dev/null || true
        done
        track_step "directories_created"

        # Pull images with retry logic
        log "📥 Pulling container images..."
        local PULL_RETRIES=3
        for attempt in $(seq 1 $PULL_RETRIES); do
            if docker compose pull 2>&1 | tee -a "$LOG_FILE"; then
                track_step "images_pulled"
                break
            elif [[ $attempt -eq $PULL_RETRIES ]]; then
                error_exit_with_rollback "Failed to pull images after $PULL_RETRIES attempts"
            else
                log "⚠️ Pull attempt $attempt failed, retrying in 10 seconds..."
                sleep 10
            fi
        done

        # Start containers
        log "🔄 Starting containers..."
        if docker compose up -d 2>&1 | tee -a "$LOG_FILE"; then
            track_step "containers_started"
        else
            log "❌ Some containers failed to start. Checking status..."
            docker compose ps
            error_exit_with_rollback "Container startup failed"
        fi

        # Clear trap on success
        trap - ERR
    }

    # --------------------------------------------
    # ENHANCED SERVICE VERIFICATION
    # --------------------------------------------
    verify_service_health() {
        local service_name="$1"
        local max_wait=300  # 5 minutes
        local interval=10
        
        log "🔍 Waiting for $service_name to be healthy..."
        
        for ((i=0; i<max_wait; i+=interval)); do
            local health=$(docker inspect --format='{{.State.Health.Status}}' "$service_name" 2>/dev/null || echo "none")
            
            case "$health" in
                "healthy")
                    log "✅ $service_name is healthy"
                    return 0
                    ;;
                "starting")
                    log "⏳ $service_name is starting... (${i}s elapsed)"
                    ;;
                "unhealthy")
                    log "❌ $service_name is unhealthy"
                    return 1
                    ;;
                "none")
                    # No health check defined, check if container is running
                    local state=$(docker inspect --format='{{.State.Status}}' "$service_name" 2>/dev/null || echo "unknown")
                    if [[ "$state" == "running" ]]; then
                        log "✅ $service_name is running (no health check)"
                        return 0
                    fi
                    ;;
            esac
            
            sleep "$interval"
        done
        
        log "⚠️ $service_name health check timed out"
        return 1
    }

    verify_services() {
        log "🩺 Verifying service health..."

        local FAILED_SERVICES=()
        for svc in "${SERVICES[@]}"; do
            if docker ps --format "{{.Names}}" | grep -qi "^${svc}$"; then
                if ! verify_service_health "$svc"; then
                    FAILED_SERVICES+=("$svc")
                fi
            else
                log "❌ $svc container not found"
                FAILED_SERVICES+=("$svc")
            fi
        done

        if [[ ${#FAILED_SERVICES[@]} -gt 0 ]]; then
            log "⚠️ Services requiring attention:"
            for svc in "${FAILED_SERVICES[@]}"; do
                log "   • $svc - Check logs: docker logs $svc"
            done
        else
            log "✅ All services are healthy"
        fi
    }

    # --------------------------------------------
    # SECURITY SETUP
    # --------------------------------------------
    setup_security() {
        log "🔒 Applying security hardening..."
        
        # Secure sensitive files
        find "$APPDATA_DIR" -name "*.env" -exec chmod 600 {} \; 2>/dev/null || true
        find "$APPDATA_DIR" -name "*.key" -exec chmod 600 {} \; 2>/dev/null || true
        find "$APPDATA_DIR" -name "*.pem" -exec chmod 600 {} \; 2>/dev/null || true
        
        # Set secure permissions on homelab directory
        chmod 750 "$HOME/hops"
        
        log "✅ Security hardening applied"
    }

    setup_firewall() {
        if [[ "$OS_NAME_LOWER" == "macos" ]]; then
            info "🔥 Skipping firewall configuration on macOS (configure manually if needed)"
            return 0
        fi
        
        if command -v ufw &>/dev/null; then
            log "🔥 Configuring UFW firewall..."
            
            # Don't reset if already configured
            if ! ufw status | grep -q "Status: active"; then
                ufw --force reset >/dev/null 2>&1
                ufw default deny incoming >/dev/null 2>&1
                ufw default allow outgoing >/dev/null 2>&1
                
                # Allow SSH
                ufw allow ssh >/dev/null 2>&1
            fi
            
            # Allow service ports based on selection
            if [[ -f "$SCRIPT_DIR/hops_service_definitions.sh" ]]; then
                source "$SCRIPT_DIR/hops_service_definitions.sh"
                
                for svc in "${SERVICES[@]}"; do
                    local ports=$(get_service_ports "$svc")
                    for port in $ports; do
                        # Skip UDP ports and handle TCP/UDP notation
                        if [[ "$port" =~ /udp$ ]]; then
                            local port_num="${port%/udp}"
                            ufw allow "$port_num/udp" comment "$svc" >/dev/null 2>&1
                        else
                            local port_num="${port%/tcp}"
                            ufw allow "$port_num/tcp" comment "$svc" >/dev/null 2>&1
                        fi
                    done
                done
            fi
            
            ufw --force enable >/dev/null 2>&1
            log "✅ Firewall configured"
        else
            log "ℹ️ UFW not available, skipping firewall configuration"
        fi
    }

    # --------------------------------------------
    # MAIN INSTALLATION FLOW
    # --------------------------------------------
    validate_system_requirements
    check_required_packages
    collect_user_configuration
    select_services
    check_all_ports "${SERVICES[@]}"

    # Install dependencies using abstraction
    info "📦 Installing prerequisites..."
    
    # Define packages based on OS
    local required_packages
    if [[ "$OS_NAME_LOWER" == "macos" ]]; then
        required_packages=("curl" "openssl" "lsof" "httpd")
    else
        required_packages=("ca-certificates" "curl" "gnupg" "lsb-release" "lsof" "ufw" "fail2ban" "openssl" "apache2-utils")
    fi
    
    # Install each package
    for package in "${required_packages[@]}"; do
        if ! command -v "${package%%-*}" &>/dev/null; then
            install_package "$package"
        fi
    done

    # Install Docker if not present
    if ! check_docker_installation; then
        install_docker
    else
        success "✅ Docker already installed and running"
    fi

    check_docker_compose_version

    # Ensure Docker daemon is running
    if ! is_service_running docker; then
        start_service docker
        enable_service docker
    fi

    setup_firewall
    generate_docker_compose
    deploy_services
    setup_security
    verify_services

    # --------------------------------------------
    # FINAL SUMMARY
    # --------------------------------------------
    echo -e "\n🎉 HOPS Enhanced Deployment Complete!"
    echo -e "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

    log "📋 Deployment Summary:"
    echo -e "\n📂 Configuration:"
    echo "   • Homelab Directory: $HOME/hops"
    echo "   • Application Data: $APPDATA_DIR"
    echo "   • Media Directory: $MEDIA_DIR"
    echo "   • User/Group: $RUNNING_USER ($PUID:$PGID)"
    echo "   • Timezone: $TIMEZONE"
    echo "   • Log File: $LOG_FILE"

    echo -e "\n🔐 Security:"
    echo "   • Generated secure passwords (see .env file)"
    echo "   • Firewall configured with service-specific rules"
    echo "   • File permissions hardened"

    echo -e "\n📱 Deployed Services:"
    local service_count=0
    for svc in "${SERVICES[@]}"; do
        if [[ -f "$SCRIPT_DIR/services" ]]; then
            source "$SCRIPT_DIR/services"
            local ports=$(get_service_ports "$svc")
            local main_port=$(echo $ports | cut -d' ' -f1)
            if [[ -n "$main_port" ]]; then
                echo "   • $svc: http://$(get_primary_ip):$main_port"
                ((service_count++))
            fi
        fi
    done

    echo -e "\n🔧 Management Commands:"
    echo "   • View all logs: docker compose logs -f"
    echo "   • View service logs: docker compose logs -f [service]"
    echo "   • Restart service: docker compose restart [service]"
    echo "   • Stop services: docker compose down"
    echo "   • Start services: docker compose up -d"
    echo "   • Update services: docker compose pull && docker compose up -d"

    echo -e "\n📚 Next Steps:"
    echo "   1. Access services using the URLs above"
    echo "   2. Change default passwords from .env file"
    echo "   3. Configure services according to your needs"
    echo "   4. Set up your media library paths"

    echo -e "\n📋 Logs and troubleshooting: $LOG_FILE"
    echo -e "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

    log "🎉 HOPS Enhanced deployment completed successfully!"
    return 0
}

# Execute the main installation function
install_hops