# jerbuild is the self-contained build tool: it bundles Chez Scheme + the
# jerboa stdlib under ~/.cache/jerbuild/<sha>/, so the host dev loop and the
# native `binary` need NO mutable dependency checkout and NO separately-built Chez.
JERBOA_VERSION ?= v0.2.3
JERBOA_TOOL_DIR ?= $(CURDIR)/.jerboa/bin
JERBUILD ?= $(shell if [ -x ./jerbuild ]; then echo ./jerbuild; \
	elif [ -x "$(JERBOA_TOOL_DIR)/jerbuild" ]; then echo "$(JERBOA_TOOL_DIR)/jerbuild"; \
	elif [ -x ../jerboa/dist/jerbuild ]; then echo ../jerboa/dist/jerbuild; \
	elif [ -x ../jerboa/jerbuild ]; then echo ../jerboa/jerbuild; \
	elif command -v jerbuild >/dev/null 2>&1; then command -v jerbuild; \
	else echo "$(JERBOA_TOOL_DIR)/jerbuild"; fi)

# Bundled stdlib path (Chez + jerboa libs live under $(JH)/lib). Resolved by
# asking the jerbuild binary where it unpacked its bundle.
JH = $(shell "$(JERBUILD)" --jerboa-home 2>/dev/null)

JSQLITE_DIR ?= $(CURDIR)/vendor/jsqlite
JSQLITE_LIBDIR ?= $(JSQLITE_DIR)/src

WEBSEARCH_OVERLAY := $(CURDIR)/vendor-overrides/jerboa-websearch
WEBSEARCH_WORKER := $(WEBSEARCH_OVERLAY)/bin/jerbsearch-engine-worker
LIBDIRS = --libdirs ./lib:$(JSQLITE_LIBDIR):$(WEBSEARCH_OVERLAY)/src:vendor/jerboa-websearch/src:$(JH)/lib
JEXEC   = $(JERBUILD) exec $(LIBDIRS)
SBOM_DIR ?= dist/sbom
REPRO_DIR ?= dist/reproducibility
TARGET_EVIDENCE_DIR ?= dist/target-evidence
RELEASE_EVIDENCE_DIR ?= dist/release-evidence

# Exact development inputs for FFI shared objects. Source-mode runs opt into
# each canonical file explicitly; ambient dyld/ld paths and CWD searches are
# intentionally not part of the loader contract.
TUI_SHIM_DIR   := $(CURDIR)/vendor/termbox2
NATIVE_LIB_DIR := $(CURDIR)/lib

# Native Rust lib (vendored crate, built with cargo). Only the features jcode
# uses — tls + crypto + wasm; no duckdb/pcap/postgres.
NATIVE_DIR      := vendor/jerboa-native-rs
NATIVE_FEATURES ?= tls,crypto,wasm
comma := ,
NATIVE_FEATURES_TAG := $(subst $(comma),-,$(NATIVE_FEATURES))
NATIVE_A        := $(NATIVE_DIR)/target/release/libjerboa_native.a
NATIVE_DYLIB    := $(NATIVE_DIR)/target/release/libjerboa_native.dylib
NATIVE_SO       := $(NATIVE_DIR)/target/release/libjerboa_native.so
NATIVE_SENTINEL := $(NATIVE_DIR)/target/release/.built-with-$(NATIVE_FEATURES_TAG)

# Per-OS link flags handed to `jerbuild build --os-libs`. jerbuild appends
# these after the Chez kernel + our archives when linking the binary.
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
JCODE_OS_LIBS := -lm -lpthread -lncurses -liconv -lc++ -framework Security -framework CoreFoundation
JCODE_DEV_NATIVE_LIB := $(NATIVE_LIB_DIR)/libjerboa_native.dylib
JCODE_DEV_TUI_LIB := $(TUI_SHIM_DIR)/jcode_tui_shim.dylib
else ifeq ($(UNAME_S),FreeBSD)
JCODE_OS_LIBS := -lm -lpthread -lutil -lncurses -L/usr/local/lib -liconv
JCODE_DEV_NATIVE_LIB := $(NATIVE_LIB_DIR)/libjerboa_native.so
JCODE_DEV_TUI_LIB := $(TUI_SHIM_DIR)/jcode_tui_shim.so
else
JCODE_OS_LIBS := -lm -ldl -lpthread -luuid -lncurses -lstdc++
JCODE_DEV_NATIVE_LIB := $(NATIVE_LIB_DIR)/libjerboa_native.so
JCODE_DEV_TUI_LIB := $(TUI_SHIM_DIR)/jcode_tui_shim.so
endif
JCODE_DEV_NATIVE_ENV = JERBOA_DEV_NATIVE=1 \
	JERBOA_NATIVE_LIB="$(JCODE_DEV_NATIVE_LIB)" \
	JCODE_TUI_DEV_NATIVE=1 JCODE_TUI_LIB="$(JCODE_DEV_TUI_LIB)"

