#!/bin/bash
set -euo pipefail

# =============================================================================
# Metrici Ubuntu 24.04 Installation Script v4.1
# =============================================================================
# Features:
#   - Strict error handling (critical steps stop installation)
#   - Visual progress bar (ASCII text in console)
#   - State tracking (.metrici-install-state.json)
#   - Resume capability (--resume flag)
#   - Colored summary report
# =============================================================================

# --- Colors ---
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly BOLD='\033[1m'
readonly NC='\033[0m' # No Color

# --- Configuration ---
readonly SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
readonly HOME_DIR="${HOME}"
readonly METRICI_DIR="${HOME_DIR}/metrici"
readonly METRICI_OBJECTS_DIR="${METRICI_DIR}/objects"
readonly METRICI_DB_NAME="metrici2"
readonly METRICI_DB_USER="root"
readonly METRICI_DB_PASS="metriciadmin"
readonly TIMEZONE="$(realpath /etc/localtime | awk -F'/usr/share/zoneinfo/' '{ print $2 }')"
readonly DOWNLOAD_BASE="https://support.metrici.ro/ubuntu2404"
readonly DOWNLOAD_TIMEOUT=120
readonly DOWNLOAD_RETRIES=3
readonly DOWNLOAD_RETRY_DELAY=5

# --- State File ---
readonly STATE_FILE="${SCRIPT_DIR}/.metrici-install-state.json"

# --- Progress ---
# Text-only progress bar, no zenity
readonly VERBOSE_LOG="${SCRIPT_DIR}/install-verbose.log"

# --- Step Tracking ---
declare -A STEP_STATUS
declare -A STEP_CRITICAL
declare -a STEP_ORDER=()
TOTAL_STEPS=0
CURRENT_STEP=0
FAILED_CRITICAL=""

# --- Sudo Keepalive ---
SUDO_KEEPALIVE_PID=""
IS_ROOT=false  # Will be set to true if running as root

# =============================================================================
# State Management
# =============================================================================

init_state_file() {
    if [[ ! -f "$STATE_FILE" ]]; then
        echo "" > "$STATE_FILE"  # placeholder, will be written at end
    fi
}

