#!/usr/bin/env bash
# ============================================================================
# qcrows-initrd-regen — Environment-aware initrd/ramfs/cramfs regeneration
#
# Rebuilds the initrd component of a QCrows bundle with precise awareness
# of the Kata Containers runtime environment. Unlike dracut or mkinitramfs,
# this script produces an initrd where kata-agent IS the final process
# (no pivot_root, no switch_root) and includes ONLY the kernel modules
# required by the detected VMM transport layer.
#
# Usage:
#   qcrows-initrd-regen image.qcrows [options]
#   qcrows-initrd-regen image.qcrows --vmm qemu --compress lz4 -o new-initrd.img
#   qcrows-initrd-regen image.qcrows --in-place
#
# Environment detection (automatic when --vmm is not specified):
#   1. Reads /etc/kata-containers/configuration.toml or the path in
#      KATA_CFG to determine the active hypervisor profile.
#   2. Inspects the QCrows bundle's kernel/.config to determine which
#      compression algorithms the guest kernel supports.
#   3. Examines the rootfs to detect init system type (systemd, OpenRC,
#      busybox /init) and locate the kata-agent binary.
#   4. Detects host architecture for correct module paths.
#
# Output formats:
#   cpio-gzip   — gzip-compressed cpio (default, universal)
#   cpio-lz4    — lz4-compressed cpio (fastest boot, kernel must support)
#   cpio-xz     — xz-compressed cpio (smallest size, slowest boot)
#   cpio-zstd   — zstd-compressed cpio (balanced, kernel 5.15+)
#   cramfs      — cramfs filesystem (read-only, extremely minimal)
# ============================================================================
set -euo pipefail

# ─── Version ────────────────────────────────────────────────────────────────
VERSION="0.1.0"

# ─── Colors ─────────────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BLUE='\033[0;34m'
NC='\033[0m'

log()   { echo -e "${GREEN}[initrd-regen]${NC} $*"; }
warn()  { echo -e "${YELLOW}[initrd-regen]${NC} WARNING: $*"; }
error() { echo -e "${RED}[initrd-regen]${NC} ERROR: $*" >&2; }
die()   { error "$@"; exit 1; }

# ─── Defaults ───────────────────────────────────────────────────────────────
INPUT=""
OUTPUT=""
VMM=""                # auto-detected from kata config if empty
COMPRESS=""           # auto-detected from kernel config if empty
FORMAT=""             # cpio-gzip, cpio-lz4, cpio-xz, cpio-zstd, cramfs
AGENT_PATH=""         # auto-discovered from rootfs if empty
INIT_STYLE=""         # auto-detected: systemd, openrc, busybox
IN_PLACE=false
KEEP_TEMP=false
STRIP_LOCALES=true
STRIP_DOCS=true
STRIP_MAN=true
EXTRA_MODULES=""      # comma-separated additional kernel modules
EXCLUDE_MODULES=""    # comma-separated modules to exclude
KATA_CFG=""           # path to configuration.toml (auto-detected if empty)
VERBOSE=false
KERNEL_MODULES_DIR="" # auto-discovered from bundle kernel version

# ─── Temp directory ────────────────────────────────────────────────────────
TMPDIR=""
cleanup() {
  if [[ -n "$TMPDIR" && -d "$TMPDIR" && "$KEEP_TEMP" == "false" ]]; then
    rm -rf "$TMPDIR"
  elif [[ -n "$TMPDIR" && -d "$TMPDIR" && "$KEEP_TEMP" == "true" ]]; then
    log "Temp directory preserved: ${TMPDIR}"
  fi
}
trap cleanup EXIT

# ============================================================================
# VMM Kernel Module Matrix
# ============================================================================
# Each VMM requires a specific set of virtio transports and guest drivers.
# This table drives module selection — no nested ifs, just array lookup.
#
# Format: VMM:required_modules:optional_modules
#   required  — MUST be included for the VMM to function
#   optional  — included only if present in the kernel and not excluded

declare -A VMM_REQUIRED_MODULES
declare -A VMM_OPTIONAL_MODULES

VMM_REQUIRED_MODULES[qemu]="virtio_pci virtio_blk virtio_net virtio_rng virtio_balloon virtio_console virtio_gpu"
VMM_OPTIONAL_MODULES[qemu]="virtio_scsi virtio_input virtio_crypto virtio_mem virtio_pmem 9pnet_virtio"

VMM_REQUIRED_MODULES[cloud-hypervisor]="virtio_mmio virtio_blk virtio_net virtio_rng virtio_console virtio_balloon"
VMM_OPTIONAL_MODULES[cloud-hypervisor]="virtio_gpu virtio_scsi 9pnet_virtio"

VMM_REQUIRED_MODULES[firecracker]="virtio_mmio virtio_blk virtio_net virtio_rng"
VMM_OPTIONAL_MODULES[firecracker]="virtio_console"

VMM_REQUIRED_MODULES[dragonball]="virtio_blk virtio_net virtio_rng virtio_console"
VMM_OPTIONAL_MODULES[dragonball]="virtio_balloon virtio_gpu 9pnet_virtio"

# Core modules needed regardless of VMM — filesystem and device infrastructure
CORE_MODULES="ext4 vfat nls_cp437 nls_iso8859_1 dm_mod dm_bufio loop squashfs overlay"

# ============================================================================
# Compression detection from kernel .config
# ============================================================================
# The guest kernel must be compiled with support for the chosen initrd
# compression algorithm. These config symbols determine what works.

declare -A COMPRESS_CONFIG_MAP
COMPRESS_CONFIG_MAP[cpio-gzip]="CONFIG_RD_GZIP"
COMPRESS_CONFIG_MAP[cpio-lz4]="CONFIG_RD_LZ4"
COMPRESS_CONFIG_MAP[cpio-xz]="CONFIG_RD_XZ"
COMPRESS_CONFIG_MAP[cpio-zstd]="CONFIG_RD_ZSTD"

# Compression commands: how to compress the cpio stream
declare -A COMPRESS_CMD
COMPRESS_CMD[cpio-gzip]="gzip -9"
COMPRESS_CMD[cpio-lz4]="lz4 -l"
COMPRESS_CMD[cpio-xz]="xz -9 --check=crc32"
COMPRESS_CMD[cpio-zstd]="zstd -19"

# Compression file extensions
declare -A COMPRESS_EXT
COMPRESS_EXT[cpio-gzip]=".img"
COMPRESS_EXT[cpio-lz4]=".cpio.lz4"
COMPRESS_EXT[cpio-xz]=".cpio.xz"
COMPRESS_EXT[cpio-zstd]=".cpio.zst"

# Priority order for auto-detection (fastest boot first)
COMPRESS_PRIORITY=("cpio-lz4" "cpio-zstd" "cpio-gzip" "cpio-xz")