.PHONY: all help ensure-jerboa-tools build gen run test fuzz test-websearch-worker test-websearch-packaged test-tui-native-loader-security test-binary-startup security audit security-audit verify sbom target-evidence reproducibility-report release-evidence test-providers local-eval clean repl binary install tui-shim run-tui native-rs linux linux-check linux-amd64 linux-arm64 jcode-linux-amd64 jcode-linux-arm64 freebsd freebsd-amd64 jcode-freebsd-amd64 purge-stale android android-clean vendor-deps vendor-provenance-check vendor-clean lint

all: help

help:
	@echo "Available targets:"
	@echo "  ensure-jerboa-tools  Ensure project-local jerboa/jerbuild are available"
	@echo "  build        Compile src/ → lib/ and pre-compile imports (jerbuild)"
	@echo "  test         Run test suite (test/run.ss)"
	@echo "  fuzz         Run harness fuzzer (test/fuzz.ss); JCODE_FUZZ_ITERS controls depth"
	@echo "  audit        Run release security audit checks"
	@echo "  sbom         Write SBOM/provenance evidence to $(SBOM_DIR)"
	@echo "  target-evidence  Record target proof status for sandbox/MCP/LSP/remote/fuzz/clean-host gates"
	@echo "  reproducibility-report  Compare two clean binary builds"
	@echo "  release-evidence  Write test/audit/SBOM/reproducibility bundle"
	@echo "  test-providers  Live 'say hello' smoke test per configured provider"
	@echo "  local-eval   Run live local-model verified eval (PROVIDER=mlx2 MODEL=/path/model)"
	@echo "  run          Start interactive agent REPL"
	@echo "  run-tui      Start TUI mode"
	@echo "  repl         Open a bare Scheme REPL with project libdirs"
	@echo "  gen          Transpile src/ → lib/ (jerbuild)"
	@echo "  native-rs    Build vendored libjerboa_native (cargo, tls+crypto+wasm)"
	@echo "  binary       Build native binary via 'jerbuild build' (.jerbuild)"
	@echo "  install      Install binary to ~/.local/bin"
	@echo "  binary       Build jcode for THIS host's os/arch (jerbuild, native)"
	@echo "  linux        Alias for linux-amd64"
	@echo "  linux-amd64  CROSS-compile static jcode-linux-amd64 (musl) from this host"
	@echo "  linux-arm64  CROSS-compile static jcode-linux-arm64 (musl) from this host"
	@echo "  freebsd      CROSS-compile dynamic jcode-freebsd-amd64 from this host"
	@echo "  linux-check  Fast drift check of the cross-build (no link, ~10s)"
	@echo "  clean        Remove compiled artifacts and binaries"
	@echo "  purge-stale  Remove stale .so/.wpo files"
	@echo "  tui-shim     Rebuild jcode_tui_shim"
	@echo "  android      Build Android APK in Termux (android/build/*.apk)"
	@echo "  android-clean  Remove android/build/"

ensure-jerboa-tools:
	@if [ -x ./jerbuild ]; then \
	  echo "=== Using project-local ./jerbuild ==="; \
	elif [ -x "$(JERBOA_TOOL_DIR)/jerbuild" ]; then \
	  echo "=== Using downloaded Jerboa toolchain: $(JERBOA_TOOL_DIR) ==="; \
	elif [ -x ../jerboa/dist/jerbuild ]; then \
	  echo "=== Using sibling Jerboa build: ../jerboa/dist/jerbuild ==="; \
	elif [ -x ../jerboa/jerbuild ]; then \
	  echo "=== Using sibling Jerboa build: ../jerboa/jerbuild ==="; \
	elif command -v jerbuild >/dev/null 2>&1; then \
	  echo "=== Using Jerboa toolchain from PATH: $$(command -v jerbuild) ==="; \
	else \
	  echo "=== Fetching Jerboa $(JERBOA_VERSION) release tools into $(JERBOA_TOOL_DIR) ==="; \
	  sh support/ensure-jerboa.sh "$(JERBOA_VERSION)" "$(JERBOA_TOOL_DIR)"; \
	fi
	@"$(JERBUILD)" --jerboa-home >/dev/null || { \
	  echo "ERROR: Jerboa toolchain is unavailable; set JERBUILD=/path/to/jerbuild or JERBOA_VERSION=<tag>"; \
	  exit 1; \
	}

