# Variables
# Every numbered directory at the repository root is treated as a self-contained flake example.
EXAMPLES := $(sort $(wildcard [0-9][0-9]-*))

# Tools are invoked via `nix run` so nothing needs to be pre-installed beyond Nix itself.
# Override any of these if you have the tools on $PATH and want faster startup.
NIX        ?= nix
NIXFMT     ?= $(NIX) run nixpkgs#nixfmt-rfc-style --
STATIX     ?= $(NIX) run nixpkgs#statix --
DEADNIX    ?= $(NIX) run nixpkgs#deadnix --

# Selector for single-example targets (dev, show, update-one).
EXAMPLE    ?=

# Default target
.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: examples
examples: ## List discovered example directories
	@echo "Examples:"
	@for e in $(EXAMPLES); do echo "  - $$e"; done

.PHONY: fmt
fmt: ## Format every .nix file with nixfmt (RFC 166 style)
	@echo "Formatting .nix files..."
	@find . -type f -name '*.nix' -not -path './.git/*' -print0 | xargs -0 -r $(NIXFMT)

.PHONY: fmt-check
fmt-check: ## Check formatting of every .nix file (non-zero exit on drift)
	@echo "Checking .nix formatting..."
	@find . -type f -name '*.nix' -not -path './.git/*' -print0 | xargs -0 -r $(NIXFMT) --check

.PHONY: lint
lint: ## Run statix and deadnix against every example
	@echo "Running statix..."
	@$(STATIX) check .
	@echo "Running deadnix..."
	@$(DEADNIX) --fail .

.PHONY: fix-lint
fix-lint: ## Apply statix and deadnix autofixes where possible
	@echo "Applying statix fixes..."
	@$(STATIX) fix .
	@echo "Applying deadnix fixes..."
	@$(DEADNIX) --edit .

.PHONY: check
check: ## Run `nix flake check` in every example directory
	@if [ -z "$(EXAMPLES)" ]; then echo "No examples found."; exit 0; fi
	@set -e; for e in $(EXAMPLES); do \
	    echo ">>> nix flake check $$e"; \
	    (cd "$$e" && $(NIX) flake check); \
	done

.PHONY: build
build: ## Run `nix build` on the default package of every example (skips those without one)
	@if [ -z "$(EXAMPLES)" ]; then echo "No examples found."; exit 0; fi
	@set -e; for e in $(EXAMPLES); do \
	    if $(NIX) eval --no-warn-dirty "$$e#packages.$$($(NIX) eval --impure --raw --expr 'builtins.currentSystem').default" --apply 'x: true' >/dev/null 2>&1; then \
	        echo ">>> nix build $$e"; \
	        (cd "$$e" && $(NIX) build --no-link); \
	    else \
	        echo "--- $$e has no default package, skipping"; \
	    fi; \
	done

.PHONY: show
show: ## Print `nix flake show` for every example
	@if [ -z "$(EXAMPLES)" ]; then echo "No examples found."; exit 0; fi
	@for e in $(EXAMPLES); do \
	    echo ">>> nix flake show $$e"; \
	    (cd "$$e" && $(NIX) flake show) || true; \
	done

.PHONY: update
update: ## Run `nix flake update` in every example (updates all flake.lock files)
	@if [ -z "$(EXAMPLES)" ]; then echo "No examples found."; exit 0; fi
	@set -e; for e in $(EXAMPLES); do \
	    echo ">>> nix flake update $$e"; \
	    (cd "$$e" && $(NIX) flake update); \
	done

.PHONY: update-one
update-one: ## Run `nix flake update` in EXAMPLE=<dir>
	@if [ -z "$(EXAMPLE)" ]; then echo "Usage: make update-one EXAMPLE=<dir>"; exit 1; fi
	@(cd "$(EXAMPLE)" && $(NIX) flake update)

.PHONY: dev
dev: ## Enter `nix develop` in EXAMPLE=<dir>
	@if [ -z "$(EXAMPLE)" ]; then echo "Usage: make dev EXAMPLE=<dir>"; exit 1; fi
	@(cd "$(EXAMPLE)" && $(NIX) develop)

.PHONY: metadata
metadata: ## Print `nix flake metadata` for every example
	@for e in $(EXAMPLES); do \
	    echo ">>> nix flake metadata $$e"; \
	    (cd "$$e" && $(NIX) flake metadata) || true; \
	done

.PHONY: clean
clean: ## Remove `result` symlinks produced by `nix build`
	@echo "Removing result symlinks..."
	@find . -maxdepth 3 -type l \( -name 'result' -o -name 'result-*' \) -print -delete

.PHONY: gc
gc: ## Run `nix store gc` to garbage collect unreferenced store paths
	@echo "Running nix store gc..."
	@$(NIX) store gc

.PHONY: setup-hooks
setup-hooks: ## Install Git hooks (pre-commit)
	@echo "Setting up Git hooks..."
	@if ! command -v pre-commit >/dev/null 2>&1; then \
	    echo "pre-commit not found. Install it via 'pip install pre-commit' or enter a shell that provides it."; \
	    exit 1; \
	fi
	@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
	@echo "Running pre-commit hooks on all files..."
	@pre-commit run --all-files --show-diff-on-failure

.PHONY: all
all: fmt-check lint check ## Run format check, lint, and flake checks
	@echo "All checks passed."