# ============================================================================
# Kata configuration.toml VMM detection
# ============================================================================
# Maps hypervisor entries in configuration.toml to our VMM identifiers.

declare -A CFG_HYPERVISOR_MAP
CFG_HYPERVISOR_MAP[qemu]="qemu"
CFG_HYPERVISOR_MAP[cloud-hypervisor]="cloud-hypervisor"
CFG_HYPERVISOR_MAP[clh]="cloud-hypervisor"
CFG_HYPERVISOR_MAP[firecracker]="firecracker"
CFG_HYPERVISOR_MAP[fc]="firecracker"
CFG_HYPERVISOR_MAP[dragonball]="dragonball"

# ============================================================================
# Usage
# ============================================================================
usage() {
  cat <<EOF
qcrows-initrd-regen v${VERSION} — Environment-aware initrd regeneration for Kata Containers

USAGE:
  qcrows-initrd-regen QCROWS_FILE [OPTIONS]

REQUIRED:
  QCROWS_FILE             Path to .qcrows archive

VMM SELECTION (auto-detected from kata config if not specified):
  --vmm VMM               Target VMM: qemu|cloud-hypervisor|firecracker|dragonball
  --kata-cfg FILE         Path to configuration.toml (default: auto-detect)

OUTPUT:
  -o, --output FILE       Output initrd file path (default: kata-initrd.img in cwd)
  --in-place              Replace the initrd inside the QCrows bundle
  --format FORMAT         Force output format: cpio-gzip|cpio-lz4|cpio-xz|cpio-zstd|cramfs
  --compress ALGO         Shorthand: gzip|lz4|xz|zstd (sets format to cpio-\$ALGO)

INITRD CONTENT:
  --agent PATH            Path to kata-agent binary (default: extract from rootfs)
  --init-style STYLE      Init system: systemd|openrc|busybox (default: auto-detect)
  --extra-modules LIST    Comma-separated additional kernel modules to include
  --exclude-modules LIST  Comma-separated kernel modules to exclude

OPTIMIZATION:
  --no-strip-locales      Keep locale files in initrd
  --no-strip-docs         Keep documentation files
  --no-strip-man          Keep man pages
  --keep-temp             Preserve temp directory for inspection

GENERAL:
  -v, --verbose           Verbose output
  -h, --help              Show this help
  --version               Show version

ENVIRONMENT:
  KATA_CFG                Default path to configuration.toml

AUTO-DETECTION:
  When --vmm is not specified, the script reads configuration.toml
  to determine the active hypervisor. When --compress is not specified,
  it reads the bundled kernel/.config to find the fastest algorithm
  the guest kernel supports.

  When --init-style is not specified, the script examines the rootfs
  to detect the init system:
    - /sbin/init → systemd → systemd init style
    - /sbin/openrc-init → OpenRC → openrc init style
    - Neither → busybox /init style (kata-agent as PID 1)

EXAMPLES:
  # Auto-detect everything, output to cwd
  qcrows-initrd-regen alpine-3.20-kata.qcrows

  # Target QEMU with lz4 compression
  qcrows-initrd-regen alpine.qcrows --vmm qemu --compress lz4

  # Update the bundle in-place
  qcrows-initrd-regen alpine.qcrows --in-place --vmm cloud-hypervisor

  # Custom agent binary and extra modules
  qcrows-initrd-regen gentoo.qcrows --agent /usr/bin/kata-agent \\
    --extra-modules "tun,veth,bridge" -o custom-initrd.img

  # Inspect what would be included without building
  qcrows-initrd-regen alpine.qcrows --keep-temp --verbose
EOF
}

# ============================================================================
# Parse Arguments
# ============================================================================
parse_args() {
  local positional_count=0
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --vmm)             VMM="$2"; shift 2 ;;
      --kata-cfg)        KATA_CFG="$2"; shift 2 ;;
      -o|--output)       OUTPUT="$2"; shift 2 ;;
      --in-place)        IN_PLACE=true; shift ;;
      --format)          FORMAT="$2"; shift 2 ;;
      --compress)        FORMAT="cpio-${2}"; shift 2 ;;
      --agent)           AGENT_PATH="$2"; shift 2 ;;
      --init-style)      INIT_STYLE="$2"; shift 2 ;;
      --extra-modules)   EXTRA_MODULES="$2"; shift 2 ;;
      --exclude-modules) EXCLUDE_MODULES="$2"; shift 2 ;;
      --no-strip-locales) STRIP_LOCALES=false; shift ;;
      --no-strip-docs)    STRIP_DOCS=false; shift ;;
      --no-strip-man)     STRIP_MAN=false; shift ;;
      --keep-temp)        KEEP_TEMP=true; shift ;;
      -v|--verbose)       VERBOSE=true; shift ;;
      -h|--help)          usage; exit 0 ;;
      --version)          echo "qcrows-initrd-regen v${VERSION}"; exit 0 ;;
      -*)                 die "Unknown option: $1 (use --help)" ;;
      *)
        positional_count=$((positional_count + 1))
        case "$positional_count" in
          1) INPUT="$1" ;;
          *) die "Unexpected positional argument: $1" ;;
        esac
        shift
        ;;
    esac
  done
}

# ============================================================================
# Validation (array-driven)
# ============================================================================
validate_inputs() {
  [[ -z "$INPUT" ]] && die "QCrows file is required. Usage: qcrows-initrd-regen <file.qcrows> [options]"
  [[ ! -f "$INPUT" ]] && die "File not found: ${INPUT}"

  # Validate --vmm value against known VMMs
  local -a known_vmms=("qemu" "cloud-hypervisor" "firecracker" "dragonball")
  if [[ -n "$VMM" ]]; then
    local vmm_valid=false
    local known
    for known in "${known_vmms[@]}"; do
      [[ "$VMM" == "$known" ]] && { vmm_valid=true; break; }
    done
    [[ "$vmm_valid" == "false" ]] && die "Unknown VMM: ${VMM}. Supported: ${known_vmms[*]}"
  fi

  # Validate --init-style
  local -a known_init_styles=("systemd" "openrc" "busybox")
  if [[ -n "$INIT_STYLE" ]]; then
    local style_valid=false
    local known
    for known in "${known_init_styles[@]}"; do
      [[ "$INIT_STYLE" == "$known" ]] && { style_valid=true; break; }
    done
    [[ "$style_valid" == "false" ]] && die "Unknown init style: ${INIT_STYLE}. Supported: ${known_init_styles[*]}"
  fi

  # Validate --format
  local -a known_formats=("cpio-gzip" "cpio-lz4" "cpio-xz" "cpio-zstd" "cramfs")
  if [[ -n "$FORMAT" ]]; then
    local fmt_valid=false
    local known
    for known in "${known_formats[@]}"; do
      [[ "$FORMAT" == "$known" ]] && { fmt_valid=true; break; }
    done
    [[ "$fmt_valid" == "false" ]] && die "Unknown format: ${FORMAT}. Supported: ${known_formats[*]}"
  fi

  # Validate --agent path if specified
  if [[ -n "$AGENT_PATH" ]]; then
    [[ ! -f "$AGENT_PATH" ]] && die "Agent binary not found: ${AGENT_PATH}"
    [[ ! -x "$AGENT_PATH" ]] && die "Agent binary not executable: ${AGENT_PATH}"
  fi

  # In-place requires output to be empty
  [[ "$IN_PLACE" == "true" && -n "$OUTPUT" ]] && die "Cannot use --in-place and --output together"

  # cramfs format cannot be used in-place (different structure)
  [[ "$IN_PLACE" == "true" && "$FORMAT" == "cramfs" ]] && die "cramfs format is not supported with --in-place (use cpio format instead)"
}