load_state() {
    if [[ -f "$STATE_FILE" ]] && [[ -s "$STATE_FILE" ]]; then
        # Parse step statuses from JSON (simple grep/sed, no jq required)
        local step_name
        local status
        # Extract all step_NN entries and their statuses
        while IFS= read -r line; do
            # Match lines like:    "step_validate_dependencies": "success",
            if [[ "$line" =~ \"step_[^\"]+\":\ *\"([^\"]+)\" ]]; then
                step_name=$(echo "$line" | grep -oP '"step_\K[^"]+(?=")')
                status="${BASH_REMATCH[1]}"
                STEP_STATUS["$step_name"]="$status"
            fi
        done < "$STATE_FILE"
    fi
}

update_step_status() {
    local step_name="$1"
    local status="$2"
    STEP_STATUS["$step_name"]="$status"
}

write_state_file() {
    local started_at="$1"
    local completed_at="$2"

    {
        echo "{"
        echo "  \"version\": \"4.1\","
        echo "  \"started_at\": \"${started_at}\","
        echo "  \"completed_at\": \"${completed_at}\","
        echo "  \"steps\": {"

        local total=${#STEP_ORDER[@]}
        local current=0

        for step_name in "${STEP_ORDER[@]}"; do
            current=$((current + 1))
            local status="${STEP_STATUS[$step_name]:-pending}"
            if [[ $current -lt $total ]]; then
                echo "    \"${step_name}\": \"${status}\","
            else
                echo "    \"${step_name}\": \"${status}\""
            fi
        done

        echo "  }"
        echo "}"
    } > "$STATE_FILE"
}

# =============================================================================
# Progress Bar (text only, in console) — functions defined in Logging section
# =============================================================================

SPINNER_PID=""

init_progress_bar() {
    :
}

update_progress() {
    :
}

start_spinner() {
    local text="$1"
    (
        local frames=('|' '/' '\' '-')
        local i=0
        while true; do
            printf "\r  [%s] %s..." "${frames[$i]}" "$text" >/dev/tty
            i=$(( (i + 1) % 4 ))
            sleep 0.3
        done
    ) &
    SPINNER_PID=$!
}

stop_spinner() {
    if [[ -n "$SPINNER_PID" ]]; then
        kill "$SPINNER_PID" 2>/dev/null || true
        wait "$SPINNER_PID" 2>/dev/null || true
        SPINNER_PID=""
        # Clear the spinner line
        printf "\r\033[K" >/dev/tty
    fi
}

# =============================================================================
# Logging - messages go to terminal (fd 4), command output goes to log file
# =============================================================================

log_info()    { echo -e "${BLUE}[INFO]${NC} $(date '+%H:%M:%S') - $*" >&4; }
log_error()   { echo -e "${RED}[ERROR]${NC} $(date '+%H:%M:%S') - $*" >&4; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $(date '+%H:%M:%S') - $*" >&4; }
log_warn()    { echo -e "${YELLOW}[WARN]${NC} $(date '+%H:%M:%S') - $*" >&4; }
log_step()    { echo "" >&4; echo -e "${BOLD}${CYAN}========== $* ==========${NC}" >&4; }

# Progress bar goes to terminal (fd 4)
show_step_result() {
    local step_num="$1"
    local step_name="$2"
    local total="$3"
    local status="$4"  # "success", "failed", or "skipped"
    local percentage=$(( (step_num * 100) / total ))
    local timestamp
    timestamp=$(date '+%H:%M:%S')

    local status_str
    case "$status" in
        success) status_str="${GREEN}[SUCCESS]${NC}" ;;
        failed)  status_str="${RED}[FAILED]${NC}" ;;
        skipped) status_str="${YELLOW}[SKIP ]${NC}" ;;
    esac

    printf "  %s - %-30s %b %3d%%\n" "$timestamp" "$step_name" "$status_str" "$percentage" >/dev/tty
}

close_progress_bar() {
    echo "" >/dev/tty
}

# =============================================================================
# Error Handling
# =============================================================================

cleanup() {
    local exit_code=$?
    # Kill sudo keepalive
    if [[ -n "$SUDO_KEEPALIVE_PID" ]]; then
        kill "$SUDO_KEEPALIVE_PID" 2>/dev/null || true
        wait "$SUDO_KEEPALIVE_PID" 2>/dev/null || true
    fi
    close_progress_bar

    if [[ $exit_code -ne 0 ]]; then
        echo "" >&4
        log_error "Script failed with exit code: $exit_code"
        if [[ -n "$FAILED_CRITICAL" ]]; then
            log_error "Critical step failed: $FAILED_CRITICAL"
        fi
        log_error "Use --resume to continue from where it stopped"
        log_error "State saved to: $STATE_FILE"
    fi
    exit $exit_code
}

trap cleanup EXIT

# =============================================================================
# Step Name Formatting
# =============================================================================

step_display_name() {
    # Convert "step_validate_dependencies" to "Validate Dependencies"
    local name="$1"
    # Remove "step_" prefix
    name="${name#step_}"
    # Replace underscores with spaces
    name="${name//_/ }"
    # Capitalize first letter of each word
    name=$(echo "$name" | sed 's/\b\(.\)/\u\1/g')
    echo "$name"
}

# =============================================================================
# Step Registration
# =============================================================================

register_step() {
    local name="$1"
    local critical="$2"  # "true" or "false"

    STEP_ORDER+=("$name")
    STEP_CRITICAL["$name"]="$critical"
    STEP_STATUS["$name"]="${STEP_STATUS[$name]:-pending}"
    TOTAL_STEPS=$((TOTAL_STEPS + 1))
}

should_skip_step() {
    local step_name="$1"
    local status="${STEP_STATUS[$step_name]:-pending}"
    [[ "$status" == "success" ]]
}

is_step_critical() {
    local step_name="$1"
    [[ "${STEP_CRITICAL[$step_name]:-false}" == "true" ]]
}

# =============================================================================
# Download Helper (Strict)
# =============================================================================

download_file() {
    local url="$1"
    local output_file="${2:-}"
    local filename
    filename=$(basename "$url")

    if [[ -n "$output_file" ]]; then
        filename="$output_file"
    fi

    log_info "Downloading: $filename"

    local attempt=0
    while (( attempt < DOWNLOAD_RETRIES )); do
        attempt=$((attempt + 1))

        if timeout "$DOWNLOAD_TIMEOUT" wget -q --timeout=60 --tries=1 -O "$filename" "$url"; then
            if [[ -f "$filename" ]] && [[ -s "$filename" ]]; then
                log_info "Downloaded: $filename"
                return 0
            fi
        fi

        log_warn "Download attempt $attempt/$DOWNLOAD_RETRIES failed for: $filename"
        rm -f "$filename"

        if (( attempt < DOWNLOAD_RETRIES )); then
            log_info "Retrying in ${DOWNLOAD_RETRY_DELAY}s..."
            sleep "$DOWNLOAD_RETRY_DELAY"
        fi
    done

    log_error "Failed to download: $filename after $DOWNLOAD_RETRIES attempts"
    return 1
}

# Download multiple files, fail on first error
download_files_strict() {
    local -a urls=("$@")
    for url in "${urls[@]}"; do
        if ! download_file "$url"; then
            return 1
        fi
    done
    return 0
}

# Download multiple files, collect failures but continue
download_files_optional() {
    local -a urls=("$@")
    local -a failed=()
    for url in "${urls[@]}"; do
        if ! download_file "$url"; then
            failed+=("$(basename "$url")")
        fi
    done
    if [[ ${#failed[@]} -gt 0 ]]; then
        log_warn "Failed to download: ${failed[*]}"
    fi
    return 0
}

# =============================================================================
# GPU Detection
# =============================================================================

detect_vendor() {
    local card="$1"
    if echo "$card" | grep -q "NVIDIA"; then
        echo "nvidia"
    elif echo "$card" | grep -q "Intel"; then
        echo "intel"
    elif echo "$card" | grep -q "AMD"; then
        echo "amd"
    else
        echo "unknown"
    fi
}

install_intel_drivers() {
    log_step "Installing Intel GPU drivers"
    wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | \
        sudo gpg --yes --dearmor --output /usr/share/keyrings/intel-graphics.gpg
    echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] \
https://repositories.intel.com/gpu/ubuntu noble client" | \
        sudo tee /etc/apt/sources.list.d/intel-gpu-noble.list >/dev/null
    sudo apt update -y
    sudo apt-get install -y libze-intel-gpu1 libze1 intel-opencl-icd intel-gsc \
        libze-dev intel-ocloc
}

install_nvidia_drivers() {
    log_step "Installing NVIDIA GPU drivers"
    sudo apt-get install -y nvidia-driver-590-open libnvidia-compute-590
}

install_amd_drivers() {
    log_step "Installing AMD GPU drivers"
    local deb_file="amdgpu-install_7.2.70200-1_all.deb"
    download_file "https://repo.radeon.com/amdgpu-install/25.35/ubuntu/noble/${deb_file}"
    sudo apt-get install -y "./${deb_file}"
    sudo apt update -y
    sudo amdgpu-install -y --usecase=opencl --opencl=rocr
    rm -f "${deb_file}"
}

# =============================================================================
# Installation Steps
# =============================================================================

step_validate_dependencies() {
    log_step "Validating dependencies"
    local missing_deps=()
    for cmd in wget sudo apt grep sed awk; do
        if ! command -v "$cmd" &>/dev/null; then
            missing_deps+=("$cmd")
        fi
    done
    if [[ ${#missing_deps[@]} -gt 0 ]]; then
        log_error "Missing dependencies: ${missing_deps[*]}"
        return 1
    fi
    log_success "All dependencies validated"
}

step_configure_gpu_drivers() {
    log_step "Configuring GPU drivers"
    local vga_cards
    vga_cards=$(lspci | grep 'VGA' | grep 'NVIDIA\|Intel\|AMD' || true)

    if [[ -z "$vga_cards" ]]; then
        log_info "No NVIDIA/Intel/AMD VGA cards detected, skipping"
        return 0
    fi

    while IFS= read -r card; do
        [[ -z "$card" ]] && continue
        local vendor
        vendor=$(detect_vendor "$card")
        log_info "Processing: $(echo "$card" | cut -c1-60) (Vendor: $vendor)"

        case "$vendor" in
            nvidia) install_nvidia_drivers ;;
            intel)  install_intel_drivers ;;
            amd)    install_amd_drivers ;;
            *)      log_info "Unknown vendor, skipping" ;;
        esac
    done <<< "$vga_cards"

    sudo usermod -a -G render,video "$(whoami)"
    log_success "GPU drivers configured"
}

step_setup_system_packages() {
    log_step "Installing system packages"

    # Add PPAs (ignore if already present)
    log_info "Adding PPAs..."
    sudo add-apt-repository ppa:quentiumyt/nvtop -y 2>/dev/null || true
    sudo add-apt-repository ppa:ondrej/php -y 2>/dev/null || true
    sudo add-apt-repository ppa:ondrej/apache2 -y 2>/dev/null || true

    # Update and upgrade
    log_info "Updating package lists..."
    sudo apt update -y
    log_info "Upgrading system packages..."
    sudo apt upgrade -y

    # Install packages
    local utils="clinfo screen sqlite3 gpsd modemmanager smstools nvtop mc chrony gedit ssh"
    local qt5="libqt5sql5-sqlite libqt5quick5 libqt5qml5 libqt5network5t64 libqt5widgets5t64"
    local qt5_gstreamer="libqt5gstreamer-1.0-0 libqt5glib-2.0-0 libqt5gstreamerutils-1.0-0"
    local gstreamer="gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-libav gstreamer1.0-pipewire \
        gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly \
        gstreamer1.0-vaapi gstreamer1.0-x libgstreamer-gl1.0-0 \
        libgstreamer-plugins-bad1.0-0 libgstreamer-plugins-base1.0-0 \
        libgstreamer-plugins-good1.0-0 libgstreamer1.0-0 libgtk-4-media-gstreamer"
    local server="apache2 mysql-server memcached curl net-tools smartmontools plocate zbar-tools libzxing3"
    local php="php7.4 php7.4-fpm php7.4-cli php7.4-json php7.4-common php7.4-mysql \
        php7.4-zip php7.4-gd php7.4-mbstring php7.4-mcrypt php7.4-memcache \
        php7.4-curl php7.4-xml php7.4-bcmath php7.4-imagick php-pear"

    log_info "Installing packages..."
    sudo apt-get install -y $utils $qt5 $qt5_gstreamer $gstreamer $server $php
    sudo apt-mark hold php7.4-*

    # Configure Apache + PHP
    sudo a2enmod proxy_fcgi setenvif rewrite
    sudo a2enconf php7.4-fpm

    log_success "System packages installed"
}

step_configure_php() {
    log_step "Configuring PHP"

    local ioncube_files=("ioncube_loader_lin_7.4.so" "ioncube_loader_lin_7.4_ts.so")

    # Download IonCube
    for file in "${ioncube_files[@]}"; do
        download_file "${DOWNLOAD_BASE}/${file}"
    done

    sudo mkdir -p /usr/local/ioncube
    for file in "${ioncube_files[@]}"; do
        sudo cp -f "$file" /usr/local/ioncube/
        rm -f "$file"
    done

    # Configure PHP (CLI and FPM)
    local php_configs=("/etc/php/7.4/cli/php.ini" "/etc/php/7.4/fpm/php.ini")

    for config in "${php_configs[@]}"; do
        if ! grep -q "date.timezone" "$config"; then
            sudo sed -i '/\[Date\]/a date.timezone = Europe/Bucharest' "$config"
        fi
        sudo sed -i "s#date\.timezone = .*#date.timezone = ${TIMEZONE}#" "$config"
        sudo sed -i "s/upload_max_filesize = 2M/upload_max_filesize = 2048M/" "$config"
        sudo sed -i "s/post_max_size = 8M/post_max_size = 3072M/" "$config"
        sudo sed -i "s/max_execution_time = 30/max_execution_time = 600/" "$config"
        sudo sed -i "s/memory_limit = -1/memory_limit = 8192M/" "$config"
        sudo sed -i "s/memory_limit = 128M/memory_limit = 8192M/" "$config"
        sudo sed -i "s/short_open_tag = Off/short_open_tag = On/" "$config"
        if ! grep -q "zend_extension" "$config"; then
            echo "zend_extension=/usr/local/ioncube/${ioncube_files[0]}" | sudo tee -a "$config" >/dev/null
        fi
    done

    sudo sed -i "s/pm.max_children = 5/pm.max_children = 400/" /etc/php/7.4/fpm/pool.d/www.conf

    log_success "PHP configured"
}

step_configure_apache() {
    log_step "Configuring Apache"

    download_file "${DOWNLOAD_BASE}/000-default.conf"
    sudo cp -f 000-default.conf /etc/apache2/sites-available/
    rm -f 000-default.conf

    echo "ServerName localhost" | sudo tee /etc/apache2/conf-available/servername.conf >/dev/null
    sudo a2enconf servername

    sudo systemctl restart php7.4-fpm
    sudo systemctl restart apache2

    log_success "Apache configured"
}

step_configure_mysql() {
    log_step "Configuring MySQL"

    sudo mysqladmin -u root password "$METRICI_DB_PASS" 2>/dev/null || true
    sudo mysqladmin --user=root --password="$METRICI_DB_PASS" create "$METRICI_DB_NAME" 2>/dev/null || true

    # Download all SQL files
    local sql_files=(
        "metrici_db.sql"
        "metrici_ac.sql"
        "metrici_ac_update_4.0_to_4.1.sql"
        "metrici_ccr.sql"
        "metrici_ccr_update_4.0_to_4.1.sql"
        "metrici_cloud.sql"
        "metrici_eer.sql"
        "metrici_ext.sql"
        "metrici_general.sql"
        "metrici_general_update_4.0_to_4.1.sql"
        "metrici_lc.sql"
        "metrici_lpr.sql"
        "metrici_lpr_update_4.0_to_4.1.sql"
        "metrici_parking.sql"
        "metrici_parking_update_4.0_to_4.1.sql"
        "metrici_ppd.sql"
        "metrici_qr.sql"
        "metrici_ta.sql"
        "metrici_toll.sql"
        "metrici_vj.sql"
        "metrici_weighing.sql"
    )

    log_info "Downloading SQL files..."
    for sql_file in "${sql_files[@]}"; do
        download_file "${DOWNLOAD_BASE}/${sql_file}"
    done

    # Import SQL files
    log_info "Importing SQL files..."
    for sql_file in "${sql_files[@]}"; do
        if [[ -f "$sql_file" ]]; then
            log_info "Importing: $sql_file"
            sudo mysql --user=root --password="$METRICI_DB_PASS" --force "$METRICI_DB_NAME" < "$sql_file" 2>/dev/null || true
            rm -f "$sql_file"
        else
            log_warn "SQL file not found, skipping: $sql_file"
        fi
    done

    # Download and apply MySQL config
    download_file "${DOWNLOAD_BASE}/mysqld.cnf"
    sudo cp -f mysqld.cnf /etc/mysql/mysql.conf.d/
    rm -f mysqld.cnf

    sudo systemctl restart mysql

    log_success "MySQL configured"
}

step_configure_memcached() {
    log_step "Configuring Memcached"
    if ! grep -q "CACHESIZE" /etc/default/memcached 2>/dev/null; then
        echo "CACHESIZE=\"2048\"" | sudo tee -a /etc/default/memcached >/dev/null
    else
        # Update existing CACHESIZE
        sudo sed -i 's/CACHESIZE=.*/CACHESIZE="2048"/' /etc/default/memcached
    fi
    log_success "Memcached configured"
}

step_install_opencv() {
    log_step "Installing OpenCV"

    local opencv_packages=(
        "opencv-4.11.0-x86_64-dev.deb"
        "opencv-4.11.0-x86_64-libs.deb"
        "opencv-4.11.0-x86_64-licenses.deb"
        "opencv-4.11.0-x86_64-main.deb"
        "opencv-4.11.0-x86_64-python.deb"
        "opencv-4.11.0-x86_64-scripts.deb"
    )

    log_info "Downloading OpenCV packages..."
    for pkg in "${opencv_packages[@]}"; do
        download_file "${DOWNLOAD_BASE}/${pkg}" || {
            log_warn "Failed to download $pkg, will skip if missing"
        }
    done

    log_info "Installing OpenCV packages..."
    for pkg in "${opencv_packages[@]}"; do
        if [[ -f "$pkg" ]]; then
            log_info "Installing: $pkg"
            sudo apt-get install -y "./${pkg}" 2>/dev/null || {
                log_warn "Failed to install $pkg"
            }
            rm -f "$pkg"
        else
            log_warn "Package not downloaded, skipping: $pkg"
        fi
    done

    log_success "OpenCV installed"
}

step_install_metrici_files() {
    log_step "Installing Metrici files"

    mkdir -p "$METRICI_DIR" "$METRICI_OBJECTS_DIR"

    # Main executables
    local executables=("metrici-ac" "metrici-cpan" "metrici-lc" "metrici-lpr" \
        "metrici-lpr-plus" "metrici-ppd" "metrici-ccr" "metrici-qr")
    log_info "Downloading executables..."
    for exe in "${executables[@]}"; do
        download_file "${DOWNLOAD_BASE}/${exe}"
    done
    for exe in "${executables[@]}"; do
        if [[ -f "$exe" ]]; then
            cp -f "$exe" "$METRICI_DIR/"
            chmod +x "$METRICI_DIR/$exe"
            rm -f "$exe"
        else
            log_warn "Executable not found: $exe"
        fi
    done

    # Object files
    local objects=("objw.one" "objw.two" "objw.three" "objw.four" "objw.five" \
        "objw.six" "objw.seven" "objw.eight" "objw.nine" "objw.ten" \
        "objw.eleven" "objw.twelve" "objw.thirteen" "objw.zero")
    log_info "Downloading object files..."
    for obj in "${objects[@]}"; do
        download_file "${DOWNLOAD_BASE}/${obj}"
    done
    for obj in "${objects[@]}"; do
        if [[ -f "$obj" ]]; then
            cp -f "$obj" "$METRICI_OBJECTS_DIR/"
            rm -f "$obj"
        else
            log_warn "Object file not found: $obj"
        fi
    done

    # Configuration and helpers
    local configs=("lv.ini" "laser.wav" "metrici-win.zip")
    log_info "Downloading config files..."
    for cfg in "${configs[@]}"; do
        download_file "${DOWNLOAD_BASE}/${cfg}"
    done
    for cfg in "${configs[@]}"; do
        if [[ -f "$cfg" ]]; then
            cp -f "$cfg" "$METRICI_DIR/"
            rm -f "$cfg"
        else
            log_warn "Config file not found: $cfg"
        fi
    done

    # Scripts
    local delete_scripts=("metrici-ac-delete_events_after.sh" "start-metrici.sh" \
        "shmclear.sh" "metrici-shmclear.sh" \
        "metrici-send_jobs.sh" "metrici-watchdog.sh" \
        "metrici-ccr-delete_events_after.sh" "metrici-eer-delete_events_after.sh" \
        "metrici-lc-delete_events_after.sh" "metrici-lpr-delete_events_after.sh" \
        "metrici-ppd-delete_events_after.sh" "metrici-qr-delete_events_after.sh" \
        "metrici-ta-delete_events_after.sh" "metrici-vj-delete_events_after.sh")
    log_info "Downloading delete scripts..."
    for script in "${delete_scripts[@]}"; do
        download_file "${DOWNLOAD_BASE}/${script}"
    done
    for script in "${delete_scripts[@]}"; do
        if [[ -f "$script" ]]; then
            cp -f "$script" "$METRICI_DIR/"
            chmod +x "$METRICI_DIR/$script"
            rm -f "$script"
        else
            log_warn "Script not found: $script"
        fi
    done

    # Check alarms scripts
    local alarm_scripts=("metrici-ac-check_alarms.sh" "metrici-lc-check_alarms.sh" \
        "metrici-lpr-check_alarms.sh" "metrici-ppd-check_alarms.sh" \
        "metrici-ta-check_alarms.sh")
    log_info "Downloading alarm scripts..."
    for script in "${alarm_scripts[@]}"; do
        download_file "${DOWNLOAD_BASE}/${script}"
    done
    for script in "${alarm_scripts[@]}"; do
        if [[ -f "$script" ]]; then
            cp -f "$script" "$METRICI_DIR/"
            chmod +x "$METRICI_DIR/$script"
            rm -f "$script"
        else
            log_warn "Alarm script not found: $script"
        fi
    done

    # Trigger URLs script
    download_file "${DOWNLOAD_BASE}/metrici-lpr-trigger_parking_urls.sh"
    if [[ -f "metrici-lpr-trigger_parking_urls.sh" ]]; then
        cp -f metrici-lpr-trigger_parking_urls.sh "$METRICI_DIR/"
        chmod +x "$METRICI_DIR/metrici-lpr-trigger_parking_urls.sh"
        rm -f metrici-lpr-trigger_parking_urls.sh
    fi

    log_success "Metrici files installed"
}

step_configure_autostart() {
    log_step "Configuring autostart"

    cat > start-metrici.sh.desktop << EOF
[Desktop Entry]
Type=Application
Exec=${METRICI_DIR}/start-metrici.sh
Hidden=false
NoDisplay=false
X-GNOME-AutostartEnabled=true
Name=metrici
Comment=
EOF

    mkdir -p "$HOME_DIR/.config/autostart"
    cp -f start-metrici.sh.desktop "$HOME_DIR/.config/autostart/"
    rm -f start-metrici.sh.desktop

    log_success "Autostart configured"
}

step_install_license_system() {
    log_step "Installing license system"

    download_file "${DOWNLOAD_BASE}/aksusbd-10.13.1.tar.gz"
    tar -xzf aksusbd-10.13.1.tar.gz
    cd aksusbd-10.13.1
    sudo ./dinst
    cd ..
    rm -rf aksusbd-10.13.1 aksusbd-10.13.1.tar.gz

    log_success "License system installed"
}

step_install_pylon() {
    log_step "Installing Pylon SDK"

    download_file "${DOWNLOAD_BASE}/pylon5.tar.gz"
    sudo mkdir -p /usr/local/lib/pylon
    sudo tar --strip-components=1 -xzf pylon5.tar.gz -C /usr/local/lib/pylon
    sudo ldconfig

    download_file "${DOWNLOAD_BASE}/pylon.conf"
    sudo cp -f pylon.conf /etc/ld.so.conf.d/
    sudo ldconfig

    rm -f pylon5.tar.gz pylon.conf

    log_success "Pylon SDK installed"
}

step_install_web_interface() {
    log_step "Installing web interface"

    download_file "${DOWNLOAD_BASE}/metrici3.webi.tar.gz"
    sudo tar --strip-components=4 -xzf metrici3.webi.tar.gz -C /var/www/html
    sudo chown -R www-data:www-data /var/www/html

    sudo mkdir -p /var/www/metrici_storage
    sudo chown www-data:www-data /var/www/metrici_storage
    sudo chmod 777 /var/www/metrici_storage

    sudo rm -f /var/www/html/index.html
    rm -f metrici3.webi.tar.gz

    sudo mkdir -p /ramdisk
    if ! grep -q "/ramdisk" /etc/fstab 2>/dev/null; then
        echo "tmpfs /ramdisk tmpfs size=512M,noatime 0 0" | sudo tee -a /etc/fstab >/dev/null
    fi
    sudo systemctl daemon-reload
    sudo mount -a

    log_success "Web interface installed"
}

step_install_php_dependencies() {
    log_step "Installing PHP dependencies"

    local php_deps=("mdba.tar.gz" "mdb2.tar.gz" "driver-mysqli.tar.gz" "PHPMailer.tar.gz")

    log_info "Downloading PHP dependencies..."
    for dep in "${php_deps[@]}"; do
        download_file "${DOWNLOAD_BASE}/${dep}"
    done

    # Extract if files exist
    if [[ -f "mdba.tar.gz" ]]; then
        log_info "Extracting mdba.tar.gz..."
        sudo mkdir -p /usr/share/php
        sudo tar --strip-components=1 -xzf mdba.tar.gz -C /usr/share/php
        rm -f mdba.tar.gz
    fi

    if [[ -f "mdb2.tar.gz" ]]; then
        log_info "Extracting mdb2.tar.gz..."
        sudo mkdir -p /usr/share/php/MDB2
        sudo tar --strip-components=1 -xzf mdb2.tar.gz -C /usr/share/php/MDB2
        rm -f mdb2.tar.gz
    fi

    if [[ -f "driver-mysqli.tar.gz" ]]; then
        log_info "Extracting driver-mysqli.tar.gz..."
        sudo mkdir -p /usr/share/php
        sudo tar --strip-components=3 -xzf driver-mysqli.tar.gz -C /usr/share/php
        rm -f driver-mysqli.tar.gz
    fi

    if [[ -f "PHPMailer.tar.gz" ]]; then
        log_info "Extracting PHPMailer.tar.gz..."
        sudo mkdir -p /usr/share/php
        sudo tar -xzf PHPMailer.tar.gz -C /usr/share/php
        rm -f PHPMailer.tar.gz
    fi

    log_success "PHP dependencies installed"
}

step_install_cron_jobs() {
    log_step "Installing cron jobs"

    local cron_files=("cron-hourly-general.sh" "cron-daily-general.sh" \
        "cron-weekly-general.sh" "cron-monthly-general.sh" \
        "cron-hourly-ac.sh" "cron-hourly-lc.sh" "cron-hourly-ppd.sh")

    for file in "${cron_files[@]}"; do
        download_file "${DOWNLOAD_BASE}/${file}"
    done

    for file in "${cron_files[@]}"; do
        if [[ -f "$file" ]]; then
            chmod +x "$file"
        fi
    done

    sudo cp -f cron-hourly-general.sh /etc/cron.hourly/
    sudo cp -f cron-daily-general.sh /etc/cron.daily/
    sudo cp -f cron-weekly-general.sh /etc/cron.weekly/
    sudo cp -f cron-monthly-general.sh /etc/cron.monthly/
    sudo cp -f cron-hourly-ac.sh /etc/cron.hourly/
    sudo cp -f cron-hourly-lc.sh /etc/cron.hourly/
    sudo cp -f cron-hourly-ppd.sh /etc/cron.hourly/

    rm -f "${cron_files[@]}"

    log_success "Cron jobs installed"
}

step_install_teamviewer() {
    log_step "Installing TeamViewer"

    download_file "https://download.teamviewer.com/download/linux/teamviewer_amd64.deb"
    sudo apt-get install -y ./teamviewer_amd64.deb
    rm -f teamviewer_amd64.deb

    log_success "TeamViewer installed"
}

step_install_rustdesk() {
    log_step "Installing RustDesk"

    download_file "https://github.com/rustdesk/rustdesk/releases/download/1.4.9/rustdesk-1.4.9-x86_64.deb"
    sudo apt-get install -y ./rustdesk-1.4.9-x86_64.deb
    rm -f rustdesk-1.4.9-x86_64.deb

    log_success "RustDesk installed"
}

step_configure_firewall() {
    log_step "Configuring firewall"
    sudo systemctl stop ufw
    sudo systemctl disable ufw
    log_success "Firewall disabled"
}

step_final_update() {
    log_step "Final system update"
    sudo apt update -y
    sudo apt upgrade -y
    log_success "System updated"
}

# =============================================================================
# Summary Report
# =============================================================================

generate_summary_report() {
    local report_file="${SCRIPT_DIR}/install-report.txt"
    local log_file="${SCRIPT_DIR}/install.log"

    echo "" >&4
    echo -e "${BOLD}==========================================${NC}" >&4
    echo -e "${BOLD}     Metrici Installation Summary${NC}" >&4
    echo -e "${BOLD}==========================================${NC}" >&4
    echo "" >&4

    local success_count=0
    local failed_count=0
    local skipped_count=0
    local total_count=${#STEP_ORDER[@]}

    for step in "${STEP_ORDER[@]}"; do
        local status="${STEP_STATUS[$step]:-unknown}"
        local critical="${STEP_CRITICAL[$step]:-false}"
        local critical_tag=""
        local display_name
        display_name=$(step_display_name "$step")
        [[ "$critical" == "true" ]] && critical_tag=" [CRITICAL]"

        case "$status" in
            success)
                echo -e "  ${GREEN}[✓]${NC} $display_name${critical_tag}" >&4
                success_count=$((success_count + 1))
                ;;
            failed)
                echo -e "  ${RED}[✗]${NC} $display_name${critical_tag}" >&4
                failed_count=$((failed_count + 1))
                ;;
            skipped)
                echo -e "  ${YELLOW}[−]${NC} $display_name${critical_tag} (skipped - already done)" >&4
                skipped_count=$((skipped_count + 1))
                ;;
            *)
                echo -e "  ${RED}[?]${NC} $display_name${critical_tag} (status: $status)" >&4
                failed_count=$((failed_count + 1))
                ;;
        esac
    done

    echo "" >&4
    echo -e "${BOLD}Results:${NC}" >&4
    echo -e "  Total:   $total_count" >&4
    echo -e "  ${GREEN}Success: $success_count${NC}" >&4
    echo -e "  ${RED}Failed:  $failed_count${NC}" >&4
    echo -e "  ${YELLOW}Skipped: $skipped_count${NC}" >&4
    echo "" >&4

    # Also write to file
    {
        echo "=========================================="
        echo "Metrici Installation Report"
        echo "=========================================="
        echo "Date: $(date '+%Y-%m-%d %H:%M:%S')"
        echo "Hostname: $(hostname)"
        echo "User: $(whoami)"
        echo "System: $(uname -a)"
        echo ""
        echo "Configuration:"
        echo "  - Metrici Directory: ${METRICI_DIR}"
        echo "  - Database: ${METRICI_DB_NAME}"
        echo "  - Timezone: ${TIMEZONE}"
        echo ""
        echo "Installed Components:"
        echo "  - GPU Drivers: $(lspci | grep -E 'VGA|3D' | head -1 || echo 'Not detected')"
        echo "  - Apache: $(apache2 -v 2>/dev/null | grep 'Apache' || echo 'Not installed')"
        echo "  - PHP: $(php -v 2>/dev/null | head -1 || echo 'Not installed')"
        echo "  - MySQL: $(mysql --version 2>/dev/null || echo 'Not installed')"
        echo "  - OpenCV: $(pkg-config --modversion opencv4 2>/dev/null || echo 'Not installed')"
        echo ""
        echo "Steps:"
        for step in "${STEP_ORDER[@]}"; do
            local status="${STEP_STATUS[$step]:-unknown}"
            local display_name
            display_name=$(step_display_name "$step")
            echo "  - $display_name: $status"
        done
        echo ""
        echo "Results: $success_count/$total_count successful"
        echo "=========================================="
    } > "$report_file"

    # Also save detailed log
    cp "$STATE_FILE" "$log_file" 2>/dev/null || true

    log_info "Report saved to: $report_file"
    log_info "State saved to: $STATE_FILE"

    if [[ $failed_count -gt 0 ]]; then
        echo "" >&4
        echo -e "${RED}${BOLD}Some steps failed!${NC}" >&4
        echo -e "Use ${BOLD}${SCRIPT_NAME} --resume${NC} to retry failed steps" >&4
        return 1
    fi

    echo "" >&4
    echo -e "${GREEN}${BOLD}==========================================${NC}" >&4
    echo -e "${GREEN}${BOLD}  Installation completed successfully!${NC}" >&4
    echo -e "${GREEN}${BOLD}==========================================${NC}" >&4
    echo "" >&4
    echo -e "Please ${BOLD}reboot${NC} the system." >&4
    echo "" >&4
    return 0
}

