#!/usr/bin/env bash
# ============================================================================
# Rumpk Nim Kernel Build — nim → C → .o (cross-compiled for target arch)
# ============================================================================
# Usage:
#   ./build_nim.sh              # Default: riscv64
#   ./build_nim.sh riscv64      # RISC-V 64-bit
#   ./build_nim.sh aarch64      # ARM64
#   ./build_nim.sh x86_64       # AMD64
#
# This script:
#   1. Invokes nim c --compileOnly to generate C from Nim
#   2. Cross-compiles each .c to .o using zig cc
#   3. Outputs to build/nimcache/*.o (consumed by build.zig)
# ============================================================================
set -euo pipefail
cd "$(dirname "$0")"

ARCH="${1:-riscv64}"

# ---- Validate architecture ----
case "$ARCH" in
    riscv64)
        ZIG_TARGET="riscv64-freestanding-none"
        ZIG_CPU="-mcpu=sifive_u54"
        ZIG_MODEL="-mcmodel=medany"
        NIM_CPU="riscv64"
        ;;
    aarch64)
        ZIG_TARGET="aarch64-freestanding-none"
        ZIG_CPU=""
        ZIG_MODEL="-fno-vectorize"
        NIM_CPU="arm64"
        ;;
    x86_64)
        ZIG_TARGET="x86_64-freestanding-none"
        ZIG_CPU=""
        ZIG_MODEL="-mcmodel=kernel"
        NIM_CPU="amd64"
        ;;
    *)
        echo "ERROR: Unknown architecture '$ARCH'"
        echo "Supported: riscv64, aarch64, x86_64"
        exit 1
        ;;
esac

NIMCACHE="build/nimcache"

echo "=== Rumpk Nim Build: $ARCH ==="
echo "    Target: $ZIG_TARGET"
echo "    Output: $NIMCACHE/"

# ---- Step 1: Nim → C ----
echo ""
echo "[1/2] nim c --compileOnly core/kernel.nim"

nim c \
    --cpu:"$NIM_CPU" \
    --os:any \
    --compileOnly \
    --mm:arc \
    --opt:size \
    --stackTrace:off \
    --lineDir:off \
    --nomain \
    --nimcache:"$NIMCACHE" \
    -d:noSignalHandler \
    -d:RUMPK_KERNEL \
    -d:nimAllocPagesViaMalloc \
    core/kernel.nim

C_COUNT=$(ls -1 "$NIMCACHE"/*.c 2>/dev/null | wc -l)
echo "    Generated $C_COUNT C files"

# ---- Step 2: C → .o (zig cc cross-compile) ----
echo ""
echo "[2/2] zig cc → $ZIG_TARGET"

COMPILED=0
FAILED=0

for cfile in "$NIMCACHE"/*.c; do
    [ -f "$cfile" ] || continue
    ofile="${cfile%.c}.o"

    # Skip if .o is newer than .c (incremental)
    if [ -f "$ofile" ] && [ "$ofile" -nt "$cfile" ]; then
        continue
    fi

    if zig cc \
        -target "$ZIG_TARGET" \
        $ZIG_CPU \
        $ZIG_MODEL \
        -fno-sanitize=all \
        -fvisibility=default \
        -I/usr/lib/nim/lib \
        -Icore \
        -Icore/include \
        -Ilibs/membrane \
        -Ilibs/membrane/include \
        -Ilibs/membrane/external/lwip/src/include \
        -Os \
        -c "$cfile" \
        -o "$ofile" 2>/dev/null; then
        COMPILED=$((COMPILED + 1))
    else
        echo "    FAIL: $(basename "$cfile")"
        FAILED=$((FAILED + 1))
    fi
done

O_COUNT=$(ls -1 "$NIMCACHE"/*.o 2>/dev/null | wc -l)

echo ""
echo "=== Result ==="
echo "    Arch:     $ARCH"
echo "    C files:  $C_COUNT"
echo "    Compiled: $COMPILED (incremental skip: $((O_COUNT - COMPILED)))"
echo "    Objects:  $O_COUNT"
if [ "$FAILED" -gt 0 ]; then
    echo "    FAILED:   $FAILED"
    exit 1
fi
echo "    Status:   OK"