# ============================================================================
# Extract QCrows bundle
# ============================================================================
extract_qcrows() {
  local archive="$1"
  local dest="$2"

  log "Extracting QCrows bundle: $(basename "$archive")"
  mkdir -p "$dest"

  # Detect compression and extract
  case "$archive" in
    *.gz|*.qcrows.gz|*.tar.gz)
      tar -xzf "$archive" -C "$dest"
      ;;
    *)
      # Try gzip first, then uncompressed
      if tar -tzf "$archive" &>/dev/null; then
        tar -xzf "$archive" -C "$dest"
      else
        tar -xf "$archive" -C "$dest"
      fi
      ;;
  esac

  # Verify required components exist
  local -a required_files=("metadata.toml" "rootfs.tar.gz" "kernel/")
  local req
  for req in "${required_files[@]}"; do
    [[ -e "${dest}/${req}" ]] || die "Missing required component in bundle: ${req}"
  done

  # Verify kernel binary exists
  local kernel_found=false
  [[ -f "${dest}/kernel/vmlinuz" ]] && kernel_found=true
  [[ -f "${dest}/kernel/vmlinux" ]] && kernel_found=true
  [[ "$kernel_found" == "false" ]] && die "No kernel binary found in bundle (expected kernel/vmlinuz or kernel/vmlinux)"

  # Verify kernel config exists (QCrows v0.2 requirement)
  [[ -f "${dest}/kernel/config" ]] || die "No kernel config found in bundle — required for env-aware module selection"

  log "Bundle extracted to: ${dest}"
}

# ============================================================================
# Auto-detect VMM from kata configuration.toml
# ============================================================================
detect_vmm() {
  [[ -n "$VMM" ]] && return

  log "Auto-detecting VMM from Kata configuration..."

  # Candidate configuration.toml paths
  local -a cfg_candidates=(
    "${KATA_CFG:-}"
    "/etc/kata-containers/configuration.toml"
    "/usr/share/defaults/kata-containers/configuration.toml"
    "/usr/share/kata-containers/configuration.toml"
    "/opt/kata/share/defaults/kata-containers/configuration.toml"
  )

  local cfg_path=""
  local candidate
  for candidate in "${cfg_candidates[@]}"; do
    [[ -n "$candidate" && -f "$candidate" ]] && { cfg_path="$candidate"; break; }
  done

  if [[ -z "$cfg_path" ]]; then
    warn "No configuration.toml found — defaulting to qemu"
    VMM="qemu"
    return
  fi

  log "Found configuration: ${cfg_path}"

  # Extract the hypervisor type from configuration.toml.
  # The active hypervisor section is identified by the [hypervisor.qemu] /
  # [hypervisor.cloud-hypervisor] / etc. section headers.
  # The default runtime determines which section is active.

  local runtime_link=""
  if [[ -L "/usr/bin/kata-runtime" ]]; then
    runtime_link="$(readlink -f /usr/bin/kata-runtime 2>/dev/null || true)"
  fi

  # Check kata-runtime symlink naming convention
  local -a runtime_vmm_map=(
    "kata-qemu:qemu"
    "kata-clh:cloud-hypervisor"
    "kata-cloud-hypervisor:cloud-hypervisor"
    "kata-fc:firecracker"
    "kata-firecracker:firecracker"
    "kata-dragonball:dragonball"
  )

  local entry pattern vmm_id
  for entry in "${runtime_vmm_map[@]}"; do
    pattern="${entry%%:*}"
    vmm_id="${entry##*:}"
    if [[ "$runtime_link" == *"$pattern"* ]]; then
      VMM="$vmm_id"
      log "Detected VMM from runtime symlink: ${VMM}"
      return
    fi
  done

  # Fallback: parse configuration.toml for the first hypervisor section
  local -a section_patterns=("qemu" "cloud-hypervisor" "clh" "firecracker" "fc" "dragonball")
  local sect
  for sect in "${section_patterns[@]}"; do
    if grep -q "\\[hypervisor\\.${sect}\\]" "$cfg_path" 2>/dev/null; then
      VMM="${CFG_HYPERVISOR_MAP[$sect]:-$sect}"
      log "Detected VMM from config section: ${VMM}"
      return
    fi
  done

  # Check which runtime is actually active via kata-runtime
  local kata_runtime
  kata_runtime="$(which kata-runtime 2>/dev/null || true)"
  if [[ -n "$kata_runtime" ]]; then
    local runtime_info
    runtime_info="$("$kata_runtime" --version 2>/dev/null | head -1 || true)"
    [[ "$VERBOSE" == "true" ]] && log "kata-runtime version: ${runtime_info}"
  fi

  warn "Could not determine active VMM — defaulting to qemu"
  VMM="qemu"
}

# ============================================================================
# Auto-detect compression from kernel .config
# ============================================================================
detect_compression() {
  [[ -n "$FORMAT" && "$FORMAT" != "cramfs" ]] && return

  log "Auto-detecting compression from kernel config..."

  local kernel_config="${EXTRACT_DIR}/kernel/config"
  [[ ! -f "$kernel_config" ]] && { warn "No kernel config available — defaulting to gzip"; FORMAT="${FORMAT:-cpio-gzip}"; return; }

  # Check each compression algorithm in priority order
  local algo config_key
  for algo in "${COMPRESS_PRIORITY[@]}"; do
    config_key="${COMPRESS_CONFIG_MAP[$algo]:-}"
    [[ -z "$config_key" ]] && continue

    if grep -q "^${config_key}=y" "$kernel_config" 2>/dev/null; then
      FORMAT="$algo"
      log "Kernel supports ${algo##*-} — selected as optimal compression"
      return
    fi
  done

  # No supported compression found in kernel config — this should not happen
  warn "No initrd compression support detected in kernel config — defaulting to gzip"
  FORMAT="${FORMAT:-cpio-gzip}"
}