# =============================================================================
# Execute Single Step
# =============================================================================

execute_step() {
    local step_name="$1"
    local step_num="$2"
    local display_name
    display_name=$(step_display_name "$step_name")

    CURRENT_STEP=$step_num

    # Start spinner showing current step
    start_spinner "$display_name"

    # Save terminal fd 4 to fd 5, then redirect fd 4 to verbose log
    # During step execution, ALL output (including log_* messages) goes to log
    # Only the spinner remains visible on terminal
    exec 5>&4
    exec 4>>"$VERBOSE_LOG"

    local step_result=0
    "$step_name" >> "$VERBOSE_LOG" 2>&1 || step_result=$?

    # Restore fd 4 to terminal
    exec 4>&5
    exec 5>&-

    # Stop spinner
    stop_spinner

    if [[ $step_result -ne 0 ]]; then
        update_step_status "$step_name" "failed"

        if is_step_critical "$step_name"; then
            FAILED_CRITICAL="$display_name"
            show_step_result "$step_num" "$display_name" "$TOTAL_STEPS" "failed"
            close_progress_bar
            return 1
        else
            show_step_result "$step_num" "$display_name" "$TOTAL_STEPS" "failed"
            log_warn "Non-critical step failed, continuing: $display_name"
        fi
    else
        update_step_status "$step_name" "success"
        show_step_result "$step_num" "$display_name" "$TOTAL_STEPS" "success"
    fi

    return 0
}

