# Gleann Makefile
export PATH := $(HOME)/.local/go/bin:$(PATH)
ORIGINAL_HOME ?= $(HOME)
export PYTHONUSERBASE ?= $(ORIGINAL_HOME)/.local
# Usage:
#   make               — build pure Go binary (gleann)
#   make full          — build FAISS + tree-sitter binary (gleann-full)
#   make install       — install gleann to /usr/local/bin
#   make install-user  — install gleann-full to ~/.local/bin/gleann
#   make test          — run all tests
#   make test-faiss    — run FAISS backend tests
#   make release       — build all release artifacts into dist/
#   make clean         — remove built binaries

# ── Variables ──────────────────────────────────────────────────────────────
BUILD_DIR   := build
BINARY      := $(BUILD_DIR)/gleann
BINARY_FULL := $(BUILD_DIR)/gleann-full
CMD         := ./cmd/gleann
VERSION     ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
LDFLAGS     := -s -w -X main.version=$(VERSION)
INSTALL_DIR ?= /usr/local/bin
REPO_ROOT   := $(CURDIR)
USER_BIN_DIR ?= $(HOME)/.local/bin
USER_LIB_DIR ?= $(HOME)/.local/lib

BUILDER_IMAGE ?= gleann-builder:latest

# FAISS shared lib locations
FAISS_LIB_DIR ?= $(REPO_ROOT)/deps/faiss_install/lib
FAISS_INC_DIR ?= $(REPO_ROOT)/deps/faiss_install/include

# Platform detection
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
    RPATH_FLAGS := -Wl,-rpath,@loader_path -Wl,-rpath,@loader_path/../lib
    ZNOW_FLAG   := 
    SO_EXT      := dylib
    OMP_PREFIX  := $(shell brew --prefix libomp 2>/dev/null)
    OMP_CFLAGS  := $(if $(OMP_PREFIX),-I$(OMP_PREFIX)/include,)
    OMP_LDFLAGS := $(if $(OMP_PREFIX),-L$(OMP_PREFIX)/lib -lomp,)
else
    RPATH_FLAGS := -Wl,-rpath,'$$ORIGIN' -Wl,-rpath,'$$ORIGIN/../lib' -Wl,-rpath,/usr/local/lib -Wl,-rpath,$(USER_LIB_DIR)
    ZNOW_FLAG   := -Wl,-z,now
    SO_EXT      := so
    OMP_CFLAGS  :=
    OMP_LDFLAGS :=
endif

# ── Default target ──────────────────────────────────────────────────────────
.PHONY: all build
all: $(BINARY)
build: $(BINARY)

# ── Web UI ──────────────────────────────────────────────────────────────────
.PHONY: build-web prepare-assets

build-web:
	@echo "🎨 Building Web UI..."
	@if command -v npm >/dev/null 2>&1; then \
		echo "Found npm locally. Building..."; \
		cd ui && npm install && npm run build; \
	elif command -v docker >/dev/null 2>&1; then \
		echo "npm not found. Building using Docker (node:20-alpine)..."; \
		docker run --rm -v $$(pwd):/app -w /app/ui node:20-alpine sh -c "(npm run build || (npm ci && npm run build)) && chown -R $$(id -u):$$(id -g) dist"; \
	fi
	@if [ ! -f ui/dist/index.html ]; then echo "❌ ui/dist/index.html missing! Build failed."; exit 1; fi

prepare-assets:
	@if [ "$$SKIP_WEB" = "1" ]; then \
		echo "⚠️  SKIP_WEB=1: Creating minimal placeholder for API-only build..."; \
		mkdir -p internal/server/dist; \
		echo '<!DOCTYPE html><html><body><h1>API-Only Mode</h1><p>Web UI not included in this build.</p></body></html>' > internal/server/dist/index.html; \
	elif [ -d ui/dist ]; then \
		echo "📦 Copying existing web assets..."; \
		rm -rf internal/server/dist; \
		cp -r ui/dist internal/server/dist; \
	else \
		$(MAKE) build-web; \
		echo "📦 Copying web assets..."; \
		rm -rf internal/server/dist; \
		cp -r ui/dist internal/server/dist; \
	fi

