.DEFAULT_GOAL := build
.PHONY: help
help: ## Display this help message
	@echo "Usage: make [target]"
	@echo
	@echo "Targets:"
	@awk '/^[a-zA-Z0-9_-]+:.*## / {printf "%s : %s\n", $$1, substr($$0, index($$0, "##") + 3)}' $(MAKEFILE_LIST) | sort | column -t -s ':'
	@echo

.PHONY: build
build: ## Build the escript
	mix escript.build

.PHONY: compile
compile: ## Compile the project
	mix compile --all-warnings --warnings-as-errors
	@echo

.PHONY: test
test: ## Run tests
	mix test
	@echo

.PHONY: cover
cover: ## Run tests with coverage
	mix coveralls
	@echo

.PHONY: dialyzer
dialyzer: ## Run Dialyzer
	MIX_ENV=dev mix dialyzer
	@echo

.PHONY: docs
docs: md-lint ## Generate documentation
	mix docs
	@echo

# Builds the docs purely to surface ExDoc autolink failures (broken
# `Mod.fun/arity` references in @doc/@moduledoc strings). These are invisible
# to compile/test/dialyzer - only the doc generator resolves them - so without
# this the only gate is CI's "build docs" step. `--warnings-as-errors` makes
# ExDoc exit non-zero on any warning, mirroring that CI step locally.
.PHONY: docs-check
docs-check: ## Build docs, failing on any ExDoc warning (autolink check)
	MIX_ENV=dev mix docs --warnings-as-errors
	@echo

# Boots the built escript once and requires exit 0. The test suite cannot
# catch production boot regressions: test_helper starts foundational services
# (e.g. Services.Globals) for the whole VM, so a missing start in the prod
# boot path passes every test and crashes the binary (see docs/dev/gotchas.md
# item 9). Help output exercises the full pre-parse boot (Fnord.Instance,
# frob loading, CLI parse) without needing a project or network. HOME is
# isolated so the check neither reads nor writes the developer's ~/.fnord.
.PHONY: boot-check
boot-check: build ## Boot the escript once (catches prod-boot-path regressions)
	@tmp=$$(mktemp -d) && HOME=$$tmp ./fnord -h > /dev/null && rm -rf $$tmp
	@echo "escript boots"
	@echo

.PHONY: check
check: compile boot-check test dialyzer md-lint docs-check ## Run all checks
	@echo "All checks passed"

.PHONY: md-lint
md-lint: ## Lint markdown files
	markdownlint-cli2 --config .markdownlint.json {test,lib,docs}/**/*.md README.md

.PHONY: md-format
md-format: ## Format markdown files
	@git diff --exit-code >/dev/null || (printf "!! Uncommitted changes found\n!! Commit or stash first\n\n" >&2 && exit 1)
	@markdownlint-cli2 --config .markdownlint.json --fix {test,lib,docs}/**/*.md README.md

.PHONY: format
format: ## Format the code
	mix format

# Deliberately NOT a dependency of release/publish: an aborted publish must
# not leave a bump commit behind. Run as `make bump && make release`.
.PHONY: bump
bump: ## Bump the patch version in mix.exs and commit it as "version bump"
	@test -z "$$(git status --porcelain)" || (printf "!! Working tree is not clean\n!! Commit or stash first\n\n" >&2 && exit 1)
	@perl -i -pe 's/version: "\K(\d+)\.(\d+)\.(\d+)/"$$1.$$2." . ($$3 + 1)/e' mix.exs
	@git add mix.exs
	@git commit --quiet -m "version bump"
	@printf "Bumped to %s\n" "$$(perl -ne 'print $$1 if /version: "([^"]+)"/' mix.exs)"

.PHONY: release
release: publish ## Alias for publish because apparently this is what my fingers' muscle memory prefers

.PHONY: publish
publish: check docs ## Publish the package
	mix hex.publish

.PHONY: republish
republish: check docs ## Republish the package (within like 20m of publishing the last version)
	mix hex.publish --replace

.PHONY: find-bak
find-bak: ## Find all backup files generated by fnord itself (**/*.*.bak)
	find . -name "*.*.bak" -print

.PHONY: clean-bak
clean-bak: ## Clean up backup files generated by fnord itself (**/*.*.bak)
	find . -name "*.*.bak" -print -exec rm -f {} \;

.PHONY: clean
clean: clean-bak ## Clean up ALL build artifacts, including dependencies and build directories
	mix clean
	rm -rf _build
	rm -rf deps
	rm -rf .elixir_ls

# ------------------------------------------------------------------------------
# Smoke-test rig
#
# Runs fnord against the real API in a HOME-isolated sandbox so the developer's
# actual ~/.fnord/ config, conversations, memory, and indexed projects are
# untouched. API keys propagate from the parent shell's env (the rig does not
# override OPENAI_API_KEY / FNORD_OPENAI_API_KEY).
#
# Default sandbox: $(SMOKE_HOME), default project root: this repo. Override on
# the command line, e.g.
#   make smoke-setup SMOKE_HOME=/tmp/other SMOKE_PROJECT=otherproj
#   make smoke-ask ARGS='-q "summarize the responses-api migration so far"'
#   make smoke-clean
# ------------------------------------------------------------------------------

SMOKE_HOME ?= /tmp/fnord-responses-smoke
SMOKE_PROJECT ?= smoke

.PHONY: smoke-setup
smoke-setup: build ## Index $(PWD) into the smoke sandbox at $(SMOKE_HOME) (idempotent)
	mkdir -p $(SMOKE_HOME)
	HOME=$(SMOKE_HOME) ./fnord index -p $(SMOKE_PROJECT) -d $(PWD)

.PHONY: smoke-ask
smoke-ask: build ## Ask the smoke project. Pass flags via ARGS, e.g. ARGS='-q "..."'
	HOME=$(SMOKE_HOME) ./fnord ask -p $(SMOKE_PROJECT) $(ARGS)

.PHONY: smoke-clean
smoke-clean: ## Nuke the smoke sandbox. Run before retesting a destructive change.
	rm -rf $(SMOKE_HOME)
