#!/bin/bash

# deb-bootc-image-builder - Simplified container to disk image converter
# This is a simplified fork of the original Fedora bootc-image-builder
# that uses native Debian tools instead of osbuild

set -euo pipefail

# System tool paths
QEMU_IMG="/usr/bin/qemu-img"
RSYNC="/usr/bin/rsync"
TAR="/bin/tar"
MKDIR="/bin/mkdir"
CP="/bin/cp"
LOSETUP="/usr/sbin/losetup"
PARTED="/usr/sbin/parted"
MOUNT="/bin/mount"
UMOUNT="/bin/umount"
BOOTUPD="/usr/libexec/bootupd"
GRUB_INSTALL="/usr/sbin/grub-install"
GRUB_MKCONFIG="/usr/sbin/grub-mkconfig"

# Default values
CONTAINER_IMAGE=""
OUTPUT_FORMAT="qcow2"
OUTPUT_DIR="/output"
STORE_DIR="/store"
CONTAINER_STORAGE="/var/lib/containers/storage"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Global variables for cleanup
WORK_DIR=""
LOOP_DEV=""
MOUNT_POINT=""
CONTAINER_FS_DIR=""
DISK_RAW=""

# Logging functions
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Help function
show_help() {
    cat << EOF
Simplified Debian bootc-image-builder

Usage: $0 [OPTIONS] <container-image>

Options:
    -f, --format FORMAT    Output format (qcow2, raw, img) [default: qcow2]
    -o, --output DIR       Output directory [default: /output]
    -s, --store DIR        Store directory [default: /store]
    -h, --help            Show this help message

Examples:
    $0 simple-cli:latest
    $0 -f raw -o /tmp/output simple-cli:latest
    $0 --format qcow2 --output /output simple-cli:latest

EOF
}

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -f|--format)
            OUTPUT_FORMAT="$2"
            shift 2
            ;;
        -o|--output)
            OUTPUT_DIR="$2"
            shift 2
            ;;
        -s|--store)
            STORE_DIR="$2"
            shift 2
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        -*)
            log_error "Unknown option $1"
            show_help
            exit 1
            ;;
        *)
            CONTAINER_IMAGE="$1"
            shift
            ;;
    esac
done

# Validate inputs
if [[ -z "$CONTAINER_IMAGE" ]]; then
    log_error "Container image is required"
    show_help
    exit 1
fi

if [[ ! -d "$OUTPUT_DIR" ]]; then
    log_error "Output directory $OUTPUT_DIR does not exist"
    exit 1
fi

# Validate output format
case "$OUTPUT_FORMAT" in
    qcow2|raw|img)
        ;;
    *)
        log_error "Unsupported output format: $OUTPUT_FORMAT"
        exit 1
        ;;
esac

log_info "Starting simplified bootc-image-builder"
log_info "Container image: $CONTAINER_IMAGE"
log_info "Output format: $OUTPUT_FORMAT"
log_info "Output directory: $OUTPUT_DIR"

# Create working directory in project directory
WORK_DIR="$(pwd)/work/bootc-builder-$(date +%s)"
mkdir -p "$WORK_DIR" || {
    log_error "Failed to create working directory"
    exit 1
}
log_info "Working directory: $WORK_DIR"

# Check available space
AVAILABLE_SPACE=$(df "$WORK_DIR" | awk 'NR==2 {print $4}')
if [[ "$AVAILABLE_SPACE" -lt 5000000 ]]; then  # Less than 5GB
    log_warn "Low disk space available: ${AVAILABLE_SPACE}KB"
    log_warn "This might cause issues with large containers"
fi

# Signal handling for cleanup
cleanup_on_exit() {
    local exit_code=$?
    log_info "Cleaning up resources..."
    
    # Unmount if mounted
    if [[ -n "$MOUNT_POINT" && -d "$MOUNT_POINT" ]]; then
        if mountpoint -q "$MOUNT_POINT" 2>/dev/null; then
            log_info "Unmounting $MOUNT_POINT..."
            sudo umount "$MOUNT_POINT" 2>/dev/null || true
        fi
    fi
    
    # Detach loop device if exists
    if [[ -n "$LOOP_DEV" && -b "$LOOP_DEV" ]]; then
        log_info "Detaching loop device $LOOP_DEV..."
        sudo losetup -d "$LOOP_DEV" 2>/dev/null || true
    fi
    
    # Clean up any remaining loop devices that might be ours
    if [[ -n "$WORK_DIR" ]]; then
        log_info "Checking for orphaned loop devices..."
        for loop_dev in /dev/loop*; do
            if [[ -b "$loop_dev" ]]; then
                local mount_point
                mount_point=$(losetup -l "$loop_dev" 2>/dev/null | grep -o ".*/work/bootc-builder-[^[:space:]]*" || true)
                if [[ -n "$mount_point" ]]; then
                    log_info "Detaching orphaned loop device $loop_dev..."
                    sudo losetup -d "$loop_dev" 2>/dev/null || true
                fi
            fi
        done
    fi
    
    # Remove working directory
    if [[ -n "$WORK_DIR" && -d "$WORK_DIR" ]]; then
        log_info "Removing working directory $WORK_DIR..."
        sudo rm -rf "$WORK_DIR" 2>/dev/null || true
    fi
    
    # Remove any remaining temporary files
    if [[ -n "$DISK_RAW" && -f "$DISK_RAW" ]]; then
        log_info "Removing temporary disk image $DISK_RAW..."
        sudo rm -f "$DISK_RAW" 2>/dev/null || true
    fi
    
    if [[ -n "$CONTAINER_FS_DIR" && -d "$CONTAINER_FS_DIR" ]]; then
        log_info "Removing container filesystem directory $CONTAINER_FS_DIR..."
        sudo rm -rf "$CONTAINER_FS_DIR" 2>/dev/null || true
    fi
    
    log_info "Cleanup completed"
    exit "$exit_code"
}