# ── Pure Go binary ─────────────────────────────────────────────────────────
$(BINARY): prepare-assets
	@mkdir -p $(BUILD_DIR)
	@if command -v go >/dev/null 2>&1; then \
		go build -ldflags "$(LDFLAGS)" -o $(BINARY) $(CMD); \
	elif command -v docker >/dev/null 2>&1; then \
		docker run --rm -v gleann-go-cache:/go/pkg/mod -v gleann-build-cache:/root/.cache/go-build -v $$(pwd):/app -w /app golang:1.25 sh -c "go build -buildvcs=false -ldflags '$(LDFLAGS)' -o $(BINARY) $(CMD) && chown -R $$(id -u):$$(id -g) /app/$(BUILD_DIR)"; \
	else \
		echo "❌ Neither 'go' nor 'docker' found!"; exit 1; \
	fi
	@echo "✅ Built $(BINARY)"

# ── Native / CGo builds ────────────────────────────────────────────────────
.PHONY: build-cgo
build-cgo: prepare-assets
	@mkdir -p $(BUILD_DIR)
	@if command -v go >/dev/null 2>&1; then \
		CGO_ENABLED=1 CGO_CFLAGS="-w" go build -tags "treesitter" -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/gleann-cgo $(CMD); \
	elif command -v docker >/dev/null 2>&1; then \
		docker run --rm -v gleann-go-cache:/go/pkg/mod -v gleann-build-cache:/root/.cache/go-build -v $$(pwd):/app -w /app golang:1.25 sh -c "CGO_ENABLED=1 go build -buildvcs=false -tags 'treesitter' -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/gleann-cgo $(CMD) && chown -R $$(id -u):$$(id -g) /app/$(BUILD_DIR)"; \
	fi
	@echo "✅ Built $(BUILD_DIR)/gleann-cgo (with CGo and tree-sitter)"

.PHONY: build-eif-lib
build-eif-lib:
	@if [ ! -f ext/bitllm.c/CMakeLists.txt ]; then \
		echo "📦 Initializing ext/bitllm.c submodule..."; \
		git submodule update --init --recursive ext/bitllm.c; \
	fi
	@if [ -f ext/bitllm.c/CMakeLists.txt ] && command -v cmake >/dev/null 2>&1; then \
		echo "🔧 Building bitllm.c static library..."; \
		mkdir -p ext/bitllm.c/build && \
		cmake -B ext/bitllm.c/build -S ext/bitllm.c -DCMAKE_BUILD_TYPE=Release && \
		cmake --build ext/bitllm.c/build --target bitllm_static; \
	elif ! command -v cmake >/dev/null 2>&1; then \
		echo "⚠️ Warning: cmake not found. Please install cmake to build bitllm.c."; \
	fi

.PHONY: build-eif
build-eif: build-eif-lib prepare-assets
	@mkdir -p $(BUILD_DIR)
	@if command -v go >/dev/null 2>&1; then \
		CGO_ENABLED=1 go build -tags "eif" -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/gleann-eif $(CMD); \
	elif command -v docker >/dev/null 2>&1; then \
		docker run --rm -v gleann-go-cache:/go/pkg/mod -v gleann-build-cache:/root/.cache/go-build -v $$(pwd):/app -w /app golang:1.25 sh -c "CGO_ENABLED=1 go build -buildvcs=false -tags 'eif' -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/gleann-eif $(CMD) && chown -R $$(id -u):$$(id -g) /app/$(BUILD_DIR)"; \
	fi
	@echo "✅ Built $(BUILD_DIR)/gleann-eif (with EIF-Runtime in-process BERT)"

# ── ARM64 Builds (Native / Cross-Compiler / Docker) ─────────────────────────
.PHONY: build-arm64
build-arm64: prepare-assets
	@mkdir -p $(BUILD_DIR)
	@echo "🔧 Building pure Go ARM64 binary..."
	GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/gleann-linux-arm64 $(CMD)
	@echo "✅ Built $(BUILD_DIR)/gleann-linux-arm64 (Pure Go arm64)"

