#!/usr/bin/env bash
# beagle-build: compile a beagle source file to target output.
#
# Usage:
#   bin/beagle-build <source.bclj|.bjs|.bnix|.bsql|.bodin> [output]
#
# If the output path is omitted, it is derived from the namespace declared
# in the source via (ns ...) and dropped under .beagle-out/ (gitignored, so
# throwaway emit never pollutes the tracked tree). Override the output root
# with BEAGLE_OUT (e.g. BEAGLE_OUT=runtime/src to build into the runtime project).
# Extension is determined by target: .clj (default), .js, .py, .nix.

set -euo pipefail
source "$(dirname "$0")/_beagle-racket"

if [[ $# -lt 1 || $# -gt 2 ]]; then
    echo "usage: beagle-build <source.bclj|.bjs|.bnix> [output]" >&2
    exit 2
fi

src="$1"
beagle_root="$(cd "$(dirname "$0")/.." && pwd)"

if [[ ! -f "$src" ]]; then
    echo "beagle-build: source file not found: $src" >&2
    exit 1
fi

## detect target from file extension, then fall back to source content
ext="clj"
case "$src" in
    *.bjs)   ext="js" ;;
    *.bnix)  ext="nix" ;;
    *.bsql)  ext="sql" ;;
    *.bpy)   ext="py" ;;
    *.bclj)  ext="clj" ;;
    *.bzig)  ext="zig" ;;
    *.bodin) ext="odin" ;;
    *)
        # Legacy .bgl/.rkt: detect from file content
        if grep -qE '^\(define-target[[:space:]]+js\)' "$src" 2>/dev/null || \
             grep -qE '^#lang beagle/js' "$src" 2>/dev/null; then
            ext="js"
        elif grep -qE '^\(define-target[[:space:]]+py\)' "$src" 2>/dev/null || \
             grep -qE '^#lang beagle/py' "$src" 2>/dev/null; then
            ext="py"
        elif grep -qE '^\(define-target[[:space:]]+nix\)' "$src" 2>/dev/null || \
             grep -qE '^#lang beagle/nix' "$src" 2>/dev/null; then
            ext="nix"
        elif grep -qE '^\(define-target[[:space:]]+zig\)' "$src" 2>/dev/null || \
             grep -qE '^#lang beagle/zig' "$src" 2>/dev/null; then
            ext="zig"
        elif grep -qE '^\(define-target[[:space:]]+odin\)' "$src" 2>/dev/null || \
             grep -qE '^#lang beagle/odin' "$src" 2>/dev/null; then
            ext="odin"
        fi
        ;;
esac

if [[ $# -eq 2 ]]; then
    out="$2"
else
    ns="$(grep -E '^\(ns' "$src" | head -1 | \
          sed -E 's/^\(ns[[:space:]]+([a-zA-Z0-9._-]+).*/\1/' | \
          tr -d '[:space:]')"
    [[ -z "$ns" ]] && ns="beagle.user"
    rel_path="$(echo "$ns" | tr '.-' '//_')"
    out="${BEAGLE_OUT:-$beagle_root/.beagle-out}/$rel_path.$ext"
fi

mkdir -p "$(dirname "$out")"
# Atomic write: emit to a temp file first, then mv on success. Without this,
# the `>` redirection truncates $out before racket runs — if racket fails
# mid-emit, the file is left empty/partial silently. The atomic rename
# guarantees $out either has the complete new contents or the old contents.
tmp="$(mktemp "${out}.XXXXXX")"
trap 'rm -f "$tmp"' EXIT
"$RACKET" "$src" > "$tmp"
mv "$tmp" "$out"
trap - EXIT
echo "$src -> $out" >&2

# Optional Nix smoke test: confirm the emitted file parses as valid Nix.
# Set BEAGLE_NIX_EVAL_CHECK=1 to enable. Requires `nix` on PATH.
if [[ "$ext" == "nix" && "${BEAGLE_NIX_EVAL_CHECK:-0}" == "1" ]]; then
    if command -v nix-instantiate >/dev/null; then
        if ! nix-instantiate --parse "$out" >/dev/null 2>/tmp/beagle-nix-check.err; then
            echo "beagle-build: emitted $out failed nix-instantiate --parse:" >&2
            cat /tmp/beagle-nix-check.err >&2
            exit 1
        fi
    else
        echo "beagle-build: BEAGLE_NIX_EVAL_CHECK=1 set but nix-instantiate not on PATH" >&2
    fi
fi