# Set up signal handlers
trap cleanup_on_exit EXIT INT TERM

# Function to clean up any existing loop devices from previous runs
cleanup_existing_loop_devices() {
    log_info "Checking for existing loop devices from previous runs..."
    for loop_dev in /dev/loop*; do
        if [[ -b "$loop_dev" ]]; then
            local mount_point
            mount_point=$(losetup -l "$loop_dev" 2>/dev/null | grep -o ".*/work/bootc-builder-[^[:space:]]*" || true)
            if [[ -n "$mount_point" ]]; then
                log_warn "Found existing loop device $loop_dev from previous run, cleaning up..."
                # Try to unmount if mounted
                if mountpoint -q "$mount_point" 2>/dev/null; then
                    sudo umount "$mount_point" 2>/dev/null || true
                fi
                # Detach the loop device
                sudo losetup -d "$loop_dev" 2>/dev/null || true
                # Remove the mount point directory
                sudo rm -rf "$mount_point" 2>/dev/null || true
            fi
        fi
    done
}

# Clean up any existing loop devices at startup
cleanup_existing_loop_devices

# Check if container image exists locally
log_info "Checking if container image exists locally: $CONTAINER_IMAGE"
if podman images --format "{{.Repository}}:{{.Tag}}" | grep -q "^$CONTAINER_IMAGE$"; then
    log_info "Container image found locally, skipping pull"
elif podman images --format "{{.Repository}}:{{.Tag}}" | grep -q "simple-cli:latest"; then
    log_info "Found simple-cli:latest locally, using that instead"
    CONTAINER_IMAGE="simple-cli:latest"
elif podman images --format "{{.Repository}}:{{.Tag}}" | grep -q "localhost/simple-cli:latest"; then
    log_info "Found localhost/simple-cli:latest locally, using that instead"
    CONTAINER_IMAGE="localhost/simple-cli:latest"
else
    log_info "Container image not found locally, attempting to pull: $CONTAINER_IMAGE"
    podman pull "$CONTAINER_IMAGE" || {
        log_error "Failed to pull container image. Please ensure the image is available."
        log_error "You can either:"
        log_error "1. Build the image locally first"
        log_error "2. Use a fully qualified registry URL"
        exit 1
    }
fi

# Export the container to a tar file
log_info "Exporting container to tar..."
podman export "$(podman create --rm "$CONTAINER_IMAGE" true)" > "$WORK_DIR/container.tar"

# Create a loopback device and mount the container
log_info "Setting up loopback device..."
cd "$WORK_DIR"

# Extract the container
log_info "Extracting container filesystem..."
CONTAINER_FS_DIR="$WORK_DIR/container-fs"
mkdir -p "$CONTAINER_FS_DIR"
if ! tar -xf container.tar -C "$CONTAINER_FS_DIR"; then
    log_error "Failed to extract container. This might be due to:"
    log_error "1. Insufficient disk space"
    log_error "2. Corrupted container archive"
    log_error "3. Permission issues"
    exit 1
fi

# Create disk image using qemu-img (no sudo required)
log_info "Creating disk image..."
IMAGE_SIZE="8G"  # Increased size for enhanced simple-cli with Bazzite features

# Create a proper disk image with partitions for bootloader installation
log_info "Creating partitioned disk image for bootloader installation..."

# Create raw image file
DISK_RAW="$WORK_DIR/disk.raw"
$QEMU_IMG create -f raw "$DISK_RAW" "$IMAGE_SIZE"

# For bootloader installation, we need to create a proper disk structure
# This requires sudo for partitioning and mounting
log_info "Setting up disk partitions for bootloader installation..."
log_info "Note: This step requires sudo for disk operations"

# Create partition table and filesystem
log_info "Creating partition table and filesystem..."
sudo $PARTED "$DISK_RAW" mklabel msdos
sudo $PARTED "$DISK_RAW" mkpart primary ext4 1MiB 100%
sudo $PARTED "$DISK_RAW" set 1 boot on

# Setup loopback device
log_info "Setting up loopback device..."
LOOP_DEV=$(sudo $LOSETUP --find --show "$DISK_RAW")
log_info "Using loopback device: $LOOP_DEV"

# Force kernel to reread partition table
log_info "Rereading partition table..."
sudo partprobe "$LOOP_DEV" || true