# ============================================================================
# Auto-detect init style from rootfs
# ============================================================================
detect_init_style() {
  [[ -n "$INIT_STYLE" ]] && return

  log "Auto-detecting init system from rootfs..."

  local rootfs_dir="${EXTRACT_DIR}/rootfs-extracted"
  mkdir -p "$rootfs_dir"

  # Extract just enough of the rootfs to detect init system.
  # We only need the directory listing, not the full content.
  tar -tzf "${EXTRACT_DIR}/rootfs.tar.gz" 2>/dev/null | head -500 > "${TMPDIR}/rootfs-listing.txt"

  if grep -q "sbin/init$\|sbin/systemd$" "${TMPDIR}/rootfs-listing.txt"; then
    INIT_STYLE="systemd"
    log "Detected init system: systemd"
  elif grep -q "sbin/openrc-init$" "${TMPDIR}/rootfs-listing.txt"; then
    INIT_STYLE="openrc"
    log "Detected init system: OpenRC"
  else
    INIT_STYLE="busybox"
    log "Detected init system: busybox (kata-agent as PID 1)"
  fi
}

# ============================================================================
# Discover kata-agent in rootfs
# ============================================================================
discover_agent() {
  [[ -n "$AGENT_PATH" && -f "$AGENT_PATH" ]] && return

  log "Discovering kata-agent in rootfs..."

  local listing="${TMPDIR}/rootfs-listing.txt"

  # Agent candidate paths in the rootfs
  local -a agent_candidates=(
    "usr/bin/kata-agent"
    "usr/local/bin/kata-agent"
    "usr/sbin/kata-agent"
    "sbin/kata-agent"
  )

  local candidate
  for candidate in "${agent_candidates[@]}"; do
    if grep -q "^\\./${candidate}$\\|^${candidate}$" "$listing" 2>/dev/null; then
      AGENT_PATH="${EXTRACT_DIR}/rootfs-extracted/${candidate}"
      log "Found kata-agent at: /${candidate}"
      return
    fi
  done

  die "kata-agent not found in rootfs. Specify path with --agent"
}

# ============================================================================
# Extract rootfs for initrd building
# ============================================================================
extract_rootfs() {
  local rootfs_dir="${EXTRACT_DIR}/rootfs-extracted"
  [[ -d "$rootfs_dir" && -f "${rootfs_dir}/init" ]] && return

  log "Extracting rootfs for initrd assembly..."
  mkdir -p "$rootfs_dir"
  tar -xzf "${EXTRACT_DIR}/rootfs.tar.gz" -C "$rootfs_dir" 2>/dev/null || \
    tar -xf "${EXTRACT_DIR}/rootfs.tar.gz" -C "$rootfs_dir" 2>/dev/null || \
    die "Failed to extract rootfs"

  log "Rootfs extracted: $(du -sh "$rootfs_dir" | cut -f1)"
}

# ============================================================================
# Resolve kernel module paths
# ============================================================================
resolve_kernel_modules() {
  log "Resolving kernel modules for VMM: ${VMM}"

  local kernel_config="${EXTRACT_DIR}/kernel/config"

  # Determine kernel version from the bundled kernel
  local kernel_version
  kernel_version="$(strings "${EXTRACT_DIR}/kernel/vmlinuz" "${EXTRACT_DIR}/kernel/vmlinux" 2>/dev/null \
    | grep -oP '^\d+\.\d+\.\d+' | head -1 || true)"

  if [[ -z "$kernel_version" ]]; then
    # Fallback: extract from kernel config
    kernel_version="$(grep "^CONFIG_VERSION_SIGNATURE=" "$kernel_config" 2>/dev/null \
      | grep -oP '\d+\.\d+\.\d+' | head -1 || true)"
  fi

  if [[ -z "$kernel_version" ]]; then
    warn "Could not determine kernel version — module inclusion will be name-only"
  else
    log "Kernel version: ${kernel_version}"
  fi

  # Build the complete module list from the matrix
  local -a required_modules=()
  local -a optional_modules=()

  # Core modules (always needed)
  local core
  for core in $CORE_MODULES; do
    required_modules+=("$core")
  done

  # VMM-specific required modules
  local vmm_req="${VMM_REQUIRED_MODULES[$VMM]:-}"
  local mod
  for mod in $vmm_req; do
    required_modules+=("$mod")
  done

  # VMM-specific optional modules (only if compiled in kernel)
  local vmm_opt="${VMM_OPTIONAL_MODULES[$VMM]:-}"
  for mod in $vmm_opt; do
    # Check if the module is compiled (=y or =m) in the kernel config
    local config_name="CONFIG_${mod^^}"
    if grep -q "^${config_name}=y\\|^${config_name}=m" "$kernel_config" 2>/dev/null; then
      optional_modules+=("$mod")
    fi
  done

  # Extra modules from --extra-modules
  if [[ -n "$EXTRA_MODULES" ]]; then
    IFS=',' read -ra extra_arr <<< "$EXTRA_MODULES"
    for mod in "${extra_arr[@]}"; do
      [[ -n "$mod" ]] && required_modules+=("$mod")
    done
  fi

  # Apply exclusion list from --exclude-modules
  local -a exclude_arr=()
  if [[ -n "$EXCLUDE_MODULES" ]]; then
    IFS=',' read -ra exclude_arr <<< "$EXCLUDE_MODULES"
  fi

  # Final module list (deduplicated, exclusions applied)
  local -A module_set=()
  local m
  for m in "${required_modules[@]}" "${optional_modules[@]}"; do
    local excluded=false
    local ex
    for ex in "${exclude_arr[@]}"; do
      [[ "$m" == "$ex" ]] && { excluded=true; break; }
    done
    [[ "$excluded" == "false" ]] && module_set[$m]=1
  done

  # Store final module list
  FINAL_MODULES=()
  for m in "${!module_set[@]}"; do
    FINAL_MODULES+=("$m")
  done

  log "Module list (${#FINAL_MODULES[@]} modules): ${FINAL_MODULES[*]}"
  KERNEL_VERSION="$kernel_version"
}