# =============================================================================
# Main
# =============================================================================

main() {
    # Set up file descriptors:
    # fd 4 = terminal (for our log messages)
    # stdout/stderr will be redirected to log file during steps
    exec 4>&1

    # Initialize verbose log
    : > "$VERBOSE_LOG"

    # Parse arguments
    local resume=false
    for arg in "$@"; do
        case "$arg" in
            --resume) resume=true ;;
            --help)
                echo "Usage: $0 [OPTIONS]" >&4
                echo "" >&4
                echo "Options:" >&4
                echo "  --resume  Resume installation from last successful step" >&4
                echo "  --help    Show this help message" >&4
                exit 0
                ;;
            *)
                log_error "Unknown option: $arg"
                echo "Use --help for usage information" >&4
                exit 1
                ;;
        esac
    done

    # Display header
    echo "" >&4
    echo -e "${BOLD}${CYAN}╔══════════════════════════════════════════╗${NC}" >&4
    echo -e "${BOLD}${CYAN}║   Metrici Ubuntu 24.04 Installer v4.1   ║${NC}" >&4
    echo -e "${BOLD}${CYAN}╚══════════════════════════════════════════╝${NC}" >&4
    echo "" >&4

    # Detect if running as root
    if [[ "$(id -u)" -eq 0 ]]; then
        IS_ROOT=true
        log_info "Running as root, sudo not required"
        # Override sudo to be a pass-through when running as root
        sudo() {
            "$@"
        }
    else
        IS_ROOT=false
        log_info "Running as user $(whoami), sudo will be used for privileged operations"
        log_info "Requesting sudo credentials..."
        sudo -v

        # Start sudo keepalive
        while true; do
            sudo -n true 2>/dev/null
            sleep 60
            kill -0 $$ 2>/dev/null || exit
        done &
        SUDO_KEEPALIVE_PID=$!
    fi

    # Initialize
    init_state_file
    load_state
    INSTALL_START_TIME="$(date -Iseconds)"

    # Register all steps (name, critical?)
    register_step "step_validate_dependencies" "true"
    register_step "step_configure_gpu_drivers" "false"
    register_step "step_setup_system_packages" "true"
    register_step "step_configure_php" "true"
    register_step "step_configure_apache" "true"
    register_step "step_configure_mysql" "true"
    register_step "step_configure_memcached" "false"
    register_step "step_install_opencv" "true"
    register_step "step_install_metrici_files" "true"
    register_step "step_configure_autostart" "false"
    register_step "step_install_license_system" "true"
    register_step "step_install_pylon" "true"
    register_step "step_install_web_interface" "true"
    register_step "step_install_php_dependencies" "true"
    register_step "step_install_cron_jobs" "false"
    register_step "step_install_teamviewer" "false"
    register_step "step_install_rustdesk" "false"
    register_step "step_configure_firewall" "false"
    register_step "step_final_update" "false"

    TOTAL_STEPS=${#STEP_ORDER[@]}

    # Display plan
    log_info "Total steps: $TOTAL_STEPS"
    if [[ "$resume" == "true" ]]; then
        log_info "Resuming from last successful step"
    fi
    echo "" >&4

    # Initialize progress bar
    init_progress_bar

    # Execute steps
    local step_num=0
    for step_name in "${STEP_ORDER[@]}"; do
        step_num=$((step_num + 1))

        # Check if we can skip (already succeeded)
        if should_skip_step "$step_name"; then
            local display_name
            display_name=$(step_display_name "$step_name")
            show_step_result "$step_num" "$display_name" "$TOTAL_STEPS" "skipped"
            update_step_status "$step_name" "skipped"
            continue
        fi

        # Execute step
        if ! execute_step "$step_name" "$step_num"; then
            # Critical step failed
            break
        fi
    done

    # Close progress bar
    close_progress_bar
    echo ""

    # Write final state file
    write_state_file "$INSTALL_START_TIME" "$(date -Iseconds)"

    # Generate report
    generate_summary_report
}

main "$@"