.PHONY: build-eif-lib-arm64
build-eif-lib-arm64:
	@if [ ! -f ext/bitllm.c/CMakeLists.txt ]; then \
		echo "📦 Initializing ext/bitllm.c submodule..."; \
		git submodule update --init --recursive ext/bitllm.c; \
	fi
	@if [ -f ext/bitllm.c/CMakeLists.txt ] && command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then \
		echo "🔧 Cross-compiling bitllm.c static library for ARM64..."; \
		mkdir -p ext/bitllm.c/build-arm64 && \
		cmake -B ext/bitllm.c/build-arm64 -S ext/bitllm.c \
			-DCMAKE_SYSTEM_NAME=Linux \
			-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
			-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
			-DCMAKE_BUILD_TYPE=Release \
			-DEIF_ENABLE_VULKAN=OFF \
			-DCMAKE_C_FLAGS="-fno-tree-vectorize -fmath-errno" && \
		cmake --build ext/bitllm.c/build-arm64 --target bitllm_static; \
	else \
		echo "⚠️ aarch64-linux-gnu-gcc not found. Run 'make docker-build-eif-arm64' for containerized ARM build."; \
		exit 1; \
	fi

.PHONY: build-eif-arm64
build-eif-arm64: build-eif-lib-arm64 prepare-assets
	@mkdir -p $(BUILD_DIR) ext/bitllm.c/build
	@cp ext/bitllm.c/build-arm64/libbitllm.a ext/bitllm.c/build/libbitllm.a
	@echo "🔧 Building gleann-eif for ARM64..."
	CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ \
	GOOS=linux GOARCH=arm64 CGO_ENABLED=1 \
	CGO_CFLAGS="-w -fno-tree-vectorize -fmath-errno" \
	CGO_CXXFLAGS="-w -fno-tree-vectorize -fmath-errno" \
	go build -tags "eif" -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/gleann-eif-linux-arm64 $(CMD)
	@echo "✅ Built $(BUILD_DIR)/gleann-eif-linux-arm64 (Embedded EIF runtime arm64)"

.PHONY: docker-build-arm64
docker-build-arm64: prepare-assets
	@mkdir -p $(BUILD_DIR)
	@echo "🐳 Building pure Go ARM64 binary in Docker..."
	docker run --rm \
		-v gleann-go-cache:/go/pkg/mod \
		-v gleann-build-cache:/root/.cache/go-build \
		-v $$(pwd):/app -w /app golang:1.25 \
		sh -c "GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -buildvcs=false -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/gleann-linux-arm64 $(CMD) && chown -R $$(id -u):$$(id -g) /app/$(BUILD_DIR)"
	@echo "✅ Built $(BUILD_DIR)/gleann-linux-arm64 via Docker"

.PHONY: docker-builder-arm64
docker-builder-arm64:
	@if command -v docker >/dev/null 2>&1; then \
		if ! docker image inspect gleann-builder-arm64:latest >/dev/null 2>&1; then \
			echo "📦 Creating gleann-builder-arm64:latest (Debian Bookworm + aarch64 cross-compiler)..."; \
			printf 'FROM golang:1.25-bookworm\nRUN apt-get update && apt-get install -y --no-install-recommends cmake gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libgomp1-arm64-cross patchelf && rm -rf /var/lib/apt/lists/*\n' | docker build -t gleann-builder-arm64:latest -; \
		fi; \
	fi

.PHONY: docker-build-eif-arm64
docker-build-eif-arm64: docker-builder-arm64 prepare-assets
	@mkdir -p $(BUILD_DIR)
	@echo "🐳 Building gleann-eif for ARM64 in Docker container..."
	docker run --rm \
		-v gleann-go-cache:/go/pkg/mod \
		-v gleann-build-cache:/root/.cache/go-build \
		-v $$(pwd):/app -w /app gleann-builder-arm64:latest \
		sh -c "set -e && \
			mkdir -p ext/bitllm.c/build-arm64 && \
			cmake -B ext/bitllm.c/build-arm64 -S ext/bitllm.c \
				-DCMAKE_SYSTEM_NAME=Linux \
				-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
				-DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
				-DCMAKE_BUILD_TYPE=Release \
				-DEIF_ENABLE_VULKAN=OFF \
				-DCMAKE_C_FLAGS='-fno-tree-vectorize -fmath-errno' && \
			cmake --build ext/bitllm.c/build-arm64 --target bitllm_static && \
			mkdir -p ext/bitllm.c/build && \
			cp ext/bitllm.c/build-arm64/libbitllm.a ext/bitllm.c/build/libbitllm.a && \
			CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ \
			GOOS=linux GOARCH=arm64 CGO_ENABLED=1 \
			CGO_CFLAGS='-w -fno-tree-vectorize -fmath-errno' \
			CGO_CXXFLAGS='-w -fno-tree-vectorize -fmath-errno' \
			go build -buildvcs=false -tags 'eif' -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/gleann-eif-linux-arm64 $(CMD) && \
			chown -R $$(id -u):$$(id -g) /app/$(BUILD_DIR) ext/bitllm.c/build"
	@echo "✅ Built $(BUILD_DIR)/gleann-eif-linux-arm64 via Docker"