# ============================================================================
# Copy kernel modules from rootfs
# ============================================================================
copy_kernel_modules() {
  local initrd_root="$1"
  local rootfs_dir="${EXTRACT_DIR}/rootfs-extracted"

  [[ -z "$KERNEL_VERSION" ]] && { warn "No kernel version — skipping module copy"; return; }

  local modules_src="${rootfs_dir}/lib/modules/${KERNEL_VERSION}"
  local modules_dest="${initrd_root}/lib/modules/${KERNEL_VERSION}"

  # Check if modules exist in the rootfs
  if [[ ! -d "$modules_src" ]]; then
    warn "Kernel modules directory not found in rootfs: ${modules_src}"
    warn "Initrd will not include loadable kernel modules (built-in only)"
    return
  fi

  log "Copying kernel modules for ${KERNEL_VERSION}..."
  mkdir -p "$modules_dest"

  # Copy module files for selected modules
  local mod_count=0
  local mod
  for mod in "${FINAL_MODULES[@]}"; do
    # Find the module .ko file (multiple possible paths and extensions)
    local -a ko_candidates
    mapfile -t ko_candidates < <(
      find "$modules_src" -name "${mod}.ko*" -type f 2>/dev/null || true
    )

    local ko
    for ko in "${ko_candidates[@]}"; do
      local rel_path="${ko#${modules_src}/}"
      mkdir -p "${modules_dest}/$(dirname "$rel_path")"
      cp "$ko" "${modules_dest}/${rel_path}"
      mod_count=$((mod_count + 1))
      [[ "$VERBOSE" == "true" ]] && log "  Module: ${mod} → ${rel_path}"
    done
  done

  # Copy module metadata files
  local dep_file
  for dep_file in modules.dep modules.dep.bin modules.alias modules.alias.bin modules.symbols modules.symbols.bin; do
    [[ -f "${modules_src}/${dep_file}" ]] && cp "${modules_src}/${dep_file}" "${modules_dest}/"
  done

  # Generate a minimal modules.dep if not present
  if [[ ! -f "${modules_dest}/modules.dep" ]]; then
    (cd "$modules_dest" && find . -name '*.ko*' -print0 | xargs -0 -I{} echo "{}: " | sort > modules.dep)
  fi

  log "Copied ${mod_count} kernel modules"
}

# ============================================================================
# Generate /init for the initrd
# ============================================================================
generate_init() {
  local initrd_root="$1"
  local init_file="${initrd_root}/init"

  log "Generating /init for ${INIT_STYLE} style..."

  case "$INIT_STYLE" in
    systemd)
      # systemd init: mount virtual filesystems, then exec systemd which
      # will start kata-agent.service via the kata-containers.target
      cat > "$init_file" << 'INITEOF'
#!/bin/sh
# Kata Containers initrd — systemd init style
# Mounts virtual filesystems, then hands off to systemd which starts kata-agent.

mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
mkdir -p /dev/pts /dev/shm /run
mount -t devpts devpts /dev/pts
mount -t tmpfs tmpfs /dev/shm
mount -t tmpfs tmpfs /run

# Load kernel modules from initrd
[ -d /lib/modules ] && {
  KVER=$(ls /lib/modules/ 2>/dev/null | head -1)
  [ -n "$KVER" ] && depmod -a "$KVER" 2>/dev/null
}

exec /sbin/init
INITEOF
      ;;
    openrc)
      # OpenRC init: mount virtual filesystems, then exec openrc-init
      cat > "$init_file" << 'INITEOF'
#!/bin/sh
# Kata Containers initrd — OpenRC init style
# Mounts virtual filesystems, then hands off to openrc-init which starts kata-agent.

mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
mkdir -p /dev/pts /dev/shm /run
mount -t devpts devpts /dev/pts
mount -t tmpfs tmpfs /dev/shm
mount -t tmpfs tmpfs /run

# Load kernel modules from initrd
[ -d /lib/modules ] && {
  KVER=$(ls /lib/modules/ 2>/dev/null | head -1)
  [ -n "$KVER" ] && depmod -a "$KVER" 2>/dev/null
}

exec /sbin/openrc-init
INITEOF
      ;;
    busybox|*)
      # Busybox /init: mount virtual filesystems and exec kata-agent as PID 1.
      # This is the minimal, fastest boot path — no service manager overhead.
      cat > "$init_file" << 'INITEOF'
#!/bin/sh
# Kata Containers initrd — busybox init style
# Mounts virtual filesystems and execs kata-agent as PID 1.
# This is the minimal boot path for fastest VM startup.

mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
mkdir -p /dev/pts /dev/shm /run
mount -t devpts devpts /dev/pts
mount -t tmpfs tmpfs /dev/shm
mount -t tmpfs tmpfs /run

# Load kernel modules from initrd
[ -d /lib/modules ] && {
  KVER=$(ls /lib/modules/ 2>/dev/null | head -1)
  [ -n "$KVER" ] && depmod -a "$KVER" 2>/dev/null
}

# Execute kata-agent as the final process (PID 1)
exec /usr/bin/kata-agent
INITEOF
      ;;
  esac

  chmod 755 "$init_file"
  log "Generated /init (${INIT_STYLE} style, $(wc -l < "$init_file") lines)"
}

# ============================================================================
# Helper: Find first existing file in rootfs
# ============================================================================
first_in_rootfs() {
  local name="$1"
  local rootfs="$2"
  local -a paths=("bin/${name}" "sbin/${name}" "usr/bin/${name}" "usr/sbin/${name}" "usr/local/bin/${name}")
  local p
  for p in "${paths[@]}"; do
    if [[ -f "${rootfs}/${p}" ]]; then
      echo "${rootfs}/${p}"
      return 0
    fi
  done
  return 1
}

# ============================================================================
# Helper: Copy if source exists
# ============================================================================
copy_if_exists() {
  local src="$1"
  local dest="$2"
  if [[ -e "$src" ]]; then
    if [[ -d "$src" ]]; then
      mkdir -p "$dest"
      cp -r "${src}/"* "$dest/" 2>/dev/null || true
    else
      mkdir -p "$(dirname "$dest")"
      cp "$src" "$dest"
    fi
  fi
}

