# DAM — local development helpers
#
# Quick start:
#   make setup   ← run once after cloning
#   make dev     ← hot-reload dev server (backend + Next.js dev)
#   make build   ← build production frontend after UI changes
#   make run     ← production mode using the existing frontend build
#   make test    ← run the full test suite
#   make docs    ← preview documentation (mkdocs serve)
#
# CI jobs (GitHub Actions):
#   make ci-lint           ← ruff format + lint
#   make ci-syntax        ← AST parse check
#   make ci-import         ← build Rust + import
#   make ci-stackfile     ← validate stackfile
#
.PHONY: setup setup-lerobot ros dev build run docs docs-check test test-py test-rs test-ui test-one lint format typecheck check build-rs clean help dam validate record ci-lint ci-syntax ci-import ci-stackfile _kill_port

# Ensure scripts are executable before every target that uses them
_chmod:
	@chmod +x scripts/setup.sh scripts/run.sh scripts/run_prod.sh scripts/test.sh

_kill_port:
	@echo "Checking for processes on ports 8080 and 3000..."
	@lsof -ti:8080 -ti:3000 | sort -u | xargs kill -9 2>/dev/null || true

setup: _chmod   ## First-time setup: venv + Rust + npm + pre-commit hooks + build frontend
	@bash scripts/setup.sh
	@$(MAKE) build

setup-lerobot: _chmod   ## Setup with lerobot hardware support (SO-ARM101 + cameras)
	@bash scripts/setup.sh --lerobot

ros: _chmod   ## Setup with ROS2 support (transforms3d; install the ROS2 distro separately)
	@bash scripts/setup.sh --ros

build: _chmod   ## Build frontend (Next.js production) + copy static assets
	@echo "Building frontend (Next.js production)..."
	@cd dam-console && npm run build
	@cp -r dam-console/public dam-console/.next/standalone/public 2>/dev/null || true
	@cp -r dam-console/.next/static dam-console/.next/standalone/.next/static 2>/dev/null || true
	@echo "Frontend build complete."

build-rs: _chmod   ## Rebuild Rust extension only (dam_rs via maturin)
	@bash scripts/setup.sh --rust-only

setup-precommit:   ## Install and setup pre-commit hooks
	@uv pip install pre-commit --python .venv/bin/python
	@.venv/bin/pre-commit install

# macOS: prefer venv's bundled ffmpeg dylibs over Homebrew to silence
# "Class AVFAudioReceiver is implemented in both …" ObjC duplicate warnings.
_AV_DYLIB_DIR := $(shell ls -d .venv/lib/python*/site-packages/av/.dylibs 2>/dev/null | head -1)
_DYLD_PREFIX   := $(if $(_AV_DYLIB_DIR),DYLD_LIBRARY_PATH="$(_AV_DYLIB_DIR):$$DYLD_LIBRARY_PATH" ,)

dev: _chmod _kill_port  ## Dev mode: hot-reload backend + Next.js dev server
	@$(_DYLD_PREFIX)BACKEND_SCRIPT=scripts/dam_host.py bash scripts/run.sh

run: _chmod _kill_port  ## Production mode: start backend + existing frontend build
	@$(_DYLD_PREFIX)bash scripts/run_prod.sh

record: _chmod  ## Safe recording with DAM guards (edit examples/stackfiles/safety.yaml, or pass ARGS)
	@.venv/bin/python scripts/record.py $(ARGS)

docs:   ## Preview documentation locally at http://127.0.0.1:8002/DAM/
	@export PATH="$$HOME/.local/bin:$$HOME/.cargo/bin:/opt/homebrew/bin:$$PATH"; \
	 uv pip install --python .venv/bin/python mkdocs mkdocs-material pymdown-extensions --quiet
	@.venv/bin/mkdocs serve --dev-addr 127.0.0.1:8002

docs-check:   ## Run documentation quality checks (strict MkDocs + onboarding patterns)
	@python scripts/check_docs.py

test: _chmod   ## Run all tests + linters (Python, Rust, frontend)
	@bash scripts/test.sh

test-py: _chmod   ## Python tests only (unit + integration + safety + property)
	@bash scripts/test.sh --python

test-rs: _chmod   ## Rust tests only (cargo test --workspace)
	@bash scripts/test.sh --rust

test-ui: _chmod   ## Frontend tests only (jest --ci)
	@bash scripts/test.sh --frontend

test-one:   ## Run a single test file: make test-one FILE=tests/unit/test_guards.py
	@.venv/bin/python -m pytest $(FILE) -x -v

lint: _chmod   ## Linters only (ruff check, mypy, cargo clippy) — no auto-fix
	@bash scripts/test.sh --lint

typecheck:   ## Run mypy only (fast type-check without ruff/tests)
	@.venv/bin/mypy --config-file pyproject.toml dam tests

check:   ## Run all pre-commit hooks on all files (one-shot CI gate)
	@.venv/bin/pre-commit run --all-files

format:   ## Auto-format Python (ruff) + Rust (cargo fmt) + trailing whitespace
	@echo "Formatting Python..."
	@.venv/bin/ruff format dam/ tests/ scripts/
	@.venv/bin/ruff check --fix dam/ tests/ scripts/ || true
	@if command -v cargo >/dev/null 2>&1 && [ -d dam-rust ]; then \
		echo "Formatting Rust..."; \
		cargo fmt --all --manifest-path dam-rust/Cargo.toml; \
	fi
	@echo "Done."

clean:   ## Remove venv, Rust build artefacts, and node_modules
	rm -rf .venv dam-rust/target dam-console/node_modules dam-console/.next

help:   ## Show this help message
	@echo ""
	@echo "  DAM — local development targets"
	@echo ""
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
		| awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-14s\033[0m %s\n", $$1, $$2}'
	@echo ""

dam:   ## Run the dam CLI (e.g. make dam ARGS="inspect" or ARGS="callbacks")
	@.venv/bin/dam $(ARGS)

callbacks:  ## List all 18 built-in boundary callbacks
	@.venv/bin/dam callbacks

validate:   ## Validate all example Stackfiles (the CI stackfile gate)
	@.venv/bin/dam validate examples/stackfiles/*.yaml

# CI targets (mirrors GitHub Actions)
ci-lint: _chmod
	@bash scripts/test.sh --lint

ci-syntax:
	@python -c "import ast; import glob; [ast.parse(open(f).read()) for f in glob.glob('dam/**/*.py', recursive=True)]"

ci-import: _chmod
	@bash scripts/setup.sh --rust-only
	@python -c "import dam; print('OK')"

ci-stackfile: _chmod
	@.venv/bin/dam validate examples/stackfiles/*.yaml
