# EcoOS ISO Builder
# Build from eco_os directory:
#   docker build --build-arg TARGET_ARCH=amd64 -t ecoos-builder -f isobuild/Dockerfile .
#   docker run --privileged -v $(pwd)/isobuild/output:/output ecoos-builder
#
# Supported architectures: amd64, arm64, rpi

FROM ubuntu:24.04

ARG TARGET_ARCH=amd64
ENV TARGET_ARCH=${TARGET_ARCH}
ENV DEBIAN_FRONTEND=noninteractive

# Install common build dependencies
RUN apt-get update && apt-get install -y \
    live-build \
    debootstrap \
    xorriso \
    squashfs-tools \
    mtools \
    dosfstools \
    curl \
    unzip \
    git \
    parted \
    fdisk \
    e2fsprogs \
    && rm -rf /var/lib/apt/lists/*

# Install architecture-specific packages
RUN apt-get update && \
    if [ "$TARGET_ARCH" = "amd64" ]; then \
        apt-get install -y \
            grub-efi-amd64-bin \
            grub-efi-amd64-signed \
            grub-pc-bin \
            shim-signed \
            syslinux-utils \
            syslinux \
            syslinux-common \
            isolinux; \
    elif [ "$TARGET_ARCH" = "arm64" ]; then \
        apt-get install -y \
            grub-efi-arm64-bin \
            grub-efi-arm64-signed; \
    elif [ "$TARGET_ARCH" = "rpi" ]; then \
        apt-get install -y \
            grub-efi-arm64-bin; \
    fi && rm -rf /var/lib/apt/lists/*

# Install Deno
RUN curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh

# Create build directory
WORKDIR /build

# Copy isobuild configuration
COPY isobuild/config/ /build/config/
COPY isobuild/scripts/ /build/scripts/

# Copy hooks to enable services (already in config/, but put in separate dir for build script)
COPY isobuild/config/hooks/ /build/hooks/

# Copy daemon source (for bundling)
COPY ecoos_daemon/ /daemon/

# Bundle the daemon - cross-compile for target architecture
RUN cd /daemon && \
    if [ "$TARGET_ARCH" = "amd64" ]; then \
        deno compile --allow-all --target x86_64-unknown-linux-gnu --output /build/daemon-bundle/eco-daemon mod.ts; \
    else \
        deno compile --allow-all --target aarch64-unknown-linux-gnu --output /build/daemon-bundle/eco-daemon mod.ts; \
    fi

# Download Chromium during Docker build (network works here, not in chroot hooks)
# Note: ARM64 Chromium snapshots may be less reliable, fallback to known version
RUN echo "Downloading Chromium for $TARGET_ARCH..." && \
    cd /tmp && \
    if [ "$TARGET_ARCH" = "amd64" ]; then \
        PLATFORM="Linux_x64"; \
        FALLBACK_VERSION="1368529"; \
    else \
        PLATFORM="Linux_ARM64"; \
        FALLBACK_VERSION="1368529"; \
    fi && \
    LATEST=$(curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/${PLATFORM}%2FLAST_CHANGE?alt=media" 2>/dev/null || echo "$FALLBACK_VERSION") && \
    echo "Using Chromium build: $LATEST for platform $PLATFORM" && \
    curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/${PLATFORM}%2F${LATEST}%2Fchrome-linux.zip?alt=media" -o chromium.zip || \
    curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/${PLATFORM}%2F${FALLBACK_VERSION}%2Fchrome-linux.zip?alt=media" -o chromium.zip && \
    mkdir -p /build/chromium && \
    unzip -q chromium.zip -d /tmp && \
    mv /tmp/chrome-linux/* /build/chromium/ && \
    rm -rf chromium.zip /tmp/chrome-linux && \
    chmod +x /build/chromium/chrome && \
    echo "Chromium downloaded to /build/chromium/"

# Make scripts executable
RUN chmod +x /build/scripts/*.sh

# Create dummy isohybrid for UEFI-only builds (real isohybrid needs BIOS boot record)
RUN echo '#!/bin/sh' > /usr/local/bin/isohybrid && \
    echo 'echo "Skipping isohybrid (UEFI-only build)"' >> /usr/local/bin/isohybrid && \
    echo 'exit 0' >> /usr/local/bin/isohybrid && \
    chmod +x /usr/local/bin/isohybrid

# Build script - parameterized for architecture
COPY <<'EOF' /build/docker-build.sh
#!/bin/bash
set -e

export PATH="/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin:$PATH"

# Get architecture from environment (passed from docker run -e)
TARGET_ARCH="${TARGET_ARCH:-amd64}"

echo "=== EcoOS ISO Builder (Docker) ==="
echo "Target architecture: $TARGET_ARCH"

cd /build

# Determine live-build architecture and image format
case "$TARGET_ARCH" in
    amd64)
        LB_ARCH="amd64"
        IMAGE_FORMAT="iso-hybrid"
        BOOTLOADER_OPT="--bootloader grub-efi"
        ;;
    arm64)
        LB_ARCH="arm64"
        IMAGE_FORMAT="iso-hybrid"
        BOOTLOADER_OPT="--bootloader grub-efi"
        ;;
    rpi)
        LB_ARCH="arm64"
        IMAGE_FORMAT="hdd"
        BOOTLOADER_OPT=""  # RPi uses native bootloader
        ;;
esac

echo "Live-build arch: $LB_ARCH, format: $IMAGE_FORMAT"

# Initialize live-build
lb config \
    --architectures $LB_ARCH \
    --distribution noble \
    --archive-areas "main restricted universe multiverse" \
    --mirror-bootstrap "http://ftp.halifax.rwth-aachen.de/ubuntu/" \
    --mirror-chroot "http://ftp.halifax.rwth-aachen.de/ubuntu/" \
    --mirror-chroot-security "http://ftp.halifax.rwth-aachen.de/ubuntu/" \
    --mirror-binary "http://ftp.halifax.rwth-aachen.de/ubuntu/" \
    --mirror-binary-security "http://ftp.halifax.rwth-aachen.de/ubuntu/" \
    --binary-images $IMAGE_FORMAT \
    --debian-installer false \
    --memtest none \
    $BOOTLOADER_OPT \
    --iso-application "EcoOS" \
    --iso-publisher "EcoBridge" \
    --iso-volume "EcoOS"

# Copy common package lists (excluding architecture-specific ones)
for f in /build/config/live-build/package-lists/*.list.chroot; do
    filename=$(basename "$f")
    # Skip architecture-specific files (base-amd64, base-arm64, base-rpi)
    case "$filename" in
        base-amd64.list.chroot|base-arm64.list.chroot|base-rpi.list.chroot)
            echo "Skipping arch-specific list: $filename"
            ;;
        *)
            cp "$f" config/package-lists/
            ;;
    esac
done

# Append architecture-specific packages to base.list.chroot
if [ -f "/build/config/live-build/package-lists/base-${TARGET_ARCH}.list.chroot" ]; then
    echo "Adding architecture-specific packages for $TARGET_ARCH..."
    cat "/build/config/live-build/package-lists/base-${TARGET_ARCH}.list.chroot" >> config/package-lists/base.list.chroot
fi

# Prepare includes.chroot
mkdir -p config/includes.chroot/opt/eco/bin
mkdir -p config/includes.chroot/opt/eco/daemon
mkdir -p config/includes.chroot/etc/systemd/system

# Copy daemon bundle
cp /build/daemon-bundle/eco-daemon config/includes.chroot/opt/eco/bin/
chmod +x config/includes.chroot/opt/eco/bin/eco-daemon

# Copy pre-downloaded Chromium
echo "Installing pre-downloaded Chromium into chroot..."
mkdir -p config/includes.chroot/opt/chromium
cp -r /build/chromium/* config/includes.chroot/opt/chromium/
chmod +x config/includes.chroot/opt/chromium/chrome

# Create symlinks for chromium-browser command
mkdir -p config/includes.chroot/usr/bin
cat > config/includes.chroot/usr/bin/chromium-browser << 'CHROMEWRAPPER'
#!/bin/sh
exec /opt/chromium/chrome "$@"
CHROMEWRAPPER
chmod +x config/includes.chroot/usr/bin/chromium-browser
ln -sf /opt/chromium/chrome config/includes.chroot/usr/bin/chromium
echo "Chromium installed to /opt/chromium/"

# Create dummy isohybrid in chroot (UEFI-only, no BIOS boot record)
mkdir -p config/includes.chroot/usr/bin
cat > config/includes.chroot/usr/bin/isohybrid << 'ISOHYBRID'
#!/bin/sh
echo "Skipping isohybrid (UEFI-only build)"
exit 0
ISOHYBRID
chmod +x config/includes.chroot/usr/bin/isohybrid

# Copy systemd services
cp /build/config/systemd/eco-daemon.service config/includes.chroot/etc/systemd/system/

# Copy installer (files are already in config/includes.chroot via COPY)
chmod +x config/includes.chroot/opt/eco/installer/install.sh 2>/dev/null || true

# Copy hooks to enable services
mkdir -p config/hooks/normal
cp /build/hooks/normal/*.hook.chroot config/hooks/normal/
chmod +x config/hooks/normal/*.hook.chroot

# Copy autoinstall config
mkdir -p config/includes.binary/autoinstall
cp /build/config/autoinstall/user-data config/includes.binary/autoinstall/
touch config/includes.binary/autoinstall/meta-data

# Architecture-specific EFI/boot setup
if [ "$TARGET_ARCH" = "amd64" ]; then
    # AMD64 EFI boot setup
    echo "Preparing AMD64 EFI boot structure..."
    mkdir -p config/includes.binary/EFI/BOOT
    mkdir -p config/includes.binary/boot/grub

    # Copy signed EFI files from host (installed in Docker image)
    cp /usr/lib/shim/shimx64.efi.signed.latest config/includes.binary/EFI/BOOT/BOOTX64.EFI || \
    cp /usr/lib/shim/shimx64.efi.signed config/includes.binary/EFI/BOOT/BOOTX64.EFI || \
    cp /usr/lib/shim/shimx64.efi config/includes.binary/EFI/BOOT/BOOTX64.EFI || true

    cp /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed config/includes.binary/EFI/BOOT/grubx64.efi || \
    cp /usr/lib/grub/x86_64-efi/grubx64.efi config/includes.binary/EFI/BOOT/grubx64.efi || true

    # Also provide mmx64.efi for some UEFI implementations
    if [ -f config/includes.binary/EFI/BOOT/grubx64.efi ]; then
        cp config/includes.binary/EFI/BOOT/grubx64.efi config/includes.binary/EFI/BOOT/mmx64.efi
    fi

    # Create grub.cfg for live boot with installer option
    cat > config/includes.binary/boot/grub/grub.cfg << 'GRUBCFG'
set default=0
set timeout=10

insmod part_gpt
insmod fat
insmod efi_gop
insmod efi_uga

menuentry "Install EcoOS (auto-selects in 10s)" {
    linux /casper/vmlinuz boot=casper noprompt quiet splash ecoos_install=1 ---
    initrd /casper/initrd
}

menuentry "EcoOS Live (Try without installing)" {
    linux /casper/vmlinuz boot=casper noprompt quiet splash ---
    initrd /casper/initrd
}

menuentry "EcoOS Live (Safe Mode)" {
    linux /casper/vmlinuz boot=casper noprompt nomodeset ---
    initrd /casper/initrd
}
GRUBCFG

    # Also put grub.cfg in EFI/BOOT for fallback
    cp config/includes.binary/boot/grub/grub.cfg config/includes.binary/EFI/BOOT/grub.cfg

elif [ "$TARGET_ARCH" = "arm64" ]; then
    # ARM64 EFI boot setup
    echo "Preparing ARM64 EFI boot structure..."
    mkdir -p config/includes.binary/EFI/BOOT
    mkdir -p config/includes.binary/boot/grub

    # Copy ARM64 GRUB EFI
    cp /usr/lib/grub/arm64-efi-signed/grubaa64.efi.signed config/includes.binary/EFI/BOOT/BOOTAA64.EFI || \
    cp /usr/lib/grub/arm64-efi/grubaa64.efi config/includes.binary/EFI/BOOT/BOOTAA64.EFI || true

    # Create grub.cfg for ARM64
    cat > config/includes.binary/boot/grub/grub.cfg << 'GRUBCFG'
set default=0
set timeout=10

insmod part_gpt
insmod fat
insmod efi_gop

menuentry "Install EcoOS (auto-selects in 10s)" {
    linux /casper/vmlinuz boot=casper noprompt quiet splash ecoos_install=1 ---
    initrd /casper/initrd
}

menuentry "EcoOS Live (Try without installing)" {
    linux /casper/vmlinuz boot=casper noprompt quiet splash ---
    initrd /casper/initrd
}

menuentry "EcoOS Live (Safe Mode)" {
    linux /casper/vmlinuz boot=casper noprompt nomodeset ---
    initrd /casper/initrd
}
GRUBCFG

    cp config/includes.binary/boot/grub/grub.cfg config/includes.binary/EFI/BOOT/grub.cfg

elif [ "$TARGET_ARCH" = "rpi" ]; then
    # Raspberry Pi boot setup (native bootloader, no GRUB)
    echo "Preparing Raspberry Pi boot structure..."
    mkdir -p config/includes.binary/boot

    # Create config.txt for Raspberry Pi
    cat > config/includes.binary/boot/config.txt << 'PICFG'
# EcoOS Raspberry Pi Configuration
# Supports Pi 3, 4, and 5

# Enable 64-bit mode
arm_64bit=1

# Kernel and initrd
kernel=vmlinuz
initramfs initrd.img followkernel

# Enable serial console for debugging
enable_uart=1

# GPU/display settings
dtoverlay=vc4-kms-v3d
gpu_mem=256

# USB and power settings (Pi 4/5)
max_usb_current=1

# Audio
dtparam=audio=on

# Camera/display interfaces
camera_auto_detect=1
display_auto_detect=1

# Pi 5 specific (ignored on older models)
[pi5]
dtoverlay=dwc2,dr_mode=host
PICFG

    # Create cmdline.txt
    cat > config/includes.binary/boot/cmdline.txt << 'CMDLINE'
console=serial0,115200 console=tty1 root=LABEL=EcoOS rootfstype=ext4 fsck.repair=yes rootwait quiet splash
CMDLINE
fi

# Build - use individual lb stages to control the process
echo "Running lb bootstrap..."
lb bootstrap

echo "Running lb chroot..."
lb chroot

# Try lb binary, but continue even if isohybrid fails
echo "Running lb binary..."
lb binary || {
    echo "lb binary had errors, checking if output was created anyway..."
    if ls /build/*.iso 2>/dev/null || ls /build/*.img 2>/dev/null; then
        echo "Output exists despite errors, continuing..."
    else
        echo "No output found, build truly failed"
        exit 1
    fi
}

# Post-processing based on architecture
if [ "$TARGET_ARCH" = "amd64" ] || [ "$TARGET_ARCH" = "arm64" ]; then
    # Find the ISO file
    echo "Searching for ISO file..."
    find /build -name "*.iso" -type f 2>/dev/null
    ls -la /build/*.iso 2>/dev/null || true

    ISO_FILE=$(find /build -name "*.iso" -type f 2>/dev/null | head -1)
    if [ -z "$ISO_FILE" ]; then
        echo "ERROR: No ISO file found in build directory"
        ls -la /build/
        exit 1
    fi

    echo "Found ISO: $ISO_FILE"

    # Rebuild ISO with proper EFI boot support
    echo "Creating UEFI-bootable ISO..."

    # Extract ISO contents
    mkdir -p /tmp/iso_extract
    xorriso -osirrox on -indev "$ISO_FILE" -extract / /tmp/iso_extract

    # Find the actual kernel and initrd names
    VMLINUZ=$(ls /tmp/iso_extract/casper/vmlinuz* 2>/dev/null | head -1 | xargs basename)
    INITRD=$(ls /tmp/iso_extract/casper/initrd* 2>/dev/null | head -1 | xargs basename)

    echo "Found kernel: $VMLINUZ, initrd: $INITRD"

    # Ensure EFI structure exists with proper files
    mkdir -p /tmp/iso_extract/EFI/BOOT
    mkdir -p /tmp/iso_extract/boot/grub

    if [ "$TARGET_ARCH" = "amd64" ]; then
        # Copy AMD64 EFI files
        cp /usr/lib/shim/shimx64.efi.signed.latest /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || \
        cp /usr/lib/shim/shimx64.efi.signed /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || \
        cp /usr/lib/shim/shimx64.efi /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || true

        cp /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed /tmp/iso_extract/EFI/BOOT/grubx64.efi 2>/dev/null || \
        cp /usr/lib/grub/x86_64-efi/grubx64.efi /tmp/iso_extract/EFI/BOOT/grubx64.efi 2>/dev/null || true

        if [ -f /tmp/iso_extract/EFI/BOOT/grubx64.efi ]; then
            cp /tmp/iso_extract/EFI/BOOT/grubx64.efi /tmp/iso_extract/EFI/BOOT/mmx64.efi
        fi

        EFI_BOOT_FILE="BOOTX64.EFI"
    else
        # Copy ARM64 EFI files
        cp /usr/lib/grub/arm64-efi-signed/grubaa64.efi.signed /tmp/iso_extract/EFI/BOOT/BOOTAA64.EFI 2>/dev/null || \
        cp /usr/lib/grub/arm64-efi/grubaa64.efi /tmp/iso_extract/EFI/BOOT/BOOTAA64.EFI 2>/dev/null || true

        EFI_BOOT_FILE="BOOTAA64.EFI"
    fi

    # Update grub.cfg with correct filenames
    cat > /tmp/iso_extract/boot/grub/grub.cfg << GRUBCFG2
set default=0
set timeout=10

insmod part_gpt
insmod fat
insmod efi_gop
$([ "$TARGET_ARCH" = "amd64" ] && echo "insmod efi_uga")

menuentry "Install EcoOS (auto-selects in 10s)" {
    linux /casper/${VMLINUZ} boot=casper noprompt quiet splash ecoos_install=1 ---
    initrd /casper/${INITRD}
}

menuentry "EcoOS Live (Try without installing)" {
    linux /casper/${VMLINUZ} boot=casper noprompt quiet splash ---
    initrd /casper/${INITRD}
}

menuentry "EcoOS Live (Safe Mode)" {
    linux /casper/${VMLINUZ} boot=casper noprompt nomodeset ---
    initrd /casper/${INITRD}
}
GRUBCFG2

    cp /tmp/iso_extract/boot/grub/grub.cfg /tmp/iso_extract/EFI/BOOT/grub.cfg

    # Create EFI boot image (FAT filesystem for UEFI El Torito boot)
    echo "Creating EFI boot image..."
    dd if=/dev/zero of=/tmp/efi.img bs=1M count=10
    mkfs.fat -F 12 /tmp/efi.img
    mmd -i /tmp/efi.img ::/EFI
    mmd -i /tmp/efi.img ::/EFI/BOOT
    mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/$EFI_BOOT_FILE ::/EFI/BOOT/
    if [ "$TARGET_ARCH" = "amd64" ]; then
        mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/grubx64.efi ::/EFI/BOOT/ 2>/dev/null || true
        mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/mmx64.efi ::/EFI/BOOT/ 2>/dev/null || true
    fi
    mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/grub.cfg ::/EFI/BOOT/

    # Rebuild ISO with EFI boot support
    echo "Rebuilding ISO with UEFI boot support..."
    xorriso -as mkisofs \
        -r -V "EcoOS" \
        -o /tmp/ecoos-efi.iso \
        -J -joliet-long \
        -eltorito-alt-boot \
        -e --interval:appended_partition_2:all:: \
        -no-emul-boot -isohybrid-gpt-basdat \
        -append_partition 2 0xef /tmp/efi.img \
        /tmp/iso_extract

    if [ -f /tmp/ecoos-efi.iso ]; then
        ISO_FILE=/tmp/ecoos-efi.iso
        echo "Created UEFI-bootable ISO: $ISO_FILE"
    else
        echo "ERROR: Failed to create EFI ISO"
        exit 1
    fi

    rm -rf /tmp/iso_extract

    # Determine output filename
    if [ "$TARGET_ARCH" = "amd64" ]; then
        OUTPUT_NAME="ecoos.iso"
    else
        OUTPUT_NAME="ecoos-arm64.iso"
    fi

    # Copy to output
    mkdir -p /output
    cp "$ISO_FILE" /output/$OUTPUT_NAME

    echo ""
    echo "=== Final ISO EFI check ==="
    xorriso -indev /output/$OUTPUT_NAME -find / -maxdepth 2 -type d 2>/dev/null || true

    echo ""
    echo "=== Build Complete ==="
    echo "ISO: /output/$OUTPUT_NAME"
    ls -lh /output/$OUTPUT_NAME

elif [ "$TARGET_ARCH" = "rpi" ]; then
    # Raspberry Pi image creation
    echo "Creating Raspberry Pi bootable image..."

    # Find the live-build output
    HDD_FILE=$(find /build -name "*.img" -type f 2>/dev/null | head -1)
    SQUASHFS_FILE=$(find /build -name "filesystem.squashfs" -type f 2>/dev/null | head -1)

    if [ -z "$SQUASHFS_FILE" ]; then
        echo "Looking for squashfs in chroot..."
        SQUASHFS_FILE=$(find /build/chroot -name "filesystem.squashfs" -type f 2>/dev/null | head -1)
    fi

    echo "Found squashfs: $SQUASHFS_FILE"

    # Create RPi image using the helper script
    /build/scripts/create-rpi-image.sh "$SQUASHFS_FILE" /output/ecoos-rpi.img

    echo ""
    echo "=== Build Complete ==="
    echo "Image: /output/ecoos-rpi.img"
    ls -lh /output/ecoos-rpi.img
fi
EOF

RUN chmod +x /build/docker-build.sh

CMD ["/build/docker-build.sh"]