# ── Stale-artifact prevention ───────────────────────────────────────────────
# Delete any compiled .so/.wpo whose source .ss/.sls is newer (or whose
# source no longer exists). This makes "make build" idempotent and immune
# to the class of bug where a stale .so silently linked against an old
# shim causes a runtime "no entry for X" foreign-procedure error.
purge-stale:
	@find lib -name "*.so" -o -name "*.wpo" 2>/dev/null | while read f; do \
	  src=$$(echo $$f | sed -e 's|^lib/|src/|' -e 's|\.so$$|.ss|' -e 's|\.wpo$$|.ss|'); \
	  sls=$$(echo $$f | sed 's|\.\(so\|wpo\)$$|.sls|'); \
	  if [ ! -f "$$src" ] && [ ! -f "$$sls" ]; then rm -f "$$f"; \
	  elif [ ! -f "$$sls" ]; then rm -f "$$f"; \
	  elif [ -f "$$src" ] && [ "$$src" -nt "$$f" ]; then rm -f "$$f"; \
	  elif [ -f "$$sls" ] && [ "$$sls" -nt "$$f" ]; then rm -f "$$f"; \
	  fi; \
	done
	@for s in $$(find src -name '*.ss' 2>/dev/null); do \
	  sls=$$(echo $$s | sed 's|^src/|lib/|;s|\.ss$$|.sls|'); \
	  if [ ! -f "$$sls" ]; then \
	    echo "purge-stale: $$s has no compiled output — invalidating .jerbuild-hashes"; \
	    rm -f src/.jerbuild-hashes; \
	    break; \
	  fi; \
	done
	@find "$(WEBSEARCH_OVERLAY)/src" \( -name '*.so' -o -name '*.wpo' \) 2>/dev/null | while read f; do \
	  src=$${f%.*}.ss; \
	  if [ ! -f "$$src" ] || [ "$$src" -nt "$$f" ]; then rm -f "$$f"; fi; \
	done

# ── libjerboa_native (Rust FFI) ─────────────────────────────────────────────
# secrets.ss + std/net/request + std/regex etc. all bind FFI symbols from
# libjerboa_native at library load time, so the shared lib must exist in
# ./lib before scheme starts. Without it, `make build` dies with
# "no entry for jerboa_last_error" the moment any library importing
# (std crypto native-rust) is visited.
#
# We vendor the crate (sparse-clone from the jerboa monorepo) and build it
# with cargo using ONLY the features jcode needs (tls + crypto + wasm) — no
# dependency on a ~/mine/jerboa checkout. The same crate + features feed the
# static `binary` build via (rust-crates ...) in .jerbuild.
native-rs: $(NATIVE_DIR) vendor-provenance-check
	@command -v cargo >/dev/null 2>&1 || { \
	  echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; exit 1; }
	@if [ ! -f "$(NATIVE_A)" ] || \
	    [ ! -f "$(NATIVE_SENTINEL)" ] || \
	    [ -n "$$(find $(NATIVE_DIR)/src -name '*.rs' -newer $(NATIVE_A) 2>/dev/null)" ]; then \
	  echo "=== Building libjerboa_native (features: $(NATIVE_FEATURES)) ==="; \
	  ( cd $(NATIVE_DIR) && cargo build --locked --release --no-default-features --features $(NATIVE_FEATURES) ); \
	  rm -f $(NATIVE_DIR)/target/release/.built-with-*; \
	  touch "$(NATIVE_SENTINEL)"; \
	fi
	@mkdir -p lib
	@# The dev loop loads a shared object; the binary links the .a (jerbuild
	@# builds that itself via rust-crates). Drop the dylib/so into ./lib and,
	@# on macOS, symlink the .so name the loader tries first.
	@if [ -f "$(NATIVE_DYLIB)" ]; then \
	  cp -f "$(NATIVE_DYLIB)" lib/libjerboa_native.dylib; \
	  ln -sf libjerboa_native.dylib lib/libjerboa_native.so; \
	elif [ -f "$(NATIVE_SO)" ]; then \
	  cp -f "$(NATIVE_SO)" lib/libjerboa_native.so; \
	fi

