# SPDX-License-Identifier: MPL-2.0
set -e
run() {
  local cmd="$1"
  local success_msg="$2"
  local error_msg="$3"
  shift 3
  tmpfile=$(mktemp)
  if eval "$cmd" >"$tmpfile" 2>&1; then
    echo "${success_msg:-[OK] Command succeeded}"
    rm -f "$tmpfile"
    return 0
  else
    echo -e "${error_msg:-[ERR] Command failed]}"
    cat "$tmpfile"
    rm -f "$tmpfile"
    return 1
  fi
}

rm -rf initfs_dir
mkdir -p initfs_dir

echo "[Build] Checking virtual memory layout:"
echo ""
python3 shelter/tools/checker/vmem_layout_check.py shelter/lib/include/memory/vmem_layout.h
echo ""

mkdir -p shelter/lib/include/kernel/tests/payloads

echo "[Build] Generating kernel payloads:"
echo -n "[Build]   Radix tests..."
run "python shelter/tools/generator/radix_tree_payload_gen.py > shelter/lib/include/kernel/tests/payloads/test_radix_payload.h" " done." "\n[Build] Error:\n"
echo -n "[Build]   Pez tests..."
run "python shelter/tools/generator/pez_alloc_free_payload_gen.py > shelter/lib/include/kernel/tests/payloads/test_pez_payload.h" " done." "\n[Build] Error:\n"
echo -n "[Build]   Malloc tests..."
run "python shelter/tools/generator/malloc_payload_gen.py > shelter/lib/include/kernel/tests/payloads/test_malloc_payload.h" " done." "\n[Build] Error:\n"
echo "[Build] Successfully generated kernel payloads."

echo "[Build] Compiling keycard:"
echo -n "[Build]   Changing directory..."
run "cd Blastproof/src" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cleaning up..."
run "rm -f ./keycard.bin" " done." "\n[Build] Error:\n"
echo -n "[Build]   Compiling keycard executable..."
run "nasm -f bin keycard.asm -o keycard.bin" " done." "\n[Build] Error:\n"
echo -n "[Build]   Moving keycard to InitFS..."
run "mv keycard.bin ../../initfs_dir/" " done." "\n[Build] Error:\n"
echo -n "[Build]   Exiting directory..."
run "cd ../.." " done." "\n[Build] Error:\n"
echo "[Build] Successfully compiled keycard."

echo "[Build] Compiling vyld and Shelter:"
echo -n "[Build]   Changing directory..."
run "cd vyld" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cleaning up..."
run "rm -f ./vyld" " done." "\n[Build] Error:\n"
echo -n "[Build]   Compiling vyld executable..."
run "g++ vyld.cpp -o vyld" " done." "\n[Build] Error:\n"
echo -n "[Build]   Granting permissions to execute vyld..."
run "chmod +x ./vyld" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cleaning up..."
run "rm -f *.o *.vyx *.elf *.bin" " done." "\n[Build] Error:\n"
echo -n "[Build]   Changing directory..."
run "cd ../shelter" " done." "\n[Build] Error:\n"
echo "[Build]   Compiling Shelter:"
echo ""
VYLD_COMPILATION_FLAGS="-fno-stack-protector -O1 -Wall -Wextra -Werror -Wpedantic -Wshadow -Wconversion -Wsign-conversion -Wstrict-prototypes -Wmissing-prototypes -Wundef -fmax-errors=0 -Ilib/include/" \
  ../vyld/vyld main.c \
  lib/src/kernel/log.c \
  lib/src/kernel/conf.c \
  lib/src/kernel/tests/test_utils.c \
  lib/src/kernel/tests/test_slabs.c \
  lib/src/kernel/tests/test_radix.c \
  lib/src/kernel/tests/test_pez.c \
  lib/src/kernel/tests/test_malloc.c \
  lib/src/std/mem.c \
  lib/src/std/malloc.c \
  lib/src/cpu/tsc.c \
  lib/src/cpu/serial.c \
  lib/src/memory/page.c \
  lib/src/memory/ring.c \
  lib/src/memory/pba.c \
  lib/src/memory/heap.c \
  lib/src/memory/slabs/slab_reg_phys.c \
  lib/src/memory/slabs/slab_reg_virt.c \
  lib/src/memory/slabs/slab_radix_node.c \
  lib/src/memory/slabs/slab_generic.c \
  lib/src/memory/pez/pez.c \
  lib/src/memory/pez/pez_debug.c \
  lib/src/memory/pez/radix.c \
  shelter.vyx
