# Storage engine playground helpers.

HAS_CARGO := $(wildcard Cargo.toml)

# Workspace crates discovered under `crates/*/Cargo.toml`. The directory name is
# assumed to match the package name (the convention documented in crates/README.md).
CRATE_MANIFESTS := $(wildcard crates/*/Cargo.toml)
CRATES := $(patsubst crates/%/Cargo.toml,%,$(CRATE_MANIFESTS))
CRATE_FLAGS := $(addprefix -p ,$(CRATES))

.DEFAULT_GOAL := help

.PHONY: help
help: ## Show help messages for all available targets
	@grep -E '^[a-zA-Z_-]+:.*## .*$$' Makefile | \
	awk 'BEGIN {FS = ":.*## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'

.PHONY: format
format: ## Apply code formatting
	@if [ -z "$(HAS_CARGO)" ]; then \
		echo "No Cargo.toml found. Skipping Rust formatting."; \
	else \
		cargo fmt --all; \
	fi

.PHONY: format-check
format-check: ## Check code formatting without applying changes
	@if [ -z "$(HAS_CARGO)" ]; then \
		echo "No Cargo.toml found. Skipping Rust format check."; \
	else \
		cargo fmt --all --check; \
	fi

.PHONY: lint
lint: ## Run linters across every crate under crates/
	@if [ -z "$(HAS_CARGO)" ]; then \
		echo "No Cargo.toml found. Skipping lint."; \
	elif [ -z "$(CRATES)" ]; then \
		echo "No crates/*/Cargo.toml found. Skipping lint."; \
	else \
		cargo clippy $(CRATE_FLAGS) --no-deps -- -D warnings -D clippy::unwrap_used -D clippy::expect_used; \
	fi

.PHONY: test
test: ## Run unit, integration, and doc tests across all features (no benches)
	@if [ -z "$(HAS_CARGO)" ]; then \
		echo "No Cargo.toml found. Skipping tests."; \
	else \
		cargo test --all-features; \
	fi

.PHONY: bench
bench: ## Run benchmarks across all features
	@if [ -z "$(HAS_CARGO)" ]; then \
		echo "No Cargo.toml found. Skipping benchmarks."; \
	else \
		cargo bench --all-features; \
	fi

.PHONY: bench-check
bench-check: ## Type-check benchmark code without running it
	@if [ -z "$(HAS_CARGO)" ]; then \
		echo "No Cargo.toml found. Skipping bench check."; \
	else \
		cargo check --benches --all-features --quiet; \
	fi

.PHONY: check
check: format-check lint test bench-check ## Run all checks (format-check, lint, test, bench-check)

.PHONY: clean
clean: ## Remove build output
	@if [ -z "$(HAS_CARGO)" ]; then \
		echo "No Cargo.toml found. Nothing to clean."; \
	else \
		cargo clean; \
	fi

EXPORTER_DIR := tools/exporter
EXPORTER_FIXTURES := crates/plan-runner/fixtures
EXAMPLES_DIR := $(EXPORTER_DIR)/examples

.PHONY: export-fixtures
export-fixtures: ## Regenerate plan JSON for every tools/exporter/examples/*.scenario.json (needs Cabal and GHC; use `make shell` first).
	@if ! command -v cabal >/dev/null 2>&1; then \
		echo "cabal not found. Enter the dev shell with 'make shell' (or 'nix develop') first."; \
		exit 1; \
	fi
	@cd $(EXPORTER_DIR) && cabal build plan-export
	@mkdir -p $(EXPORTER_FIXTURES)
	@for sc in $(EXAMPLES_DIR)/*.scenario.json; do \
		base=$$(basename $$sc .scenario.json); \
		out=$(EXPORTER_FIXTURES)/$$base.json; \
		echo "exporting $$sc -> $$out"; \
		(cd $(EXPORTER_DIR) && cabal run -v0 plan-export -- examples/$$base.scenario.json) > $$out; \
	done

.PHONY: examples
examples: export-fixtures ## Regenerate fixtures from scenarios and run them through plan-runner against their oracles.
	@cargo test -p plan-runner --test examples

.PHONY: shell
shell: ## Enter the Nix dev shell defined in flake.nix
	@nix develop

.PHONY: setup-hooks
setup-hooks: ## Install Git hooks with pre-commit
	@pre-commit install --hook-type pre-commit
	@pre-commit install --hook-type pre-push
	@pre-commit install-hooks

.PHONY: test-hooks
test-hooks: ## Run pre-commit hooks across all files
	@pre-commit run --all-files --show-diff-on-failure