# ─── Vendor Dependencies ─────────────────────────────────────────────────────
# Populate dependency repos only from the immutable commit/tree identities in
# vendor-lock.env. No build target resolves or checks out a moving branch.

vendor-deps: vendor/termbox2 vendor/jerboa-websearch vendor/jsqlite
	@JCODE_VENDOR_COMPONENT=source sh scripts/vendor-provenance-check.sh >/dev/null

vendor/termbox2: vendor-lock.env scripts/fetch-vendor.sh
	@echo "=== Fetching locked termbox2 source ==="
	@sh scripts/fetch-vendor.sh termbox2

vendor/jerboa-websearch: vendor-lock.env scripts/fetch-vendor.sh
	@echo "=== Fetching locked jerboa-websearch source ==="
	@sh scripts/fetch-vendor.sh websearch

vendor/jsqlite: vendor-lock.env scripts/fetch-vendor.sh
	@echo "=== Fetching locked jsqlite source ==="
	@sh scripts/fetch-vendor.sh jsqlite

# Sparse-clone just the jerboa-native-rs crate out of the jerboa monorepo.
# Depended on only by native-rs (not vendor-deps), so cross targets — which
# build their own target-triple native lib — don't pull it.
$(NATIVE_DIR): vendor-lock.env scripts/fetch-vendor.sh
	@echo "=== Fetching locked jerboa-native-rs source ==="
	@sh scripts/fetch-vendor.sh native

vendor-provenance-check: vendor-deps $(NATIVE_DIR)
	@sh scripts/vendor-provenance-check.sh

vendor-clean:
	rm -rf vendor

lint: gen

gen: ensure-jerboa-tools vendor-deps purge-stale
	$(JERBUILD) transpile src lib

build: ensure-jerboa-tools gen native-rs
	$(JCODE_DEV_NATIVE_ENV) \
	$(JERBUILD) compile $(LIBDIRS) support/build-check.ss < /dev/null

run: ensure-jerboa-tools native-rs
	JERBSEARCH_ENGINE_WORKER="$(WEBSEARCH_WORKER)" \
	$(JCODE_DEV_NATIVE_ENV) \
	$(JEXEC) main.ss

tui-shim: vendor/termbox2
	@if [ ! -f "$(JCODE_DEV_TUI_LIB)" ] || \
	    [ src/jcode/ui/jcode_tui_shim.c -nt "$(JCODE_DEV_TUI_LIB)" ]; then \
	  cc -shared -fPIC -DTB_OPT_ATTR_W=32 \
	    -I$(TUI_SHIM_DIR) \
	    -o "$(JCODE_DEV_TUI_LIB)" \
	    src/jcode/ui/jcode_tui_shim.c; \
	fi

run-tui: ensure-jerboa-tools build tui-shim native-rs
	JERBSEARCH_ENGINE_WORKER="$(WEBSEARCH_WORKER)" \
	$(JCODE_DEV_NATIVE_ENV) \
	$(JEXEC) main.ss --tui

repl: ensure-jerboa-tools
	$(JCODE_DEV_NATIVE_ENV) \
	$(JEXEC) support/repl.ss

test: build test-websearch-worker test-tui-native-loader-security
	JERBSEARCH_ENGINE_WORKER="$(WEBSEARCH_WORKER)" \
	$(JCODE_DEV_NATIVE_ENV) \
	sh test/security-regression.sh $(JEXEC) test/security-regression.ss
	JERBSEARCH_ENGINE_WORKER="$(WEBSEARCH_WORKER)" \
	$(JCODE_DEV_NATIVE_ENV) \
	$(JEXEC) test/run.ss
	$(MAKE) test-binary-startup

fuzz: build
	JERBSEARCH_ENGINE_WORKER="$(WEBSEARCH_WORKER)" \
	$(JCODE_DEV_NATIVE_ENV) \
	$(JEXEC) test/fuzz.ss

test-websearch-worker: build
	JERBSEARCH_ENGINE_WORKER="$(WEBSEARCH_WORKER)" \
	$(JCODE_DEV_NATIVE_ENV) \
	$(JEXEC) test/websearch-worker-failclosed.ss
	JERBSEARCH_ENGINE_WORKER="$(CURDIR)/test/fixtures/websearch-engine-worker" \
	$(JCODE_DEV_NATIVE_ENV) \
	$(JEXEC) test/websearch-search-limits.ss

test-websearch-packaged: binary
	sh test/websearch-worker-binary.sh ./jcode