echo ""
echo -n "[Build]   Copying Shelter executable.."
run "mv shelter.vyx ../initfs_dir/" " done." "\n[Build] Error:\n"
echo -n "[Build]   Exiting directory..."
run "cd .." " done." "\n[Build] Error:\n"
echo "[Build] Successfully compiled all files."

if [ ! -d "edk2" ]; then
  echo "[Build] Cloning and setuping edk2:"
  echo "[Build]   Cloning edk2:"
  git clone https://github.com/tianocore/edk2.git
  echo -n "[Build]   Entering directory..."
  run "cd edk2" " done." "\n[Build] Error:\n"
  echo "[Build]   Cloning submodule:"
  git submodule update --init --recursive --progress
  echo "[Build]   Compiling necessary tools:"
  make -C BaseTools/
  tmpfile=$(mktemp)
  echo -n "[Build]   Setuping environment..."
  . ./edksetup.sh >"$tmpfile" 2>&1
  status=$?
  if [[ $status -eq 0 ]]; then
    echo " done."
  else
    echo -e "\n[Build] Error:\n$(cat "$tmpfile")"
    exit $status
  fi
  rm -f "$tmpfile"
  echo -n "[Build]   Building OVMF..."
  run "build -p OvmfPkg/OvmfPkgX64.dsc -b RELEASE -a X64 -t GCC" " done." "\n[Build] Error:\n"
  echo -n "[Build]   Exiting directory..."
  run "cd .." " done." "\n[Build] Error:\n"
  echo "[Build] Succesfully setuped edk2."
fi

cd edk2
tmpfile=$(mktemp)
echo -n "[Build] Setuping environment..."
. ./edksetup.sh >"$tmpfile" 2>&1
status=$?
if [[ $status -eq 0 ]]; then
  echo " done."
else
  echo -e "\n[Build] Error:\n$(cat "$tmpfile")"
  exit $status
fi
rm -f "$tmpfile"
cd ..

echo -n "[Build] Copying Blastproof files..."
cp ./Blastproof ./edk2/ -r
echo " done."
echo -n "[Build] Entering directory..."
cd edk2
echo " done."

echo "[Build] Building bootanim executable:"
echo -n "[Build]   Changing directory..."
run "cd Blastproof/bootanim" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cleaning up..."
run "rm bootanim bootanim.bin -f" " done." "\n[Build] Error:\n"
echo -n "[Build]   Compiling bootanim..."
run "g++ bootanim.cpp -o bootanim -Ofast -march=native" " done." "\n[Build] Error:\n"
echo -n "[Build]   Giving permissions to execute bootanim..."
run "chmod +x bootanim" " done." "\n[Build] Error:\n"
echo "[Build] Bootanim executable built."

echo "[Build] Building boot animation:"
echo -n "[Build]   Generating boot animation... "
run "./bootanim logo.png file 1920 1080" " done." "\n[Build] Error:\n"
echo -n "[Build]   Exiting directory... "
run "cd ../.." " done." "\n[Build] Error:\n"
echo "[Build] Boot animation built."

echo "[Build] Building fontgen executable:"
echo -n "[Build]   Changing directory..."
run "cd Blastproof/fontgen" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cleaning up..."
run "rm fontgen bitra-ascii-medium.fbm -f" " done." "\n[Build] Error:\n"
echo -n "[Build]   Compiling fontgen..."
run "g++ fontgen.cpp -o fontgen" " done." "\n[Build] Error:\n"
echo -n "[Build]   Giving permissions to execute fontgen..."
run "chmod +x fontgen" " done." "\n[Build] Error:\n"
echo "[Build] Fontgen executable built."

