#! /usr/bin/env sh

stage() {
	CHROOT="$(mktemp -d -p $WORK --suffix=.root)"
	REBASE="$1"
	SOURCE="$2"
	TARGET="$3"

	mount "$SOURCE" "$CRUXMEDIA" || return 1
	mkbootstrap "crux_gnulinux" "$CHROOT" "$CRUXMEDIA/crux/core/"*
	mkbootstrap "crux_gnulinux" "$CHROOT" "$CRUXMEDIA/crux/opt/"*
	mkbootstrap "crux_gnulinux" "$CHROOT" "$CRUXMEDIA/crux/xorg/"*
	umount "$CRUXMEDIA" || return 1

	if test -d "$PWD/ports"; then
		mv "$PWD/ports" "$CHROOT/usr"
	fi

	cp "$PWD/packages.opt" "$CHROOT/packages.opt"

	cp "$PWD/packages.xorg" "$CHROOT/packages.xorg"

	cat > "$CHROOT/etc/ports/core.rsync" <<"EOF"
host=crux.nu
collection=ports/crux-3.6/core/
destination=/usr/ports/core
EOF

	cat > "$CHROOT/etc/ports/opt.rsync" <<"EOF"
host=crux.nu
collection=ports/crux-3.6/opt/
destination=/usr/ports/opt
EOF

	cat > "$CHROOT/etc/ports/xorg.rsync" <<"EOF"
host=crux.nu
collection=ports/crux-3.6/xorg/
destination=/usr/ports/xorg
EOF

	cat >> "$CHROOT/etc/pkgmk.conf" <<"EOF"
export JOBS=$(nproc)
export MAKEFLAGS="-j $(($JOBS * 2))"

PKGMK_COMPRESSION_MODE="xz"
EOF

	setup_chroot "$CHROOT"

	enter_chroot "$CHROOT" <<"EOF"
localedef -i "en_US" -f "UTF-8" "en_US.UTF-8"

export LANG="en_US.UTF-8"

echo -e "toor\ntoor" | (passwd root)
EOF

	DOWNLOAD_RETRY="..."
	while test "$DOWNLOAD_RETRY"; do
		DOWNLOAD_RETRY="${DOWNLOAD_RETRY%?}"

		enter_chroot "$CHROOT" <<"EOF"
ports -u || exit 1

cd /usr/ports
for port in core/* opt/fakeroot; do
	if cd "/usr/ports/$port"; then
		fakeroot -- pkgmk -do || exit 1
	fi
done
cd

cd /usr/ports/core
for pkg in *; do
	if cd "/usr/ports/core/$pkg"; then
		fakeroot -- pkgmk -do || exit 1
	fi
done
cd

cd /usr/ports/opt
for pkg in $(cat /packages.opt); do
	if cd "/usr/ports/opt/$pkg"; then
		fakeroot -- pkgmk -do || exit 1
	fi
done
cd

cd /usr/ports/xorg
for pkg in $(cat /packages.xorg); do
	if cd "/usr/ports/xorg/$pkg"; then
		fakeroot -- pkgmk -do || exit 1
	fi
done
cd
EOF

		EXIT_CODE="$?"

		case "$EXIT_CODE" in
			"0") unset DOWNLOAD_RETRY EXIT_CODE ;;
			"1") sleep 99 ;;
		esac

	done

	if test "$EXIT_CODE"; then
		leave_chroot "$CHROOT"

		return "$EXIT_CODE"
	fi

	# TODO
	# EXIT_CODE for rebuild|release
	case "$REBASE" in
		"rebuild")
			enter_chroot "$CHROOT" <<"EOF"
cd /usr/ports
for port in core/* opt/fakeroot; do
	case "$port" in
		"core/dcron") continue ;;
		"core/dhcpcd") continue ;;
		"core/eudev") continue ;;
		"core/exim") continue ;;
		"core/hdparm") continue ;;
		"core/httpup") continue ;;
		"core/openssh") continue ;;
		"core/sudo") continue ;;
		"core/vim") continue ;;
	esac
	if cd "/usr/ports/$port"; then
		if test -f "/usr/ports/$port/pre-install"; then
			chmod +x /usr/ports/$port/pre-install
			/usr/ports/$port/pre-install
		fi
		fakeroot -- pkgmk || exit 1
	fi
done
cd
EOF
			;;
		"release")
			cat >> "$CHROOT/etc/prt-get.conf" <<"EOF"
writelog enabled
logmode  overwrite
rmlog_on_success no

runscripts yes

makecommand      fakeroot -- pkgmk
EOF

			enter_chroot "$CHROOT" <<"EOF"
for port in $(cd /usr/ports/core ; find * -maxdepth 0 -type d) $(cat /packages.xorg) $(cat /packages.opt); do
	if prt-get isinst "$port"; then
		prt-get update -fr $port
	else
		prt-get depinst -fr $port
	fi
done

echo $(cd /usr/ports/core ; find * -maxdepth 0 -type d) $(cat /packages.opt) $(cat /packages.xorg) | tr ' ' '\n' | sort > /packages.required
prt-get listinst | sort > /packages.installed
EOF
			mv "$CHROOT/packages.required" "$DISTFILES"
			mv "$CHROOT/packages.installed" "$DISTFILES"
			mv "$CHROOT/var/log/pkgbuild" "$DISTFILES"
			mv "$CHROOT/var/lib/pkg/db" "$DISTFILES"
			;;
	esac

	leave_chroot "$CHROOT"

	find "$CRUXMEDIA" -mindepth 1 -delete

	for port in core opt xorg; do
		mkdir -p "$CRUXMEDIA/crux/$port"
		find "$CHROOT/usr/ports/$port" -name "*.pkg.tar.xz" -exec mv "{}" "$CRUXMEDIA/crux/$port" \;
	done

	mv "$CHROOT/usr/ports" "$PWD"

	mkbootisofs "$CRUXMEDIA" --output "$TARGET"
}

setup_chroot() {
	ROOT="$1"

	mount -B "/dev" "$ROOT/dev"
	mount -B "/tmp" "$ROOT/tmp"
	mount -B "/run" "$ROOT/run"
	mount -t proc proc "$ROOT/proc"
	mount -t sysfs none "$ROOT/sys"
	mount -t devpts -o noexec,nosuid,gid=tty,mode=0620 devpts "$ROOT/dev/pts"

	if grep -qs "/sys/firmware/efi/efivars" "/proc/mounts"; then
		mount -B -o ro "/sys/firmware/efi/efivars" "$ROOT/sys/firmware/efi/efivars"
	fi

	cp "/etc/resolv.conf" "$ROOT/etc/resolv.conf"
}

enter_chroot() {
	ROOT="$1"

	chroot "$ROOT" /usr/bin/env PS1="(chroot) $PS1" /bin/bash
}

leave_chroot() {
	ROOT="$1"

	for mount in $(grep "$ROOT" "/proc/mounts" | awk '{print $2}'); do
		umount -R "$mount"
	done
}

kernel_release() {
	mkdir -p "$BOOTIMAGE/crux/kernel"

	cd "$(newkernel 5.4.53 -s $BOOTIMAGE/crux/kernel)"

	make defconfig

	install -D ".config" "../linux-5.4.53.defconfig"

	make kvmconfig

	install -D ".config" "../linux-5.4.53.kvmconfig"

	# SquashFS + OverlayFS
	scripts/config -e OVERLAY_FS

	scripts/config -e SQUASHFS
	scripts/config -e SQUASHFS_XZ

	# Auto select dependencies
	make olddefconfig

	make -j$(($(nproc) * 2))

	install -D "arch/x86/boot/bzImage" "$BOOTIMAGE/boot/vmlinuz"

	make tarxz-pkg

	tar -x -f *".tar.xz" -C "$BOOTSTRAP"

	cd "$OLDPWD"

	rm -r -f "$OLDPWD"
}

os_release() {
	mkbootstrap "crux_gnulinux" "$BOOTSTRAP" --ports "$CRUXMEDIA/crux/core" $(cat /usr/systems/crux/crux_gnulinux-embedded/packages.core)

	mv "$CRUXMEDIA/crux/core" "$BOOTIMAGE/crux"
	mv "$CRUXMEDIA/crux/opt" "$BOOTIMAGE/crux"
	mv "$CRUXMEDIA/crux/xorg" "$BOOTIMAGE/crux"

	mkinitramfs "$INITRAMFS" --output "$INITRAMFS.img"
	xz --check="crc32" --threads=0 "$INITRAMFS.img"

	install -D "$INITRAMFS.img.xz" "$BOOTIMAGE/boot/initrd"

	mkbootisofs "$BOOTIMAGE" \
		--legacy-boot "grub2" --efi "grub2" \
		--overlay "$BOOTSTRAP" --squashfs \
		--output "$DISTFILES/crux-gnulinux-stage3-amd64-$(date -u +%Y%m%dT%H%M%SZ).iso"
}

build() {
	BOOTSTRAP="$WORK/bootstrap"
	BOOTIMAGE="$WORK/bootimage"
	INITRAMFS="$WORK/initramfs"
	CRUXMEDIA="$WORK/cruxmedia"
	DISTFILES="$WORK/distfiles"

	for dir in $BOOTSTRAP $BOOTIMAGE $INITRAMFS $CRUXMEDIA $DISTFILES; do
		mkdir -p "$dir"
	done

	MASTERURL="http://ftp.morpheus.net/pub/linux/crux/crux-3.5/iso/crux-3.5.iso"
	MASTERISO="$PWD/master.iso"
	STAGE0ISO="$DISTFILES/stage0.iso"
	STAGE1ISO="$DISTFILES/stage1.iso"
	STAGE2ISO="$DISTFILES/stage2.iso"
	STAGE3ISO="$DISTFILES/stage3.iso"

	test -f "$MASTERISO" || wget -T 5 -O "$MASTERISO" "$MASTERURL" || return 1

	for loop in 0 1 2 3; do
		case "$loop" in
			"0") stage "rebuild" "$MASTERISO" "$STAGE0ISO" ;;
			"1") stage "rebuild" "$STAGE0ISO" "$STAGE1ISO" ;;
			"2") stage "rebuild" "$STAGE1ISO" "$STAGE2ISO" ;;
			"3") stage "release" "$STAGE2ISO" "$STAGE3ISO" ;;
		esac
	done

	kernel_release

	os_release

	mv "$DISTFILES/"* "$DIST"
}