test-tui-native-loader-security: ensure-jerboa-tools gen tui-shim
	JERBUILD="$(JERBUILD)" sh test/tui-native-loader-security.sh

test-binary-startup: binary
	sh test/binary-startup.sh ./jcode

security: security-audit

audit: security-audit

security-audit:
	sh tools/security-audit.sh

sbom: binary
	JERBUILD="$(JERBUILD)" JSQLITE_DIR="$(JSQLITE_DIR)" JSQLITE_LIBDIR="$(JSQLITE_LIBDIR)" \
	  scripts/sbom.sh "$(SBOM_DIR)"

target-evidence:
	JCODE_TARGET_RUNTIME_PROOF_FILE="$(JCODE_TARGET_RUNTIME_PROOF_FILE)" \
	JCODE_TARGET_FUZZ_PROOF_FILE="$(JCODE_TARGET_FUZZ_PROOF_FILE)" \
	JCODE_TARGET_CLEAN_HOST_PROOF_FILE="$(JCODE_TARGET_CLEAN_HOST_PROOF_FILE)" \
	JCODE_REQUIRE_TARGET_RUNTIME_PROOF="$(JCODE_REQUIRE_TARGET_RUNTIME_PROOF)" \
	JCODE_REQUIRE_TARGET_FUZZ_PROOF="$(JCODE_REQUIRE_TARGET_FUZZ_PROOF)" \
	JCODE_REQUIRE_TARGET_CLEAN_HOST_PROOF="$(JCODE_REQUIRE_TARGET_CLEAN_HOST_PROOF)" \
	  scripts/target-evidence.sh "$(TARGET_EVIDENCE_DIR)"

reproducibility-report:
	JERBUILD="$(JERBUILD)" JSQLITE_DIR="$(JSQLITE_DIR)" JSQLITE_LIBDIR="$(JSQLITE_LIBDIR)" \
	  MAKE="$(MAKE)" scripts/reproducibility-report.sh "$(REPRO_DIR)"

verify: test audit sbom reproducibility-report target-evidence

release-evidence:
	rm -rf "$(RELEASE_EVIDENCE_DIR)"
	mkdir -p "$(RELEASE_EVIDENCE_DIR)"
	$(MAKE) test > "$(RELEASE_EVIDENCE_DIR)/test.log" 2>&1
	$(MAKE) audit > "$(RELEASE_EVIDENCE_DIR)/audit.log" 2>&1
	$(MAKE) reproducibility-report > "$(RELEASE_EVIDENCE_DIR)/reproducibility-report.log" 2>&1
	$(MAKE) sbom > "$(RELEASE_EVIDENCE_DIR)/sbom.log" 2>&1
	$(MAKE) target-evidence > "$(RELEASE_EVIDENCE_DIR)/target-evidence.log" 2>&1
	rm -rf "$(RELEASE_EVIDENCE_DIR)/sbom" "$(RELEASE_EVIDENCE_DIR)/reproducibility" "$(RELEASE_EVIDENCE_DIR)/target-evidence"
	cp -R "$(SBOM_DIR)" "$(RELEASE_EVIDENCE_DIR)/sbom"
	cp -R "$(REPRO_DIR)" "$(RELEASE_EVIDENCE_DIR)/reproducibility"
	cp -R "$(TARGET_EVIDENCE_DIR)" "$(RELEASE_EVIDENCE_DIR)/target-evidence"
	git rev-parse HEAD > "$(RELEASE_EVIDENCE_DIR)/git-commit.txt" 2>/dev/null || true
	git status --short > "$(RELEASE_EVIDENCE_DIR)/git-status.txt" 2>/dev/null || true
	git diff --stat > "$(RELEASE_EVIDENCE_DIR)/diff-stat.txt" 2>/dev/null || true
	{ echo "platform=$$(uname -srm)"; printf 'jerbuild_version='; "$(JERBUILD)" --version 2>/dev/null || true; \
	  if "$(JERBUILD)" --jerboa-home >/dev/null 2>&1; then echo "jerboa_home_status=present"; else echo "jerboa_home_status=missing"; fi; \
	} > "$(RELEASE_EVIDENCE_DIR)/build-environment.txt"
	(cc --version || cc -v) > "$(RELEASE_EVIDENCE_DIR)/cc-version.txt" 2>&1 || true
	(rustc --version && cargo --version) > "$(RELEASE_EVIDENCE_DIR)/rust-version.txt" 2>&1 || true
	./jcode --version > "$(RELEASE_EVIDENCE_DIR)/binary-version.txt" 2>&1
	shasum -a 256 jcode > "$(RELEASE_EVIDENCE_DIR)/binary-sha256.txt"
	find Makefile .build.yml .jerbuild .jerboa/security.json main.ss main-binary.ss src support test docs tools .github \
	  -type f \( -name 'Makefile' -o -name '*.ss' -o -name '*.sls' -o -name '*.c' -o -name '*.h' -o -name '*.list' -o -name '*.sh' -o -name '*.json' -o -name '*.md' -o -name '*.yml' -o -name '*.yaml' \) \
	  -print 2>/dev/null | LC_ALL=C sort | xargs shasum -a 256 > "$(RELEASE_EVIDENCE_DIR)/release-inputs.sha256"
	shasum -a 256 vendor-lock.env rust-toolchain.toml >> "$(RELEASE_EVIDENCE_DIR)/release-inputs.sha256"
	grep -q '^sbom_status=present$$' "$(RELEASE_EVIDENCE_DIR)/sbom/manifest.txt"
	grep -q '^status=match$$' "$(RELEASE_EVIDENCE_DIR)/reproducibility/result.txt"
	grep -Eq '^(status=local-status-recorded|status=target-proof-recorded-review-required)$$' "$(RELEASE_EVIDENCE_DIR)/target-evidence/status.txt"
	sh scripts/sanitize-evidence.sh "$(RELEASE_EVIDENCE_DIR)"

