#!/bin/bash
#
# make-iso.sh — Assemble a bootable FenrirOS ISO from RPMs
#
# This script runs INSIDE the build chroot (via systemd-nspawn).
# It installs all RPMs into a fresh rootfs, configures the system,
# builds an initramfs, creates a squashfs, and masters a bootable ISO.
#
# Usage (from host):
#   sudo systemd-nspawn ... -D /var/lib/fenriros-buildroot/rootfs --pipe -- \
#       bash /build/rpmbuild/make-iso.sh [RPM_DIR] [OUTPUT]
#
# Args:
#   RPM_DIR  — directory containing *.rpm files (default: /build/rpmbuild/RPMS/x86_64)
#   OUTPUT   — output ISO path (default: /build/fenriros-x86_64.iso)
#
set -euo pipefail

RPM_DIR="${1:-/build/rpmbuild/RPMS/x86_64}"
OUTPUT="${2:-/build/fenriros-x86_64.iso}"
SYSROOT="/build/fenriros-system"
ISOROOT="/build/fenriros-iso"
WORKDIR="/build/fenriros-work"

export PATH=/usr/local/musl/bin:/usr/local/bin:$PATH

die() { echo "FATAL: $*" >&2; exit 1; }

# ── Sanity checks ────────────────────────────────────────────────────────
[ -d "$RPM_DIR" ] || die "RPM directory not found: $RPM_DIR"
ls "$RPM_DIR"/*.rpm >/dev/null 2>&1 || die "No RPMs in $RPM_DIR"
command -v rpm       >/dev/null || die "rpm not found"
command -v mksquashfs >/dev/null || die "mksquashfs not found"
command -v xorriso   >/dev/null || die "xorriso not found"
command -v zstd      >/dev/null || die "zstd not found"

echo "========================================"
echo " FenrirOS ISO Builder"
echo "========================================"
echo "RPM dir : $RPM_DIR"
echo "Output  : $OUTPUT"
echo "RPMs    : $(ls "$RPM_DIR"/*.rpm | wc -l)"
echo ""

# ── 1) Install all RPMs into fresh rootfs ─────────────────────────────────
echo "=== [1/7] Installing RPMs into rootfs ==="
rm -rf "$SYSROOT" "$ISOROOT" "$WORKDIR"
mkdir -p "$SYSROOT"

# Install musl first (provides base headers/libc)
rpm -ivh --nodeps --nosignature --root="$SYSROOT" \
    "$RPM_DIR"/musl-*.rpm 2>&1 | tail -1

# Install all remaining RPMs (--force for directory ownership overlaps)
rpm -ivh --nodeps --force --nosignature --root="$SYSROOT" \
    "$RPM_DIR"/*.rpm 2>&1 | tail -3

echo "Rootfs: $(du -sh "$SYSROOT" | cut -f1)"

# ── 2) Configure system ──────────────────────────────────────────────────
echo "=== [2/7] Configuring system ==="

# Essential directories
mkdir -p "$SYSROOT"/{bin,sbin,dev,proc,sys,run,tmp,var/log,var/run,home,root,etc,lib}
mkdir -p "$SYSROOT"/var/lib/fenriros/rpms

# Toybox symlinks
if [ -x "$SYSROOT/usr/bin/toybox" ]; then
    CMDS=$("$SYSROOT/usr/bin/toybox" 2>&1 | tr " " "\n" | grep -v "^$")
    for cmd in $CMDS; do
        ln -sf /usr/bin/toybox "$SYSROOT/bin/$cmd" 2>/dev/null || true
    done
    # Critical sbin links
    for cmd in modprobe insmod rmmod lsmod modinfo depmod halt reboot poweroff \
               ifconfig route hwclock sysctl mount umount switch_root pivot_root \
               losetup blkid fsck mkswap swapon swapoff; do
        ln -sf /usr/bin/toybox "$SYSROOT/sbin/$cmd" 2>/dev/null || true
    done
    echo "Toybox: $(ls "$SYSROOT/bin/" | wc -l) /bin + $(ls "$SYSROOT/sbin/" | wc -l) /sbin"
fi

# Dynamic linker
ln -sf /usr/lib/libc.so "$SYSROOT/lib/ld-musl-x86_64.so.1" 2>/dev/null || true

# Init system
if [ -x "$SYSROOT/usr/sbin/syslite" ]; then
    ln -sf /usr/sbin/syslite "$SYSROOT/sbin/init"
    ln -sf /usr/sbin/syslite "$SYSROOT/sbin/syslite"
    ln -sf /usr/sbin/syslite "$SYSROOT/init"
fi

# Users
cat > "$SYSROOT/etc/passwd" << 'EOF'
root:x:0:0:root:/root:/bin/sh
sshd:x:74:74:sshd:/var/empty/sshd:/bin/false
postgres:x:26:26:PostgreSQL:/var/lib/postgresql:/bin/sh
EOF
cat > "$SYSROOT/etc/group" << 'EOF'
root:x:0:
sshd:x:74:
postgres:x:26:
EOF
# root password: fenriros
cat > "$SYSROOT/etc/shadow" << 'EOF'
root:$6$fenriros$kJ6Mv2VwCYk3JFPvNqFj.Vp4KDBOGm8Rr8LH7BFk1E9zIz/SKSV0XrLqZ8lKjyiX.gG2F7Y8fDBvxNpOqGp.:19000:0:99999:7:::
sshd:!:19000:0:99999:7:::
postgres:!:19000:0:99999:7:::
EOF
chmod 600 "$SYSROOT/etc/shadow"

# Profile
cat > "$SYSROOT/etc/profile" << 'EOF'
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
export HOME="${HOME:-/root}"
export PS1='[\u@\h \W]\$ '
export TERM=linux
alias ls='ls --color=auto'
EOF

# Hostname
echo "fenriros" > "$SYSROOT/etc/hostname"

# Network: DHCP on wired interfaces
mkdir -p "$SYSROOT/etc/systemd/network"
cat > "$SYSROOT/etc/systemd/network/10-wired.network" << 'EOF'
[Match]
Name=en* eth*

[Network]
DHCP=yes
EOF

# SSH configuration
mkdir -p "$SYSROOT/etc/ssh" "$SYSROOT/var/empty/sshd"
cat > "$SYSROOT/etc/ssh/sshd_config" << 'EOF'
Port 22
PermitRootLogin yes
PasswordAuthentication yes
UsePAM no
Subsystem sftp internal-sftp
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
EOF

# Syslite sshd service
mkdir -p "$SYSROOT/etc/syslite/services"
cat > "$SYSROOT/etc/syslite/services/sshd.service" << 'EOF'
[Service]
ExecStartPre=/usr/bin/ssh-keygen -A
ExecStart=/usr/sbin/sshd -D -e
Restart=always
EOF

# Stage RPMs for self-hosting
cp "$RPM_DIR"/*.rpm "$SYSROOT/var/lib/fenriros/rpms/" 2>/dev/null || true

echo "System configured"

# ── 3) Build initramfs ───────────────────────────────────────────────────
echo "=== [3/7] Building initramfs ==="
mkdir -p "$WORKDIR/initramfs"/{bin,proc,sys,dev,newroot,mnt,lib}

cp -a "$SYSROOT/usr/bin/toybox" "$WORKDIR/initramfs/bin/toybox"
ln -sf toybox "$WORKDIR/initramfs/bin/sh"

# e2fsck for early boot repair
if [ -f "$SYSROOT/usr/sbin/e2fsck" ]; then
    cp -a "$SYSROOT/usr/sbin/e2fsck" "$WORKDIR/initramfs/bin/e2fsck"
    ln -sf e2fsck "$WORKDIR/initramfs/bin/fsck.ext4"
fi

# musl dynamic linker (for dynamically linked binaries like e2fsck)
if [ -f "$SYSROOT/usr/lib/libc.so" ]; then
    cp "$SYSROOT/usr/lib/libc.so" "$WORKDIR/initramfs/lib/ld-musl-x86_64.so.1"
    ln -sf ld-musl-x86_64.so.1 "$WORKDIR/initramfs/lib/libc.so"
fi

# Toybox applet symlinks for initramfs
for cmd in modprobe insmod rmmod lsmod modinfo depmod mount umount \
           switch_root cat ls mkdir mknod sleep losetup blkid; do
    ln -sf toybox "$WORKDIR/initramfs/bin/$cmd"
done

# Init script
cat > "$WORKDIR/initramfs/init" << 'EINIT'
#!/bin/toybox sh
/bin/toybox mount -t proc proc /proc
/bin/toybox mount -t sysfs sys /sys
/bin/toybox mount -t devtmpfs dev /dev
/bin/toybox mkdir -p /mnt /newroot

# Installed-system boot: root=<dev> or root=UUID=<uuid>
ROOTSPEC=""
ROOTFLAGS="rw"
for tok in $(/bin/toybox cat /proc/cmdline 2>/dev/null); do
    case "$tok" in
        root=*) ROOTSPEC="${tok#root=}" ;;
        ro)     ROOTFLAGS="ro" ;;
        rw)     ROOTFLAGS="rw" ;;
    esac
done

if [ -n "$ROOTSPEC" ]; then
    rootdev=""
    i=0
    while [ -z "$rootdev" ] && [ "$i" -lt 30 ]; do
        case "$ROOTSPEC" in
            UUID=*) rootdev=$(/bin/toybox blkid -U "${ROOTSPEC#UUID=}" 2>/dev/null) ;;
            *)      [ -b "$ROOTSPEC" ] && rootdev="$ROOTSPEC" ;;
        esac
        [ -n "$rootdev" ] && break
        /bin/toybox sleep 1; i=$((i + 1))
    done
    if [ -n "$rootdev" ]; then
        [ -x /bin/e2fsck ] && /bin/e2fsck -p "$rootdev" || true
        if /bin/toybox mount -t ext4 -o "$ROOTFLAGS" "$rootdev" /newroot 2>/dev/null; then
            exec /bin/toybox switch_root /newroot /sbin/syslite
        fi
    fi
    echo "Failed to mount root=$ROOTSPEC"
    exec /bin/toybox sh
fi

# Live ISO boot: scan block devices for filesystem.squashfs
try_boot() {
    for dev in $(/bin/toybox ls /sys/block 2>/dev/null); do
        case "$dev" in loop*|ram*|zram*|dm-*) continue ;; esac
        for node in "/dev/$dev" /dev/"$dev"*; do
            [ -b "$node" ] || continue
            /bin/toybox mount -t iso9660 -o ro "$node" /mnt 2>/dev/null \
              || /bin/toybox mount -t udf -o ro "$node" /mnt 2>/dev/null \
              || continue
            if [ -f /mnt/boot/filesystem.squashfs ]; then
                [ -e /dev/loop-control ] || /bin/toybox mknod /dev/loop-control c 10 237 2>/dev/null
                ln=0
                while [ "$ln" -lt 8 ]; do
                    [ -e "/dev/loop$ln" ] || /bin/toybox mknod "/dev/loop$ln" b 7 "$ln" 2>/dev/null
                    if /bin/toybox losetup -r "/dev/loop$ln" /mnt/boot/filesystem.squashfs 2>/dev/null \
                       && /bin/toybox mount -t squashfs -o ro "/dev/loop$ln" /newroot 2>/dev/null; then
                        exec /bin/toybox switch_root /newroot /sbin/syslite
                    fi
                    /bin/toybox losetup -d "/dev/loop$ln" 2>/dev/null
                    ln=$((ln + 1))
                done
            fi
            /bin/toybox umount /mnt 2>/dev/null
        done
    done
    return 1
}

i=0
while [ "$i" -lt 30 ]; do
    try_boot
    /bin/toybox sleep 1; i=$((i + 1))
done

# Fallback: try to find an installed FenrirOS on any ext4 partition
echo "No ISO image found, scanning for installed system..."
for dev in $(/bin/toybox ls /sys/block 2>/dev/null); do
    case "$dev" in loop*|ram*|zram*|dm-*) continue ;; esac
    for node in "/dev/$dev" /dev/${dev}*; do
        [ -b "$node" ] || continue
        if /bin/toybox mount -t ext4 -o ro "$node" /newroot 2>/dev/null; then
            if [ -x /newroot/sbin/syslite ]; then
                echo "Found installed system on $node"
                /bin/toybox umount /newroot
                /bin/toybox mount -t ext4 -o rw "$node" /newroot
                exec /bin/toybox switch_root /newroot /sbin/syslite
            fi
            /bin/toybox umount /newroot 2>/dev/null
        fi
    done
done

echo "FenrirOS initramfs shell (no system image found)"
exec /bin/toybox sh
EINIT
chmod +x "$WORKDIR/initramfs/init"

# Create cpio + zstd compress
cd "$WORKDIR/initramfs"
find . | /usr/local/bin/toybox cpio -o -H newc > "$WORKDIR/initramfs.cpio"
zstd -19 -f "$WORKDIR/initramfs.cpio" -o "$WORKDIR/initramfs.zst"
rm -f "$WORKDIR/initramfs.cpio"
echo "Initramfs: $(ls -lh "$WORKDIR/initramfs.zst" | awk '{print $5}')"

# Also stage initramfs in rootfs for disk installer
cp "$WORKDIR/initramfs.zst" "$SYSROOT/boot/initramfs.zst"

# ── 4) Stage ISO root ────────────────────────────────────────────────────
echo "=== [4/7] Staging ISO root ==="
mkdir -p "$ISOROOT/boot/limine" "$ISOROOT/EFI/BOOT"

# Kernel
cp -a "$SYSROOT/boot/vmlinuz" "$ISOROOT/boot/vmlinuz"

# Initramfs
cp "$WORKDIR/initramfs.zst" "$ISOROOT/boot/initramfs.zst"

# Limine bootloader
cp -a "$SYSROOT/usr/share/limine/limine-bios.sys"    "$ISOROOT/boot/limine/"
cp -a "$SYSROOT/usr/share/limine/limine-bios-cd.bin" "$ISOROOT/boot/limine/"
cp -a "$SYSROOT/usr/share/limine/limine-uefi-cd.bin" "$ISOROOT/boot/limine/"
cp -a "$SYSROOT/usr/share/limine/BOOTX64.EFI"        "$ISOROOT/EFI/BOOT/"

# Limine config
cat > "$ISOROOT/boot/limine/limine.conf" << 'LIMCFG'
timeout: 3
/FenrirOS (musl/LLVM, no GNU tools)
    protocol: linux
    kernel_path: boot():/boot/vmlinuz
    module_path: boot():/boot/initramfs.zst
    cmdline: console=tty0
LIMCFG

echo "ISO root staged"

# ── 5) Create squashfs ───────────────────────────────────────────────────
echo "=== [5/7] Creating filesystem.squashfs ==="
mksquashfs "$SYSROOT" "$ISOROOT/boot/filesystem.squashfs" \
    -comp zstd -noappend -no-progress 2>&1 | tail -3
echo "Squashfs: $(ls -lh "$ISOROOT/boot/filesystem.squashfs" | awk '{print $5}')"

# ── 6) Master ISO ────────────────────────────────────────────────────────
echo "=== [6/7] Mastering ISO ==="
xorriso -as mkisofs \
    -R -r -J \
    -b boot/limine/limine-bios-cd.bin \
    -no-emul-boot -boot-load-size 4 -boot-info-table \
    --efi-boot boot/limine/limine-uefi-cd.bin \
    -efi-boot-part --efi-boot-image --protective-msdos-label \
    -volid FENRIROS \
    "$ISOROOT" -o "$OUTPUT" 2>&1 | tail -3

# ── 7) Limine BIOS install ───────────────────────────────────────────────
echo "=== [7/7] Installing Limine BIOS stage ==="
if [ -x "$SYSROOT/usr/bin/limine" ]; then
    "$SYSROOT/usr/bin/limine" bios-install "$OUTPUT" 2>&1 || true
fi

echo ""
echo "========================================"
echo " ISO created successfully"
echo "========================================"
ls -lh "$OUTPUT"
sha256sum "$OUTPUT"
echo ""
echo "Rootfs : $(du -sh "$SYSROOT" | cut -f1)"
echo "RPMs   : $(ls "$RPM_DIR"/*.rpm | wc -l) packages"
echo "Boot   : Limine BIOS+UEFI"
echo "Init   : syslite"
echo "Root pw: fenriros"