echo "[Build] Building Bitra font:"
echo -n "[Build]   Running fontgen..."
run "./fontgen \"#FFFFFF\" \"#000000\" ascii ./chars" " done." "\n[Build] Error:\n"
echo -n "[Build]   Renaming generated font..."
run "mv font.fbm bitra-ascii-medium.fbm" " done." "\n[Build] Error:\n"
echo -n "[Build]   Exiting directory..."
run "cd ../.." " done." "\n[Build] Error:\n"
echo "[Build] Bitra font built."

echo "[Build] Building initfsgen executable:"
echo -n "[Build]   Changing directory..."
run "cd Blastproof/initfsgen" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cleaning up..."
run "rm -f initfsgen" " done." "\n[Build] Error:\n"
echo -n "[Build]   Compiling initfsgen..."
run "./build.sh" " done." "\n[Build] Error:\n"
echo -n "[Build]   Giving permissions to execute initfsgen..."
run "chmod +x ./initfsgen" " done." "\n[Build] Error:\n"
echo -n "[Build]   Exiting directory..."
run "cd ../.." " done." "\n[Build] Error:\n"
echo "[Build] Initfsgen executable built."

echo "[Build] Generating initfs:"
echo -n "[Build]   Changing directory..."
run "cd Blastproof/initfsgen" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cleaning up..."
run "rm -f initfs.bin initfs-footprint.bin signsyst.bin" " done." "\n[Build] Error:\n"
echo -n "[Build]   Generating initfs..."
run "./initfsgen ../../../initfs_dir" " done." "\n[Build] Error:\n"
echo -n "[Build]   Exiting directory..."
run "cd ../.." " done." "\n[Build] Error:\n"
echo "[Build] Initfs generated."

echo "[Build] Setting up GUIDs:"
echo -n "[Build]   Removing old configuration..."
run "rm -f Blastproof/config/bp.conf" " done." "\n[Build] Error:\n"
echo -n "[Build]   Generating GUIDs..."
INITFS_TYPE_GUID="8362b434-d825-11f0-a68f-10ffe08423a6"
SIGNSYST_TYPE_GUID="da0048b4-d826-11f0-b877-10ffe08423a6"
INITFS_GUID=$(uuidgen)
SIGNSYST_GUID=$(uuidgen)
echo " done."
echo -n "[Build]   Copying configuration..."
run "cp Blastproof/config/bp_template.conf Blastproof/config/bp.conf" " done." "\n[Build] Error:\n"
echo -n "[Build]   Patching configuration for InitFS configuration..."
run "sed -i -E \"s/=(UUID_GENERATION_NEEDED_INITFS)/=$INITFS_GUID/\" Blastproof/config/bp.conf" " done." "\n[Build] Error:\n"
echo -n "[Build]   Patching configuration for SignSyst configuration..."
run "sed -i -E \"s/=(UUID_GENERATION_NEEDED_SIGNSYST)/=$SIGNSYST_GUID/\" Blastproof/config/bp.conf" " done." "\n[Build] Error:\n"
echo "[Build] GUIDs setup completed."

echo "[Build] Building keygen:"
echo -n "[Build]   Changing directory..."
run "cd Blastproof/keygen" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cleaning up directories..."
run "rm argon2 -rf" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cleaning up files..."
run "rm keygen libargon2.a argon2.h -f" " done." "\n[Build] Error:\n"
echo -n "[Build]   Cloning argon2..."
run "wget https://github.com/P-H-C/phc-winner-argon2/archive/refs/heads/master.zip" " done." "\n[Build] Error:\n"
echo -n "[Build]   Unziping argon2..."
run "unzip -qo master.zip" " done." "\n[Build] Error:\n"
echo -n "[Build]   Renamming argon2 folder..."
run "mv phc-winner-argon2-master argon2" " done." "\n[Build] Error:\n"
echo -n "[Build]   Removing downloaded archive..."
run "rm master.zip" " done." "\n[Build] Error:\n"
echo -n "[Build]   Changing directory..."
run "cd argon2" " done." "\n[Build] Error:\n"
echo -n "[Build]   Compiling argon2..."
run "make" " done." "\n[Build] Error:\n"
echo -n "[Build]   Exiting directory..."
run "cd .." " done." "\n[Build] Error:\n"
echo -n "[Build]   Moving argon2 library..."
run "mv ./argon2/libargon2.a ./libargon2.a" " done." "\n[Build] Error:\n"
echo -n "[Build]   Moving argon2 header..."
run "mv ./argon2/include/argon2.h ./argon2.h" " done." "\n[Build] Error:\n"
echo -n "[Build]   Compiling keygen..."
run "./build.sh" " done." "\n[Build] Error:\n"
echo -n "[Build]   Giving permissions to execute keygen..."
run "chmod +x keygen" " done." "\n[Build] Error:\n"
echo -n "[Build]   Exiting folder..."
run "cd .." " done." "\n[Build] Error:\n"
echo "[Build] Keygen executable built."