# Live smoke test — one round-trip per provider with a configured key.
# Providers without a key are SKIPped, not failed. Excluded from `test`
# because it makes real network calls.
test-providers: build
	JERBSEARCH_ENGINE_WORKER="$(WEBSEARCH_WORKER)" \
	$(JCODE_DEV_NATIVE_ENV) \
	$(JEXEC) test/run-providers.ss

PROVIDER ?= mlx2
MODEL ?= /Users/user/models/qwen3-coder-next-mlx
LOCAL_EVAL_JCODE ?= $(HOME)/.local/bin/jcode

local-eval: build
	JERBSEARCH_ENGINE_WORKER="$(WEBSEARCH_WORKER)" \
	$(JCODE_DEV_NATIVE_ENV) \
	$(JEXEC) eval/local-model/run-local-eval.ss \
	  --provider "$(PROVIDER)" \
	  --model "$(MODEL)" \
	  --jcode "$(LOCAL_EVAL_JCODE)"

# --- Static binary targets ---

# Self-contained: `jerbuild build` reads .jerbuild (entry, libdirs, ffi-symbols,
# main-c, C shims, rust-crate), bundles Chez + stdlib, runs cargo for the native
# .a, and links it all. Per-OS link flags come from --os-libs.
binary: ensure-jerboa-tools gen native-rs
	rm -rf lib/std
	rm -rf lib/jerboa
	$(JCODE_DEV_NATIVE_ENV) \
	$(JERBUILD) build --config .jerbuild --os-libs "$(JCODE_OS_LIBS)"
	cp -R "$(JH)/lib/std" lib/
	cp -R "$(JH)/lib/jerboa" lib/
	cp vendor/termbox2/jcode_tui_shim.dylib ./jcode_tui_shim.dylib 2>/dev/null || true
	cp vendor/termbox2/jcode_tui_shim.so ./jcode_tui_shim.so 2>/dev/null || true

install: binary
	mkdir -p $(HOME)/.local/bin
	mkdir -p $(HOME)/.local/bin/lib
	cp jcode $(HOME)/.local/bin/jcode
	rm -rf $(HOME)/.local/bin/lib/jcode
	rm -rf $(HOME)/.local/bin/lib/std
	rm -rf $(HOME)/.local/bin/lib/jerboa
	cp -R lib/jcode $(HOME)/.local/bin/lib/
	cp -R lib/std $(HOME)/.local/bin/lib/
	cp -R lib/jerboa $(HOME)/.local/bin/lib/
	cp lib/libjerboa_native.dylib $(HOME)/.local/bin/lib/libjerboa_native.dylib 2>/dev/null || true
	cp lib/libjerboa_native.so $(HOME)/.local/bin/lib/libjerboa_native.so 2>/dev/null || true
	cp vendor/termbox2/jcode_tui_shim.dylib $(HOME)/.local/bin/jcode_tui_shim.dylib 2>/dev/null || true
	@if [ "$$(uname)" = "Darwin" ]; then \
	  codesign --force --sign - $(HOME)/.local/bin/jcode; \
	  [ -f $(HOME)/.local/bin/jcode_tui_shim.dylib ] && codesign --force --sign - $(HOME)/.local/bin/jcode_tui_shim.dylib || true; \
	fi
	@echo "Installed to ~/.local/bin/jcode"