.PHONY: build-rust-core
build-rust-core:
	@if [ -d ext/gleann-core-rs ] && command -v cargo >/dev/null 2>&1; then \
		echo "🔧 Building Rust core..."; \
		cd ext/gleann-core-rs && cargo build --release; \
	fi

# ── Full Binary (Tree-sitter + KuzuDB CGo + EIF-Runtime) ─────────────────────
.PHONY: builder-image
builder-image:
	@if command -v docker >/dev/null 2>&1; then \
		if ! docker image inspect $(BUILDER_IMAGE) >/dev/null 2>&1; then \
			echo "📦 Creating $(BUILDER_IMAGE) (one-time setup, eliminates apt-get on every build)..."; \
			printf 'FROM golang:1.25\nRUN apt-get update && apt-get install -y --no-install-recommends libopenblas-dev libgomp1 patchelf && rm -rf /var/lib/apt/lists/*\n' | docker build -t $(BUILDER_IMAGE) -; \
		fi; \
	fi

.PHONY: full
full: $(BINARY_FULL)

$(BINARY_FULL): build-eif-lib prepare-assets builder-image
	@echo "🔧 Building $(BINARY_FULL) with FAISS + Tree-sitter + KuzuDB CGo + EIF Runtime (standalone single executable)..."
	@mkdir -p $(BUILD_DIR)/stage
	@if command -v go >/dev/null 2>&1; then \
		CGO_ENABLED=1 \
		CGO_CFLAGS="-w -I$(FAISS_INC_DIR)" \
		CGO_CXXFLAGS="-w -I$(FAISS_INC_DIR)" \
		CGO_LDFLAGS="$(RPATH_FLAGS) -L$(FAISS_LIB_DIR) -lfaiss_c -lfaiss -lopenblas -lgomp -lstdc++ -lm" \
		go build -tags "treesitter,faiss,eif" -ldflags "$(LDFLAGS)" -o $(BUILD_DIR)/stage/gleann-full-bin $(CMD) && \
		go mod download github.com/kuzudb/go-kuzu && \
		KUZU_DIR=$$(go list -m -f '{{.Dir}}' github.com/kuzudb/go-kuzu 2>/dev/null || true); \
		if [ -z "$$KUZU_DIR" ]; then KUZU_DIR=$$(find $$(go env GOPATH)/pkg/mod/github.com/kuzudb/go-kuzu* -maxdepth 0 2>/dev/null | head -n 1); fi; \
		cp "$$KUZU_DIR/lib/dynamic/linux-amd64/libkuzu.so" $(BUILD_DIR)/stage/ 2>/dev/null || true; \
		cp -L $(FAISS_LIB_DIR)/libopenblas.so.0 $(BUILD_DIR)/stage/ 2>/dev/null || cp -L /usr/lib/x86_64-linux-gnu/libopenblas.so.0 $(BUILD_DIR)/stage/ 2>/dev/null || true; \
		cp -L /usr/lib/x86_64-linux-gnu/libgomp.so.1 $(BUILD_DIR)/stage/ 2>/dev/null || true; \
		cp -L $(FAISS_LIB_DIR)/libgfortran.so.5 $(BUILD_DIR)/stage/ 2>/dev/null || cp -L /usr/lib/x86_64-linux-gnu/libgfortran.so.5 $(BUILD_DIR)/stage/ 2>/dev/null || true; \
		if command -v patchelf >/dev/null 2>&1; then \
			patchelf --set-rpath '$$ORIGIN:$$ORIGIN/../lib:/usr/local/lib:$(USER_LIB_DIR)' $(BUILD_DIR)/stage/gleann-full-bin 2>/dev/null || true; \
			for so in $(BUILD_DIR)/stage/*.so*; do \
				if [ -f "$$so" ]; then \
					patchelf --set-rpath '$$ORIGIN:$$ORIGIN/../lib:/usr/local/lib' "$$so" 2>/dev/null || true; \
				fi; \
			done; \
		fi; \
		tar czf cmd/gleann-full-launcher/payload.tar.gz -C $(BUILD_DIR)/stage . && \
		CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o $(BINARY_FULL) ./cmd/gleann-full-launcher && \
		tar -czf cmd/gleann-full-launcher/payload.tar.gz --files-from /dev/null && \
		rm -rf $(BUILD_DIR)/stage; \
	elif command -v docker >/dev/null 2>&1; then \
		docker run --rm \
			-v gleann-go-cache:/go/pkg/mod \
			-v gleann-build-cache:/root/.cache/go-build \
			-v $$(pwd):/app -w /app $(BUILDER_IMAGE) sh -c "\
				set -e && \
				mkdir -p $(BUILD_DIR)/stage && \
				CGO_ENABLED=1 \
				CGO_CFLAGS='-w -I/app/deps/faiss_install/include' \
				CGO_CXXFLAGS='-w -I/app/deps/faiss_install/include' \
				CGO_LDFLAGS='$(RPATH_FLAGS) -L/app/deps/faiss_install/lib -lfaiss_c -lfaiss -lopenblas -lgomp -lstdc++ -lm' \
				go build -buildvcs=false -tags 'treesitter,faiss' -ldflags '$(LDFLAGS) -extldflags \"$(RPATH_FLAGS)\"' -o $(BUILD_DIR)/stage/gleann-full-bin $(CMD) && \
				go mod download github.com/kuzudb/go-kuzu && \
				KUZU_DIR=\$$(go list -m -f '{{.Dir}}' github.com/kuzudb/go-kuzu) && \
				cp \"\$$KUZU_DIR/lib/dynamic/linux-amd64/libkuzu.so\" $(BUILD_DIR)/stage/ && \
				cp -L /usr/lib/x86_64-linux-gnu/libopenblas.so.0 $(BUILD_DIR)/stage/ 2>/dev/null || true && \
				cp -L /usr/lib/x86_64-linux-gnu/libgomp.so.1 $(BUILD_DIR)/stage/ 2>/dev/null || true && \
				cp -L /usr/lib/x86_64-linux-gnu/libgfortran.so.5 $(BUILD_DIR)/stage/ 2>/dev/null || true && \
				patchelf --set-rpath '\$$ORIGIN' $(BUILD_DIR)/stage/gleann-full-bin 2>/dev/null || true && \
				for so in $(BUILD_DIR)/stage/*.so*; do \
					[ -f \"\$$so\" ] && patchelf --set-rpath '\$$ORIGIN' \"\$$so\" 2>/dev/null || true; \
				done && \
				tar czf cmd/gleann-full-launcher/payload.tar.gz -C $(BUILD_DIR)/stage . && \
				CGO_ENABLED=0 go build -buildvcs=false -ldflags '$(LDFLAGS)' -o $(BINARY_FULL) ./cmd/gleann-full-launcher && \
				tar -czf cmd/gleann-full-launcher/payload.tar.gz --files-from /dev/null && \
				rm -rf $(BUILD_DIR)/stage && \
				chown -R $$(id -u):$$(id -g) /app/$(BUILD_DIR) cmd/gleann-full-launcher /app/internal/server/dist 2>/dev/null || true"; \
	fi
	@echo "✅ Built single standalone $(BINARY_FULL) with FAISS + Tree-sitter + KuzuDB"

# ── Install ─────────────────────────────────────────────────────────────────

# install-user — build gleann-full and install to ~/.local/bin/gleann
.PHONY: install-user
install-user: $(BINARY_FULL)
	@mkdir -p $(USER_BIN_DIR) $(USER_LIB_DIR)
	install -m 0755 $(BINARY_FULL) $(USER_BIN_DIR)/gleann
	install -m 0755 $(BINARY_FULL) $(USER_BIN_DIR)/gleann-full
	@if [ -f $(BUILD_DIR)/libkuzu.so ]; then \
		install -m 0755 $(BUILD_DIR)/libkuzu.so $(USER_LIB_DIR)/; \
		install -m 0755 $(BUILD_DIR)/libkuzu.so $(USER_BIN_DIR)/; \
	fi
	@echo "✅ Installed gleann-full → $(USER_BIN_DIR)/gleann"
	@echo "   Make sure $(USER_BIN_DIR) is in your PATH."

# install-user-lite — build plain gleann (no CGo) and install to ~/.local/bin/gleann
.PHONY: install-user-lite
install-user-lite: $(BINARY)
	@mkdir -p $(USER_BIN_DIR)
	install -m 0755 $(BINARY) $(USER_BIN_DIR)/gleann
	@echo "✅ Installed gleann → $(USER_BIN_DIR)/gleann"

# install — install to /usr/local/bin (system-wide, needs sudo)
.PHONY: install
install: $(BINARY_FULL)
	install -m 0755 $(BINARY_FULL) $(INSTALL_DIR)/gleann
	@if [ -f $(BUILD_DIR)/libkuzu.so ]; then \
		install -m 0755 $(BUILD_DIR)/libkuzu.so /usr/local/lib/ 2>/dev/null || true; \
	fi
	@echo "✅ Installed $(BINARY_FULL) → $(INSTALL_DIR)/gleann"

# ── Tests ────────────────────────────────────────────────────────────────────
ORIGINAL_GOPATH ?= $(shell go env GOPATH 2>/dev/null || echo $(HOME)/go)

.PHONY: test
test:
	@if command -v go >/dev/null 2>&1; then \
		mkdir -p /tmp/gleann-test-home; \
		GLEANN_TEST_MODE=true GOPATH=$(ORIGINAL_GOPATH) HOME=/tmp/gleann-test-home go test -race -timeout 120s $$(go list ./... | grep -v /tests/benchmarks); \
	elif command -v docker >/dev/null 2>&1; then \
		docker run --rm -v $$(pwd):/app -w /app golang:1.25-bookworm sh -c "go test -v -timeout 120s \$$(go list ./... | grep -v /tests/benchmarks)"; \
	fi

.PHONY: test-integration
test-integration:
	@if command -v go >/dev/null 2>&1; then \
		mkdir -p /tmp/gleann-test-home; \
		GLEANN_TEST_MODE=true GOPATH=$(ORIGINAL_GOPATH) HOME=/tmp/gleann-test-home go test -v -timeout 5m ./tests/integration/...; \
	elif command -v docker >/dev/null 2>&1; then \
		docker run --rm --network host -v $$(pwd):/app -w /app golang:1.25-alpine sh -c "go test -v -timeout 5m ./tests/integration/..."; \
	fi

.PHONY: test-e2e
test-e2e:
	@if command -v go >/dev/null 2>&1; then \
		mkdir -p /tmp/gleann-test-home; \
		GLEANN_TEST_MODE=true GOPATH=$(ORIGINAL_GOPATH) HOME=/tmp/gleann-test-home go test -v -timeout 5m ./tests/e2e/...; \
	elif command -v docker >/dev/null 2>&1; then \
		docker run --rm --network host -v $$(pwd):/app -w /app golang:1.25-alpine sh -c "go test -v -timeout 5m ./tests/e2e/..."; \
	fi

.PHONY: test-eif
test-eif: build-eif-lib
	@if command -v go >/dev/null 2>&1; then \
		go test -v -tags "eif" ./internal/embedding -run TestEIF; \
	fi

# ── Clean ────────────────────────────────────────────────────────────────────
.PHONY: clean
clean:
	rm -rf $(BUILD_DIR) dist/ gleann-test gleann-test-faiss coverage.out coverage-ts.out
	@echo "🧹 Cleaned"

.PHONY: vet
vet:
	@if command -v go >/dev/null 2>&1; then \
		go vet ./...; \
	elif command -v docker >/dev/null 2>&1; then \
		docker run --rm -v $$(pwd):/app -w /app golang:1.25-alpine go vet ./...; \
	fi
	@echo "✅ go vet passed"

# ── Lint / Vulnerability Scan ──────────────────────────────────────────────
.PHONY: lint
lint:
	@command -v staticcheck >/dev/null 2>&1 || { echo "installing staticcheck..."; go install honnef.co/go/tools/cmd/staticcheck@latest; }
	@command -v govulncheck >/dev/null 2>&1 || { echo "installing govulncheck..."; go install golang.org/x/vuln/cmd/govulncheck@latest; }
	@echo "── staticcheck ──"
	staticcheck ./...
	@echo "── govulncheck ──"
	govulncheck ./...
	@echo "── go mod tidy -diff ──"
	go mod tidy -diff
	@echo "✅ lint passed"