echo "[Build] Generating key for important files:"
echo "[Build]   Obtaining permissions:"
sudo echo -n ""
echo -e "[Build]   Running keygen:\n"
sudo ./keygen/keygen ./config/bp.conf ./fontgen/bitra-ascii-medium.fbm ./initfsgen/initfs-footprint.bin ./initfsgen/signsyst-hash.bin
echo -n "[Build]   Moving generated header file..."
run "sudo mv -f key.h ./src/libs/include/key.h" " done." "\n[Build] Error:\n"
echo "[Build] Keys generated."

echo "[Build] Building Blastproof:"
echo -n "[Build]   Changing directory..."
run "cd .." " done." "\n[Build] Error:\n"
echo -n "[Build]   Building Blastproof..."
run "build --platform=Blastproof/blastproof.dsc --module=Blastproof/src/main.inf --arch=X64 --buildtarget=RELEASE --tagname=GCC" " done." "\n[Build] Error:\n"
echo "[Build] Blastproof built."

echo "[Build] Building disk image:"
echo -n "[Build]   Removing old disk image..."
run "rm -rf disk.img" " done." "\n[Build] Error:\n"
echo -n "[Build]   Creating a new disk image..."
run "fallocate -l 1024M disk.img" " done." "\n[Build] Error:\n"
echo -n "[Build]   Mounting disk image..."
run "LPDEV=$(sudo losetup --find --show disk.img)" " done." "\n[Build] Error:\n"
echo -n "[Build]   Creating GPT table..."
run "sudo parted "$LPDEV" --script mklabel gpt" " done." "\n[Build] Error:\n"
echo -n "[Build]   Creating EFI partition..."
run "sudo parted "$LPDEV" --script mkpart ESP fat32 1MiB 100Mib" " done." "\n[Build] Error:\n"
echo -n "[Build]   Making EFI partition bootable..."
run "sudo parted "$LPDEV" --script set 1 esp on" " done." "\n[Build] Error:\n"
echo -n "[Build]   Creating FAT32 filesystem on EFI partition..."
run "sudo mkfs.fat -F32 "${LPDEV}p1"" " done." "\n[Build] Error:\n"
echo -n "[Build]   Creating mount point..."
run "sudo mkdir -p ./efi-part" " done." "\n[Build] Error:\n"
echo -n "[Build]   Mounting EFI partition..."
run "sudo mount "${LPDEV}p1" ./efi-part" " done." "\n[Build] Error:\n"
echo -n "[Build]   Creating folder (1/3)..."
run "sudo mkdir -p ./efi-part/EFI/BOOT" " done." "\n[Build] Error:\n"
echo -n "[Build]   Creating folder (2/3)..."
run "sudo mkdir -p ./efi-part/EFI/BlastProofFiles" " done." "\n[Build] Error:\n"
echo -n "[Build]   Copying file (1/5)..."
run "sudo cp Blastproof/bootanim/bootanim.bin ./efi-part/EFI/BlastProofFiles/bootanim.bin" " done." "\n[Build] Error:\n"
echo -n "[Build]   Copying file (2/5)..."
run "sudo cp Blastproof/config/bp.conf ./efi-part/EFI/BlastProofFiles/bp.conf" " done." "\n[Build] Error:\n"
echo -n "[Build]   Copying file (3/5)..."
run "sudo cp Blastproof/fontgen/bitra-ascii-medium.fbm ./efi-part/EFI/BlastProofFiles/bitra-ascii-medium.fbm" " done." "\n[Build] Error:\n"
echo -n "[Build]   Copying file (4/5)..."
run "sudo cp Blastproof/initfsgen/initfs-footprint.bin ./efi-part/EFI/BlastProofFiles/initfs-footprint.bin" " done." "\n[Build] Error:\n"
echo -n "[Build]   Copying file (5/5)..."
run "sudo cp Blastproof/initfsgen/signsyst-hash.bin ./efi-part/EFI/BlastProofFiles/signsyst-hash.bin" " done." "\n[Build] Error:\n"
echo -n "[Build]   Creating folder (3/3)..."
run "sudo mkdir -p ./efi-part/EFI/BlastProofSign" " done." "\n[Build] Error:\n"
echo -n "[Build]   Copying all signatures files..."
run "sudo cp Blastproof/sign/* ./efi-part/EFI/BlastProofSign/" " done." "\n[Build] Error:\n"
echo -n "[Build]   Copying bootloader..."
run "sudo cp Build/BlastproofEnv/RELEASE_GCC/X64/BlastMain.efi ./efi-part/EFI/BOOT/BOOTX64.EFI" " done." "\n[Build] Error:\n"
echo -n "[Build]   Unmounting EFI partition..."
run "sudo umount ./efi-part" " done." "\n[Build] Error:\n"
echo -n "[Build]   Creating InitFS partition..."
INITFS_BIN="Blastproof/initfsgen/initfs.bin"
INITFS_SIZE_BYTES=$(stat -c '%s' "$INITFS_BIN")
INITFS_SIZE_ALIGNED=$((INITFS_SIZE_BYTES/512+1))
SIZE="+${INITFS_SIZE_ALIGNED}"
run "sudo sgdisk \
  --new=2:0:${SIZE} \
  --typecode=2:${INITFS_TYPE_GUID} \
  --partition-guid=2:${INITFS_GUID} \
  --change-name=2:\"InitFS\" \
  \"${LPDEV}\"" " done." "\n[Build] Error:\n"
  echo -n "[Build]   Creating SignSyst partition..."
