#!/usr/bin/env zsh
set -e

ARCH=${1:-riscv64}

# Architecture-specific settings
if [ "$ARCH" = "aarch64" ]; then
  NIM_CPU="arm64"
  ZIG_TARGET="aarch64-freestanding-none"
  ZIG_CPU="baseline"
  LINKER_SCRIPT="apps/linker_user_aarch64.ld"
  BUILD_FLAG="-Darch=aarch64"
  echo "=== Building NipBox Userland (aarch64) ==="
else
  NIM_CPU="riscv64"
  ZIG_TARGET="riscv64-freestanding-none"
  ZIG_CPU="sifive_u54"
  LINKER_SCRIPT="apps/linker_user.ld"
  BUILD_FLAG=""
  echo "=== Building NipBox Userland (riscv64) ==="
fi

# Compile Nim sources to C
nim c --cpu:${NIM_CPU} --os:any --compileOnly --mm:arc --opt:size \
  --stackTrace:off --lineDir:off --nomain --nimcache:build/init_nimcache \
  -d:noSignalHandler -d:RUMPK_USER -d:nimAllocPagesViaMalloc -d:NIPBOX_LITE \
  npl/nipbox/nipbox.nim

# Compile Nim-generated C (check if files exist first)
# Skip net_glue (needs LwIP headers not available in userland build)
EXTRA_CC_FLAGS=""
if [ "$ARCH" = "riscv64" ]; then
  EXTRA_CC_FLAGS="-mcmodel=medany"
fi

if ls build/init_nimcache/*.c 1> /dev/null 2>&1; then
  for f in build/init_nimcache/*.c; do
    case "$f" in
      *net_glue*) echo "  [skip] $f (LwIP dependency)"; continue ;;
    esac
    zig cc -target ${ZIG_TARGET} -mcpu=${ZIG_CPU} ${EXTRA_CC_FLAGS} \
      -fno-sanitize=all -fno-vectorize \
      -I/usr/lib/nim/lib -Icore -Ilibs/membrane -Ilibs/membrane/include \
      -include string.h \
      -Os -c "$f" -o "${f%.c}.o"
  done
fi

# Compile clib
zig cc -target ${ZIG_TARGET} -mcpu=${ZIG_CPU} ${EXTRA_CC_FLAGS} \
  -fno-sanitize=all \
  -DNO_SYS=1 -DOMIT_EXIT -DRUMPK_USER -Ilibs/membrane/include -c libs/membrane/clib.c -o build/clib_user.o

# Create startup assembly
if [ "$ARCH" = "aarch64" ]; then
  cat > build/head_user.S << 'EOF'
.section .text._start
.global _start
_start:
    bl NimMain
1:  wfi
    b 1b
EOF
else
  cat > build/head_user.S << 'EOF'
.section .text._start
.global _start
_start:
    .option push
    .option norelax
    1:auipc gp, %pcrel_hi(__global_pointer$)
      addi  gp, gp, %pcrel_lo(1b)
    .option pop
    call NimMain
    1: wfi
       j 1b
EOF
fi

zig cc -target ${ZIG_TARGET} -mcpu=${ZIG_CPU} ${EXTRA_CC_FLAGS} \
  -fno-sanitize=all \
  -c build/head_user.S -o build/head_user.o

# Link init
zig cc -target ${ZIG_TARGET} -mcpu=${ZIG_CPU} ${EXTRA_CC_FLAGS} -nostdlib \
  -fno-sanitize=all \
  -T ${LINKER_SCRIPT} -Wl,--gc-sections \
  build/head_user.o build/init_nimcache/*.o build/clib_user.o \
  -o build/init

echo "✓ NipBox binary built (${ARCH})"
file build/init

# Create initrd
mkdir -p build/sysro/bin
cp build/init build/sysro/init
if [ "$ARCH" = "riscv64" ] && [ -f vendor/mksh/mksh.elf ]; then
  cp vendor/mksh/mksh.elf build/sysro/bin/mksh
fi
cd build/sysro
tar --format=ustar -cf ../initrd.tar *
cd ../..

# Embed initrd
cat > build/embed_initrd.S << EOF
.section .rodata
.global _initrd_start
.global _initrd_end
.align 4
_initrd_start:
    .incbin "$(pwd)/build/initrd.tar"
_initrd_end:
EOF

zig cc -target ${ZIG_TARGET} -mcpu=${ZIG_CPU} ${EXTRA_CC_FLAGS} \
  -c build/embed_initrd.S -o build/initrd.o

cp build/initrd.tar hal/initrd.tar

# Build kernel
rm -f zig-out/lib/librumpk_hal.a
zig build ${BUILD_FLAG}

echo "=== BUILD COMPLETE (${ARCH}) ==="
ls -lh build/init zig-out/bin/rumpk.elf