# ============================================================================
# Copy required shared libraries
# ============================================================================
copy_required_libs() {
  local initrd_root="$1"
  local rootfs_dir="$2"

  log "Resolving shared library dependencies..."

  # Collect all ELF binaries in the initrd
  local -a elf_files=()
  local elf
  while IFS= read -r -d '' elf; do
    elf_files+=("$elf")
  done < <(find "${initrd_root}" -type f -executable -print0 2>/dev/null | head -50)

  # Use ldd to resolve dependencies (if available)
  if command -v ldd &>/dev/null; then
    local -a lib_set=()
    local file
    for file in "${elf_files[@]}"; do
      local libs
      libs="$(ldd "$file" 2>/dev/null | grep -oP '/[^ ]+\.so[^ ]*' || true)"
      local lib
      for lib in $libs; do
        lib_set+=("$lib")
      done
    done

    # Deduplicate and copy
    local -a unique_libs=()
    local -A seen=()
    local lib
    for lib in "${lib_set[@]}"; do
      [[ -z "${seen[$lib]:-}" ]] && { seen[$lib]=1; unique_libs+=("$lib"); }
    done

    local copied=0
    for lib in "${unique_libs[@]}"; do
      if [[ -f "$lib" ]]; then
        local dest_dir="${initrd_root}/$(dirname "$lib")"
        mkdir -p "$dest_dir"
        cp "$lib" "${initrd_root}/${lib}" 2>/dev/null && copied=$((copied + 1)) || true
      fi
    done
    log "Copied ${copied} shared libraries"

    # Copy the dynamic linker
    local -a linker_candidates=(
      "${rootfs_dir}/lib64/ld-linux-x86-64.so.2"
      "${rootfs_dir}/lib/ld-linux-x86-64.so.2"
      "${rootfs_dir}/lib64/ld-musl-x86_64.so.1"
      "${rootfs_dir}/lib/ld-musl-x86_64.so.1"
    )
    local linker
    for linker in "${linker_candidates[@]}"; do
      if [[ -f "$linker" ]]; then
        mkdir -p "${initrd_root}/$(dirname "${linker#${rootfs_dir}}")"
        cp "$linker" "${initrd_root}/${linker#${rootfs_dir}}"
        log "Copied dynamic linker: ${linker#${rootfs_dir}}"
        break
      fi
    done
  else
    # No ldd — copy common library paths from rootfs
    warn "ldd not available — copying common library paths from rootfs"
    local -a lib_dirs=("lib" "lib64" "usr/lib" "usr/lib64")
    local ldir
    for ldir in "${lib_dirs[@]}"; do
      if [[ -d "${rootfs_dir}/${ldir}" ]]; then
        mkdir -p "${initrd_root}/${ldir}"
        cp "${rootfs_dir}/${ldir}/"*.so* "${initrd_root}/${ldir}/" 2>/dev/null || true
      fi
    done
  fi
}

# ============================================================================
# Strip unnecessary files from initrd
# ============================================================================
strip_initrd() {
  local initrd_root="$1"

  log "Stripping unnecessary files from initrd..."

  # Stripping targets driven by flag-state table
  local -a strip_targets=()
  [[ "$STRIP_LOCALES" == "true" ]]  && strip_targets+=("usr/share/locale")
  [[ "$STRIP_DOCS" == "true" ]]     && strip_targets+=("usr/share/doc")
  [[ "$STRIP_MAN" == "true" ]]      && strip_targets+=("usr/share/man")
  # Always strip these
  strip_targets+=("usr/share/info" "usr/share/groff" "usr/share/emacs")
  strip_targets+=("var/cache" "var/lib/apt" "var/lib/dpkg" "var/lib/pacman")

  local path_pattern
  for path_pattern in "${strip_targets[@]}"; do
    rm -rf "${initrd_root}/${path_pattern}" 2>/dev/null || true
  done

  # Remove Python cache files
  find "$initrd_root" -name '*.pyc' -delete 2>/dev/null || true
  find "$initrd_root" -name '__pycache__' -type d -exec rm -rf {} + 2>/dev/null || true

  # Remove .a and .la files (static libraries not needed at runtime)
  find "$initrd_root" -name '*.a' -delete 2>/dev/null || true
  find "$initrd_root" -name '*.la' -delete 2>/dev/null || true

  # Strip debug symbols from ELF binaries (reduces size significantly)
  if command -v strip &>/dev/null; then
    find "$initrd_root" -type f -executable -print0 2>/dev/null \
      | xargs -0 strip --strip-unneeded 2>/dev/null || true
  fi

  log "Stripping complete: $(du -sh "$initrd_root" | cut -f1)"
}

# ============================================================================
# Build the initrd root filesystem
# ============================================================================
build_initrd_root() {
  local initrd_root="${TMPDIR}/initrd-root"
  local rootfs_dir="${EXTRACT_DIR}/rootfs-extracted"

  log "Building initrd root filesystem..."
  mkdir -p "$initrd_root"

  # Essential directory structure
  local -a essential_dirs=(
    "bin" "sbin" "usr/bin" "usr/sbin" "usr/lib" "usr/lib64"
    "lib" "lib64" "etc" "proc" "sys" "dev" "run"
    "dev/pts" "dev/shm" "tmp" "root" "var/run"
    "var/log" "usr/share" "usr/libexec"
  )
  local dir
  for dir in "${essential_dirs[@]}"; do
    mkdir -p "${initrd_root}/${dir}"
  done

  # ── Copy kata-agent ───────────────────────────────────────────────────
  if [[ -n "$AGENT_PATH" && -f "$AGENT_PATH" ]]; then
    cp "$AGENT_PATH" "${initrd_root}/usr/bin/kata-agent"
    chmod 755 "${initrd_root}/usr/bin/kata-agent"
    log "Installed kata-agent from: ${AGENT_PATH}"
  else
    # Copy from rootfs
    local -a agent_src_candidates=(
      "${rootfs_dir}/usr/bin/kata-agent"
      "${rootfs_dir}/usr/local/bin/kata-agent"
      "${rootfs_dir}/usr/sbin/kata-agent"
      "${rootfs_dir}/sbin/kata-agent"
    )
    local src
    for src in "${agent_src_candidates[@]}"; do
      if [[ -f "$src" ]]; then
        cp "$src" "${initrd_root}/usr/bin/kata-agent"
        chmod 755 "${initrd_root}/usr/bin/kata-agent"
        log "Installed kata-agent from rootfs: ${src#${rootfs_dir}}"
        break
      fi
    done
  fi

  [[ ! -f "${initrd_root}/usr/bin/kata-agent" ]] && die "kata-agent not found — cannot build initrd"

  # ── Copy essential binaries and libraries ──────────────────────────────
  # Minimal set needed for init and kata-agent operation
  local -a essential_bins=(
    "sh" "mount" "umount" "mkdir" "mknod" "ln" "cp" "mv"
    "rm" "ls" "cat" "echo" "sleep" "depmod" "modprobe"
  )

  local bin
  for bin in "${essential_bins[@]}"; do
    local bin_src
    bin_src="$(first_in_rootfs "$bin" "$rootfs_dir")" || true
    if [[ -n "$bin_src" ]]; then
      cp "$bin_src" "${initrd_root}/bin/${bin}" 2>/dev/null || true
    fi
  done

  # Copy busybox if available (provides most essential binaries via symlinks)
  if [[ -f "${rootfs_dir}/bin/busybox" ]]; then
    cp "${rootfs_dir}/bin/busybox" "${initrd_root}/bin/busybox"
    chmod 755 "${initrd_root}/bin/busybox"
    # Create busybox symlinks for our essential bins that aren't already present
    local sym_bin
    for sym_bin in "${essential_bins[@]}"; do
      [[ ! -f "${initrd_root}/bin/${sym_bin}" ]] && \
        ln -sf busybox "${initrd_root}/bin/${sym_bin}" 2>/dev/null || true
    done
    log "Installed busybox with symlinks"
  fi

  # ── Copy shared libraries ─────────────────────────────────────────────
  copy_required_libs "$initrd_root" "$rootfs_dir"

  # ── Copy kernel modules ───────────────────────────────────────────────
  copy_kernel_modules "$initrd_root"

  # ── Copy init system files ────────────────────────────────────────────
  case "$INIT_STYLE" in
    systemd)
      copy_if_exists "${rootfs_dir}/sbin/init" "${initrd_root}/sbin/init"
      copy_if_exists "${rootfs_dir}/lib/systemd" "${initrd_root}/lib/systemd"
      copy_if_exists "${rootfs_dir}/usr/lib/systemd" "${initrd_root}/usr/lib/systemd"
      copy_if_exists "${rootfs_dir}/etc/systemd" "${initrd_root}/etc/systemd"

      # Ensure kata-agent service unit exists
      mkdir -p "${initrd_root}/etc/systemd/system"
      mkdir -p "${initrd_root}/etc/systemd/target"
      if [[ -f "${rootfs_dir}/etc/systemd/system/kata-agent.service" ]]; then
        cp "${rootfs_dir}/etc/systemd/system/kata-agent.service" "${initrd_root}/etc/systemd/system/"
      else
        # Generate minimal service unit
        cat > "${initrd_root}/etc/systemd/system/kata-agent.service" << 'EOF'
[Unit]
Description=kata-agent
Requires=kata-containers.target
After=kata-containers.target

[Service]
ExecStart=/usr/bin/kata-agent
Restart=always
RestartSec=1

[Install]
WantedBy=kata-containers.target
EOF
      fi

      # Generate kata-containers.target
      cat > "${initrd_root}/etc/systemd/system/kata-containers.target" << 'EOF'
[Unit]
Description=kata containers target
Requires=multi-user.target
After=multi-user.target
EOF
      ;;
    openrc)
      copy_if_exists "${rootfs_dir}/sbin/openrc-init" "${initrd_root}/sbin/openrc-init"
      copy_if_exists "${rootfs_dir}/etc/init.d" "${initrd_root}/etc/init.d"
      # Generate OpenRC init script for kata-agent
      mkdir -p "${initrd_root}/etc/init.d"
      cat > "${initrd_root}/etc/init.d/kata-agent" << 'EOF'