SIGNSYST_BIN="Blastproof/initfsgen/signsyst.bin"
SIGNSYST_SIZE_BYTES=$(stat -c '%s' "$SIGNSYST_BIN")
SIGNSYST_SIZE_ALIGNED=$((SIGNSYST_SIZE_BYTES/512+1))
SIZE="+${SIGNSYST_SIZE_ALIGNED}"
run "sudo sgdisk \
  --new=3:0:${SIZE} \
  --typecode=3:${SIGNSYST_TYPE_GUID} \
  --partition-guid=3:${SIGNSYST_GUID} \
  --change-name=3:\"SignSyst\" \
  \"${LPDEV}\"" " done." "\n[Build] Error:\n"
echo -n "[Build]   Syncing partition table..."
run "sudo partprobe \"$LPDEV\"" " done." "\n[Build] Error:\n"
echo -n "[Build]   Flashing InitFS..."
run "sudo dd if=Blastproof/initfsgen/initfs.bin of="${LPDEV}p2" bs=4M conv=fsync" " done." "\n[Build] Error:\n"
echo -n "[Build]   Flashing SignSyst..."
run "sudo dd if=Blastproof/initfsgen/signsyst.bin of="${LPDEV}p3" bs=4M conv=fsync" " done." "\n[Build] Error:\n"
echo -n "[Build]   Unmounting disk image..."
run "sudo losetup -d "$LPDEV"" " done." "\n[Build] Error:\n"
echo "[Build] Launching QEMU with disk image"
qemu-system-x86_64   \
  -drive if=pflash,format=raw,unit=0,readonly=on,file=Build/OvmfX64/RELEASE_GCC/FV/OVMF_CODE.fd \
  -drive file=disk.img,format=raw,if=virtio,index=0 \
  -serial stdio   \
  -m 4096M \
  -cpu host \
  -enable-kvm
