#!/bin/bash
#
# download-packages.sh - Download all .deb packages needed for offline PXE server setup
#
# The PXE server installs Ubuntu 24.04 (Noble), so all packages MUST come from the
# 24.04 archive. If this script is run on a non-24.04 host (e.g. Zorin 17 / 22.04),
# it auto-spawns an Ubuntu 24.04 docker container to do the download.
#
# Usage:
#   ./download-packages.sh [output_directory]
#
# Default output: ./offline-packages/

set -euo pipefail

OUT_DIR="${1:-./offline-packages}"
OUT_DIR_ABS="$(cd "$(dirname "$OUT_DIR")" 2>/dev/null && pwd)/$(basename "$OUT_DIR")"

# Detect host Ubuntu codename. Run inside the container if not Noble (24.04).
HOST_CODENAME="$(. /etc/os-release && echo "${UBUNTU_CODENAME:-${VERSION_CODENAME:-}}")"

if [ "${IN_DOCKER:-}" != "1" ] && [ "$HOST_CODENAME" != "noble" ]; then
    echo "Host is '$HOST_CODENAME', not 'noble' (Ubuntu 24.04)."
    echo "Re-running inside ubuntu:24.04 docker container..."
    echo ""

    if ! command -v docker >/dev/null; then
        echo "ERROR: docker not installed. Install docker or run on a real Ubuntu 24.04 host."
        exit 1
    fi

    SCRIPT_PATH="$(readlink -f "$0")"
    REPO_DIR="$(cd "$(dirname "$SCRIPT_PATH")"/.. && pwd)"
    mkdir -p "$OUT_DIR_ABS"

    docker run --rm -i \
        -v "$REPO_DIR:/repo" \
        -v "$OUT_DIR_ABS:/out" \
        -e IN_DOCKER=1 \
        -w /repo \
        ubuntu:24.04 \
        bash -c "apt-get update -qq && apt-get install -y --no-install-recommends sudo python3-pip python3-setuptools python3-wheel ca-certificates >/dev/null && /repo/scripts/download-packages.sh /out"

    echo ""
    echo "============================================"
    echo "Container build complete. Files in: $OUT_DIR_ABS"
    echo "============================================"
    exit 0
fi

mkdir -p "$OUT_DIR"

# Packages installed by the Ansible playbook (pxe_server_setup.yml)
PLAYBOOK_PACKAGES=(
    ansible
    dnsmasq
    apache2
    samba
    unzip
    ufw
    cron
    wimtools
    p7zip-full
    grub-efi-amd64-bin
    grub-common
    conntrack
    busybox-static
    zstd
    cpio
)

# Packages installed during autoinstall late-commands (NetworkManager, WiFi, etc.)
AUTOINSTALL_PACKAGES=(
    network-manager
    wpasupplicant
    wireless-tools
    linux-firmware
    firmware-sof-signed
)

ALL_PACKAGES=("${PLAYBOOK_PACKAGES[@]}" "${AUTOINSTALL_PACKAGES[@]}")

echo "============================================"
echo "Offline Package Downloader (Ubuntu 24.04 noble)"
echo "============================================"
echo "Output directory: $OUT_DIR"
echo ""
echo "Packages to resolve:"
printf '  - %s\n' "${ALL_PACKAGES[@]}"
echo ""

# Update package cache
echo "[1/4] Updating package cache..."
sudo apt-get update -qq

# Simulate install to find all dependencies
echo "[2/4] Resolving dependencies..."
EXPLICIT_DEPS=$(apt-get install --simulate "${ALL_PACKAGES[@]}" 2>&1 \
    | grep "^Inst " \
    | awk '{print $2}')

# ALSO pull every package that would upgrade in a dist-upgrade. This is
# critical: the Ubuntu ISO ships a point-in-time baseline, but our explicit
# packages (from noble-updates) may depend on *newer* versions of ISO-baseline
# packages (e.g. gnupg 17.4 needs matching gpgv 17.4). Without this, offline
# install fails with dpkg "dependency problems" because transitive version
# bumps aren't captured by --simulate on the explicit list.
UPGRADE_DEPS=$(apt-get dist-upgrade --simulate 2>&1 \
    | grep "^Inst " \
    | awk '{print $2}')

DEPS=$(printf '%s\n%s\n' "$EXPLICIT_DEPS" "$UPGRADE_DEPS" | sort -u | grep -v '^$')

DEP_COUNT=$(echo "$DEPS" | wc -l)
echo "    Found $DEP_COUNT packages (explicit + baseline upgrades)"

# Download all packages
echo "[3/4] Downloading .deb packages to $OUT_DIR..."
cd "$OUT_DIR"
apt-get download $DEPS 2>&1 | tail -5

DEB_COUNT=$(ls -1 *.deb 2>/dev/null | wc -l)
TOTAL_SIZE=$(du -sh . | cut -f1)

echo "    $DEB_COUNT packages ($TOTAL_SIZE)"

# Download pip wheels for Flask webapp (offline install)
echo "[4/4] Downloading Python wheels for webapp..."
# Place pip-wheels next to the script (or /repo when in docker), not next to OUT_DIR
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)"
PIP_DIR="$REPO_ROOT/pip-wheels"
mkdir -p "$PIP_DIR"
pip3 download -d "$PIP_DIR" flask lxml 2>&1 | tail -5

WHL_COUNT=$(ls -1 "$PIP_DIR"/*.whl "$PIP_DIR"/*.tar.gz 2>/dev/null | wc -l)
echo "    $WHL_COUNT Python packages downloaded to pip-wheels/"

echo ""
echo "============================================"
echo "Download complete!"
echo "============================================"
echo "  .deb packages: $DEB_COUNT ($TOTAL_SIZE) in $OUT_DIR/"
echo "  Python wheels: $WHL_COUNT in $PIP_DIR/"
echo ""