#!/sbin/openrc-run
description="kata-agent"
command="/usr/bin/kata-agent"
command_background=true
pidfile="/run/kata-agent.pid"

depend() {
  after localmount
}
EOF
      chmod 755 "${initrd_root}/etc/init.d/kata-agent"
      ;;
  esac

  # ── Generate /init ────────────────────────────────────────────────────
  generate_init "$initrd_root"

  # ── Copy DNS config ───────────────────────────────────────────────────
  if [[ -f "${rootfs_dir}/etc/resolv.conf" ]]; then
    cp "${rootfs_dir}/etc/resolv.conf" "${initrd_root}/etc/resolv.conf"
  else
    echo "nameserver 8.8.8.8" > "${initrd_root}/etc/resolv.conf"
  fi

  # ── Copy /etc/passwd and /etc/group (minimal) ────────────────────────
  copy_if_exists "${rootfs_dir}/etc/passwd" "${initrd_root}/etc/passwd"
  copy_if_exists "${rootfs_dir}/etc/group" "${initrd_root}/etc/group"

  # Generate minimal passwd/group if not present
  [[ ! -f "${initrd_root}/etc/passwd" ]] && echo "root:x:0:0:root:/root:/bin/sh" > "${initrd_root}/etc/passwd"
  [[ ! -f "${initrd_root}/etc/group" ]] && echo "root:x:0:" > "${initrd_root}/etc/group"

  # ── Strip unnecessary files ───────────────────────────────────────────
  strip_initrd "$initrd_root"

  log "Initrd root built: $(du -sh "$initrd_root" | cut -f1)"
}

# ============================================================================
# Create cpio archive
# ============================================================================
create_cpio_archive() {
  local initrd_root="${TMPDIR}/initrd-root"
  local output_file="${OUTPUT:-kata-initrd${COMPRESS_EXT[$FORMAT]:-.img}}"

  log "Creating ${FORMAT} initrd image..."

  # Verify /init exists
  [[ -f "${initrd_root}/init" ]] || die "Missing /init in initrd root — cannot create archive"

  local compress_cmd="${COMPRESS_CMD[$FORMAT]:-cat}"

  # Create cpio archive with compression
  (cd "$initrd_root" && find . | cpio -o -H newc 2>/dev/null) | $compress_cmd > "$output_file"

  local size
  size="$(du -sh "$output_file" | cut -f1)"
  log "Initrd created: ${output_file} (${size})"

  # Validate the output
  validate_initrd "$output_file"

  OUTPUT_FILE="$output_file"
}

# ============================================================================
# Create cramfs image
# ============================================================================
create_cramfs_image() {
  local initrd_root="${TMPDIR}/initrd-root"
  local output_file="${OUTPUT:-kata-initrd.cramfs}"

  log "Creating cramfs initrd image..."

  command -v mkcramfs &>/dev/null || die "mkcramfs not found — install cramfsprogs or util-linux"

  mkcramfs "$initrd_root" "$output_file"

  local size
  size="$(du -sh "$output_file" | cut -f1)"
  log "Cramfs initrd created: ${output_file} (${size})"

  OUTPUT_FILE="$output_file"
}