# ─── Cross-compile machinery (host → Linux/FreeBSD) ─────────────────────────
# `make binary` builds for the LOCAL os/arch via jerbuild. The targets below
# CROSS-compile from this host to another platform using the host Chez
# ($(SCHEME)) + a cross-built Chez kernel in $(JERBOA_HOME) + a musl/clang
# cross toolchain. These vars are used ONLY by the cross targets.
JERBOA_HOME      ?= $(HOME)/mine/jerboa
SCHEME           ?= $(JERBOA_HOME)/.chez/bin/scheme
FREEBSD_AMD64_CC ?= $(JERBOA_HOME)/support/cross-cc-freebsd-amd64
XC_LIBDIRS        = ./lib:$(JSQLITE_LIBDIR):$(WEBSEARCH_OVERLAY)/src:vendor/jerboa-websearch/src:$(JH)/lib:$(JERBOA_HOME)/lib

# `make linux` defaults to the linux amd64 cross-build.
linux: linux-amd64

# ── Fast local drift check for the cross-build path ─────────────────────────
# Runs compile-program on main-binary.ss with the same flags the cross build
# uses, but skips the C compile and link. Catches drift (new imports, removed
# stdlib exports) in ~10s before burning minutes in the full cross build.
linux-check: ensure-jerboa-tools gen
	@echo "=== Running linux-check (fast cross-build drift check) ==="
	$(JCODE_DEV_NATIVE_ENV) \
	$(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script linux-check.ss

# ─── Cross-compile: host → Linux x86_64 / arm64 (musl static) ───────────────
# Produces a fully static jcode-linux-<arch>. No Docker. Requires:
#   - <arch>-linux-musl-gcc on PATH   (brew install FiloSottile/musl-cross/musl-cross)
#   - $(JERBOA_HOME)/.chez-cross-<m>  (cd $(JERBOA_HOME) && make chez-cross[-tarm64le])
#   - rustup target add <arch>-unknown-linux-musl
linux-amd64: ensure-jerboa-tools gen
	@command -v x86_64-linux-musl-gcc >/dev/null 2>&1 || { \
	  echo "ERROR: x86_64-linux-musl-gcc not found on PATH."; \
	  echo "Install with: brew install FiloSottile/musl-cross/musl-cross"; \
	  exit 1; }
	@if test ! -d $(JERBOA_HOME)/.chez-cross-ta6le || test ! -f $(JERBOA_HOME)/build/chez/xc-ta6le/s/xpatch; then \
	  echo "=== cross Chez (ta6le) missing — building it in $(JERBOA_HOME) (one-time) ==="; \
	  $(MAKE) -C $(JERBOA_HOME) chez-cross CHEZ_TARGET_MACHINE=ta6le CROSS_CC=x86_64-linux-musl-gcc; \
	fi
	@command -v cargo >/dev/null 2>&1 || { \
	  echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; \
	  exit 1; }
	JERBOA_HOME=$(JERBOA_HOME) TARGET_ARCH=amd64 $(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script build-jcode-cross.ss
	@ls -lh jcode-linux-amd64
	@file jcode-linux-amd64

linux-arm64: ensure-jerboa-tools gen
	@command -v aarch64-linux-musl-gcc >/dev/null 2>&1 || { \
	  echo "ERROR: aarch64-linux-musl-gcc not found on PATH."; \
	  echo "Install with: brew install FiloSottile/musl-cross/musl-cross"; \
	  exit 1; }
	@if test ! -d $(JERBOA_HOME)/.chez-cross-tarm64le || test ! -f $(JERBOA_HOME)/build/chez/xc-tarm64le/s/xpatch; then \
	  echo "=== cross Chez (tarm64le) missing — building it in $(JERBOA_HOME) (one-time) ==="; \
	  $(MAKE) -C $(JERBOA_HOME) chez-cross CHEZ_TARGET_MACHINE=tarm64le CROSS_CC=aarch64-linux-musl-gcc; \
	fi
	@command -v cargo >/dev/null 2>&1 || { \
	  echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; \
	  exit 1; }
	JERBOA_HOME=$(JERBOA_HOME) TARGET_ARCH=arm64 $(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script build-jcode-cross.ss
	@ls -lh jcode-linux-arm64
	@file jcode-linux-arm64

# Friendly aliases.
jcode-linux-amd64: linux-amd64
jcode-linux-arm64: linux-arm64

# Smoke-test the cross-built amd64 binary under alpine x86_64 via podman/qemu.
test-linux-amd64: linux-amd64
	@command -v podman >/dev/null 2>&1 || { \
	  echo "ERROR: podman not found. Install with: brew install podman"; exit 1; }
	@echo "=== Smoke testing jcode-linux-amd64 under podman/qemu alpine ==="
	podman run --rm --platform linux/amd64 \
	  -v "$(CURDIR):/work:ro" -w /work \
	  alpine:3 ./jcode-linux-amd64 --version

test-linux: test-linux-amd64

# ─── Cross-compile: host → FreeBSD amd64 (dynamic ELF) ──────────────────────
# Produces a dynamic x86_64 FreeBSD ELF (jcode-freebsd-amd64). Requires:
#   - $(FREEBSD_AMD64_CC)                       (macOS clang+lld wrapper)
#   - $(JERBOA_HOME)/.chez-cross-ta6fb          (cd $(JERBOA_HOME) && make binary)
#   - FreeBSD sysroot at $(JERBOA_HOME)/.freebsd-sysroot/amd64
#   - rustup target add x86_64-unknown-freebsd
freebsd-amd64: ensure-jerboa-tools gen
	@command -v $(firstword $(FREEBSD_AMD64_CC)) >/dev/null 2>&1 || { \
	  echo "ERROR: $(FREEBSD_AMD64_CC) not found or not executable" >&2; \
	  echo "  See top of Makefile freebsd-amd64 target for setup notes." >&2; \
	  exit 1; }
	@if test ! -d $(JERBOA_HOME)/.chez-cross-ta6fb || test ! -f $(JERBOA_HOME)/build/chez/xc-ta6fb/s/xpatch; then \
	  echo "=== cross Chez (ta6fb) missing — building it in $(JERBOA_HOME) (one-time) ==="; \
	  $(MAKE) -C $(JERBOA_HOME) chez-cross CHEZ_TARGET_MACHINE=ta6fb CROSS_CC="$(FREEBSD_AMD64_CC)"; \
	fi
	@command -v cargo >/dev/null 2>&1 || { \
	  echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; \
	  exit 1; }
	JERBOA_HOME=$(JERBOA_HOME) CROSS_CC="$(FREEBSD_AMD64_CC)" $(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script build-jcode-freebsd-cross.ss
	@ls -lh jcode-freebsd-amd64
	@file jcode-freebsd-amd64

# Friendly aliases.
jcode-freebsd-amd64: freebsd-amd64
freebsd: freebsd-amd64


clean:
	find lib/jcode -name "*.sls" -delete 2>/dev/null; true
	find . -name "*.so" -delete
	find . -name "*.wpo" -delete
	rm -f jcode jcode-linux-amd64 jcode-linux-arm64 jcode-freebsd-amd64
	rm -f lib/libjerboa_native.dylib lib/libjerboa_native.so jcode_tui_shim.dylib jcode_tui_shim.so

# ── Android APK (thin client, no embedded binary) ───────────────────────────
# Build from Termux — no Android Studio / Gradle required.
# Requires Termux packages: aapt2 d8 kotlin openjdk-17 apksigner android-tools
# Requires android/android.jar (API 30+) — not checked in.
#
# The APK is a thin GUI client that connects to `jcode serve` over localhost.

android:
	@command -v bash >/dev/null || { echo "bash required"; exit 1; }
	@test -f android/android.jar || { \
	  echo "Missing android/android.jar (API 30+ platform jar)."; \
	  echo "Download one, e.g.:"; \
	  echo "  curl -L -o android/android.jar https://github.com/Sable/android-platforms/raw/master/android-30/android.jar"; \
	  exit 1; }
	@for cmd in aapt2 d8 kotlinc keytool apksigner zipalign; do \
	  command -v $$cmd >/dev/null || { \
	    echo "Missing tool: $$cmd"; \
	    echo "Install with: pkg install aapt2 d8 kotlin openjdk-17 apksigner android-tools"; \
	    exit 1; }; \
	done
	bash android/build-apk.sh
	@echo ""
	@echo "APK(s) in android/build/:"
	@ls -lh android/build/*.apk 2>/dev/null || echo "  (none found — check build-apk.sh output above)"

android-clean:
	rm -rf android/build