# Get the partition device
PART_DEV="${LOOP_DEV}p1"
log_info "Partition device: $PART_DEV"

# Wait for partition to be available and verify it exists
log_info "Waiting for partition to be available..."
for i in {1..10}; do
    if [[ -b "$PART_DEV" ]]; then
        log_info "Partition device found: $PART_DEV"
        break
    fi
    log_info "Waiting for partition device... (attempt $i/10)"
    sleep 1
done

if [[ ! -b "$PART_DEV" ]]; then
    log_error "Partition device not found: $PART_DEV"
    log_error "Available devices:"
    ls -la /dev/loop* || true
    exit 1
fi

# Create filesystem
log_info "Creating ext4 filesystem..."
sudo mkfs.ext4 "$PART_DEV"

# Mount the partition
MOUNT_POINT="$WORK_DIR/mount-point"
mkdir -p "$MOUNT_POINT"
sudo $MOUNT "$PART_DEV" "$MOUNT_POINT"

# Copy container filesystem
log_info "Copying container filesystem to disk image..."
sudo rsync -a "$CONTAINER_FS_DIR/" "$MOUNT_POINT/"

# Install bootloader manually since deb-bootupd doesn't support non-default sysroots
log_info "Installing bootloader manually..."
if [[ -x "$GRUB_INSTALL" ]]; then
    log_info "Found grub-install, installing GRUB bootloader..."
    
    # Install GRUB to the mounted filesystem
    # Use --root-directory to specify the mount point
    # Use --target=i386-pc for BIOS systems
    # Use --boot-directory to specify where boot files are located
    log_info "Installing GRUB to $MOUNT_POINT..."
    sudo "$GRUB_INSTALL" \
        --root-directory="$MOUNT_POINT" \
        --target=i386-pc \
        --boot-directory="$MOUNT_POINT/boot" \
        --force \
        "$LOOP_DEV" || {
        log_warn "GRUB installation failed, continuing without bootloader"
    }
    
    # Generate GRUB configuration manually since grub-mkconfig needs host environment
    log_info "Generating GRUB configuration manually..."
    
    # Find the actual kernel and initrd files in the container
    KERNEL_FILE=$(find "$MOUNT_POINT/boot" -name "vmlinuz-*" | head -1)
    INITRD_FILE=$(find "$MOUNT_POINT/boot" -name "initrd.img-*" | head -1)
    
    if [[ -z "$KERNEL_FILE" ]] || [[ -z "$INITRD_FILE" ]]; then
        log_error "Kernel or initrd not found in container"
        log_error "Available files in /boot:"
        ls -la "$MOUNT_POINT/boot/" || true
        exit 1
    fi
    
    # Extract just the filename without the full path
    KERNEL_NAME=$(basename "$KERNEL_FILE")
    INITRD_NAME=$(basename "$INITRD_FILE")
    
    log_info "Found kernel: $KERNEL_NAME"
    log_info "Found initrd: $INITRD_NAME"
    
    # Create a basic GRUB configuration for the container
    cat > "$MOUNT_POINT/boot/grub/grub.cfg" << EOF
# GRUB configuration for simple-cli container
set timeout=1
set default=0

menuentry "Simple CLI" {
    set root=(hd0,msdos1)
    linux /boot/$KERNEL_NAME root=/dev/sda1 rw console=ttyS0 quiet splash fastboot
    initrd /boot/$INITRD_NAME
}

menuentry "Simple CLI (Recovery)" {
    set root=(hd0,msdos1)
    linux /boot/$KERNEL_NAME root=/dev/sda1 rw single console=ttyS0
    initrd /boot/$INITRD_NAME
}
EOF
    
    log_info "GRUB configuration created at $MOUNT_POINT/boot/grub/grub.cfg"
    
else
    log_warn "grub-install not found at $GRUB_INSTALL, skipping bootloader installation"
    log_warn "Image will not be bootable without bootloader"
fi

# Unmount
sudo $UMOUNT "$MOUNT_POINT"

# Detach loopback device
sudo $LOSETUP -d "$LOOP_DEV"

# Convert to requested format
log_info "Converting to $OUTPUT_FORMAT format..."
case "$OUTPUT_FORMAT" in
    qcow2)
        $QEMU_IMG convert -f raw -O qcow2 "$DISK_RAW" "$OUTPUT_DIR/$(basename "$CONTAINER_IMAGE" | tr ':' '_').qcow2"
        ;;
    raw)
        cp "$DISK_RAW" "$OUTPUT_DIR/$(basename "$CONTAINER_IMAGE" | tr ':' '_').raw"
        ;;
    img)
        cp "$DISK_RAW" "$OUTPUT_DIR/$(basename "$CONTAINER_IMAGE" | tr ':' '_').img"
        ;;
esac

log_info "Image creation completed successfully!"
log_info "Output file: $OUTPUT_DIR/$(basename "$CONTAINER_IMAGE" | tr ':' '_').$OUTPUT_FORMAT"

# List output files
log_info "Output directory contents:"
ls -la "$OUTPUT_DIR"