# ============================================================================
# Validate the generated initrd
# ============================================================================
validate_initrd() {
  local initrd_file="$1"

  log "Validating generated initrd..."

  local -a checks=()

  # Check 1: File exists and is non-empty
  [[ -f "$initrd_file" && -s "$initrd_file" ]] && checks+=("PASS:file_exists") || checks+=("FAIL:file_exists")

  # Check 2: File format matches expected
  local file_type
  file_type="$(file -b "$initrd_file" 2>/dev/null || true)"
  case "$FORMAT" in
    cpio-gzip)  echo "$file_type" | grep -qi "gzip" && checks+=("PASS:format_match") || checks+=("FAIL:format_match:${file_type}") ;;
    cpio-lz4)   echo "$file_type" | grep -qi "lz4" && checks+=("PASS:format_match") || checks+=("WARN:format_match:file(1) may not identify LZ4") ;;
    cpio-xz)    echo "$file_type" | grep -qi "xz" && checks+=("PASS:format_match") || checks+=("FAIL:format_match:${file_type}") ;;
    cpio-zstd)  echo "$file_type" | grep -qi "zstd" && checks+=("PASS:format_match") || checks+=("WARN:format_match:file(1) may not identify ZSTD") ;;
    cramfs)     echo "$file_type" | grep -qi "cramfs" && checks+=("PASS:format_match") || checks+=("FAIL:format_match:${file_type}") ;;
  esac

  # Check 3: Can list archive contents (cpio formats only)
  if [[ "$FORMAT" != "cramfs" ]]; then
    local decompress_cmd
    case "$FORMAT" in
      cpio-gzip) decompress_cmd="zcat" ;;
      cpio-lz4)  decompress_cmd="lz4 -d -c" ;;
      cpio-xz)   decompress_cmd="xzcat" ;;
      cpio-zstd) decompress_cmd="zstdcat" ;;
    esac
    local listing
    listing="$($decompress_cmd "$initrd_file" 2>/dev/null | cpio -t 2>/dev/null | head -50 || true)"
    if echo "$listing" | grep -q "init"; then
      checks+=("PASS:init_exists")
    else
      checks+=("FAIL:init_exists")
    fi
    if echo "$listing" | grep -q "kata-agent"; then
      checks+=("PASS:agent_exists")
    else
      checks+=("FAIL:agent_exists")
    fi
  fi

  # Check 4: Size is reasonable (< 512MB for initrd)
  local size_bytes
  size_bytes="$(stat --format="%s" "$initrd_file" 2>/dev/null || stat -f "%z" "$initrd_file" 2>/dev/null || echo 0)"
  local size_mb=$(( size_bytes / (1024 * 1024) ))
  if [[ $size_mb -lt 512 ]]; then
    checks+=("PASS:size_reasonable:${size_mb}MB")
  else
    checks+=("WARN:size_large:${size_mb}MB — consider stripping more content")
  fi

  # Report results
  local pass=0 fail=0 warn=0
  local check
  for check in "${checks[@]}"; do
    local status="${check%%:*}"
    case "$status" in
      PASS) pass=$((pass + 1)) ;;
      FAIL) fail=$((fail + 1)); error "  ${check}" ;;
      WARN) warn=$((warn + 1)); warn "  ${check}" ;;
    esac
  done

  log "Validation: ${pass} passed, ${fail} failed, ${warn} warnings"
  [[ $fail -gt 0 ]] && die "Initrd validation failed — see errors above"
}

# ============================================================================
# Update QCrows bundle in-place
# ============================================================================
update_qcrows_inplace() {
  [[ "$IN_PLACE" != "true" ]] && return

  local qcrows_file="$INPUT"
  local new_initrd="$OUTPUT_FILE"

  log "Updating QCrows bundle in-place with new initrd..."

  # Create a new bundle with the updated initrd
  local staging="${TMPDIR}/inplace-staging"
  mkdir -p "$staging"

  # Copy all existing bundle contents
  cp -r "${EXTRACT_DIR}/"* "$staging/" 2>/dev/null || true

  # Replace the initrd
  local initrd_name
  initrd_name="$(ls "${staging}"/initrd* 2>/dev/null | head -1 || true)"
  if [[ -n "$initrd_name" ]]; then
    rm -f "${staging}"/initrd.*
    cp "$new_initrd" "${staging}/initrd.img"
  else
    cp "$new_initrd" "${staging}/initrd.img"
  fi

  # Recompute hashes
  (cd "$staging" && find . -type f ! -name "hashes.sha256" -print0 | sort -z | xargs -0 sha256sum) \
    > "${staging}/hashes.sha256"

  # Rebuild the archive
  local backup="${qcrows_file}.bak"
  cp "$qcrows_file" "$backup"
  log "Backup created: ${backup}"

  (cd "$staging" && tar czf - ./*) > "$qcrows_file"

  log "QCrows bundle updated: ${qcrows_file}"
}

# ============================================================================
# Print summary
# ============================================================================
print_summary() {
  local initrd_file="${OUTPUT_FILE:-}"
  local size=""
  [[ -f "$initrd_file" ]] && size="$(du -sh "$initrd_file" | cut -f1)"

  echo ""
  echo -e "${GREEN}╔══════════════════════════════════════════════════════╗${NC}"
  echo -e "${GREEN}║   Initrd regenerated successfully                   ║${NC}"
  echo -e "${GREEN}╚══════════════════════════════════════════════════════╝${NC}"
  echo ""
  echo -e "  Output:      ${CYAN}${initrd_file}${NC}"
  echo -e "  Size:        ${CYAN}${size}${NC}"
  echo -e "  Format:      ${CYAN}${FORMAT}${NC}"
  echo -e "  VMM:         ${CYAN}${VMM}${NC}"
  echo -e "  Init style:  ${CYAN}${INIT_STYLE}${NC}"
  echo -e "  Kernel:      ${CYAN}${KERNEL_VERSION:-unknown}${NC}"
  echo -e "  Modules:     ${CYAN}${#FINAL_MODULES[@]} included${NC}"
  echo -e "  In-place:    ${CYAN}${IN_PLACE}${NC}"
  echo ""
  echo -e "  Next steps:"
  echo -e "    ${CYAN}qcrows-verify ${INPUT}${NC}"
  echo -e "    ${CYAN}qcrows-export --format qcow2 ${INPUT} -o disk.qcow2${NC}"
  echo -e "    ${CYAN}qcrows-export --format pxe ${INPUT} --server-ip 192.168.1.1${NC}"
  echo ""
}

# ============================================================================
# Entry Point
# ============================================================================
EXTRACT_DIR=""
KERNEL_VERSION=""
OUTPUT_FILE=""
declare -a FINAL_MODULES=()

parse_args "$@"
validate_inputs

# ── 1. Setup temp directory ─────────────────────────────────────────────
TMPDIR="$(mktemp -d /tmp/qcrows-initrd-regen-XXXXXX)"
EXTRACT_DIR="${TMPDIR}/bundle"
log "Working directory: ${TMPDIR}"

# ── 2. Extract QCrows bundle ────────────────────────────────────────────
extract_qcrows "$INPUT" "$EXTRACT_DIR"

# ── 3. Detect environment ───────────────────────────────────────────────
detect_vmm
detect_init_style
detect_compression

# ── 4. Extract rootfs for content access ────────────────────────────────
extract_rootfs

# ── 5. Discover kata-agent ──────────────────────────────────────────────
discover_agent

# ── 6. Resolve kernel modules ───────────────────────────────────────────
resolve_kernel_modules

# ── 7. Build initrd root filesystem ─────────────────────────────────────
build_initrd_root

# ── 8. Create the initrd image ──────────────────────────────────────────
if [[ "$FORMAT" == "cramfs" ]]; then
  create_cramfs_image
else
  create_cpio_archive
fi

# ── 9. Update bundle in-place if requested ──────────────────────────────
update_qcrows_inplace

# ── 10. Print summary ───────────────────────────────────────────────────
print_summary
