PROJECT_NAME := daktela-paleo
REQ_IMAGE ?= harbor.daktela.com/coworkers/$(PROJECT_NAME)-requirements
REQ_TAG := $(shell \
	sha256sum pyproject.toml uv.lock containers/requirements.Dockerfile 2>/dev/null \
	| sha256sum | awk '{print $$1}' \
)
REQ_IMG := $(REQ_IMAGE):$(REQ_TAG)
CI_COMMIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
RELEASE_TAG ?= $(CI_COMMIT_TAG)
VENV_BIN := .venv/bin
COVERAGE_WORKERS ?= 4

.PHONY: ruff pyright coverage coverage-ci cover worktree compute-req-tag ci-build-requirements docs-serve docs-build clean update-version build check-wheel check-dist publish release startup-benchmark

# Allow `make coverage <test_file> <covered_file>` in addition to variable form.
ifeq ($(firstword $(MAKECMDGOALS)),coverage)
COVERAGE_POSITIONAL_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
COVERAGE_TEST_FILE ?= $(word 1,$(COVERAGE_POSITIONAL_ARGS))
COVERAGE_SOURCE_FILE ?= $(word 2,$(COVERAGE_POSITIONAL_ARGS))
COVERAGE_EXTRA_POSITIONAL_ARGS := $(wordlist 3,$(words $(COVERAGE_POSITIONAL_ARGS)),$(COVERAGE_POSITIONAL_ARGS))
.PHONY: $(COVERAGE_POSITIONAL_ARGS)
$(COVERAGE_POSITIONAL_ARGS):
	@:
endif

# Allow `make worktree <subcommand> [args...]`.
ifeq ($(firstword $(MAKECMDGOALS)),worktree)
WORKTREE_GOALS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
.PHONY: $(WORKTREE_GOALS)
$(WORKTREE_GOALS):
	@:
endif

ruff:
	$(VENV_BIN)/ruff check

pyright:
	$(VENV_BIN)/pyright

docs-serve:
	$(VENV_BIN)/mkdocs serve

docs-build:
	$(VENV_BIN)/mkdocs build --strict

startup-benchmark:
	uv run python -m daktela_paleo.startup_benchmark $(STARTUP_BENCHMARK_ARGS)

worktree:
	uv run python -m scripts.worktree $(WORKTREE_GOALS)

clean:
	rm -rf dist

update-version:
	$(VENV_BIN)/python scripts/bump_version.py --tag "$(RELEASE_TAG)"

build:
	$(VENV_BIN)/python -m build

check-wheel:
	@set -e; \
	wheel=$$(ls dist/*.whl); \
	$(VENV_BIN)/python -c 'import sys, zipfile; archive = zipfile.ZipFile(sys.argv[1]); names = set(archive.namelist()); entry_points_name = next((name for name in names if name.endswith(".dist-info/entry_points.txt")), None); entry_points = archive.read(entry_points_name).decode() if entry_points_name is not None else ""; assert entry_points_name is not None, "missing wheel entry_points metadata"; assert "daktela-paleo = daktela_paleo.app:main" in entry_points, "missing daktela-paleo console script entry point"; assert not any(name == "scripts/__init__.py" or name.startswith("scripts/") for name in names), "wheel unexpectedly contains the scripts package"' "$$wheel"; \
	set -e; \
	wheel=$$(ls dist/*.whl); \
	tmpdir=$$(mktemp -d); \
	trap 'rm -rf "$$tmpdir"' EXIT; \
	$(VENV_BIN)/python -m venv "$$tmpdir/venv"; \
	"$$tmpdir/venv/bin/pip" install --no-deps "$$wheel"; \
	test -x "$$tmpdir/venv/bin/daktela-paleo"; \
	"$$tmpdir/venv/bin/python" -c "import daktela_paleo"

check-dist:
	$(VENV_BIN)/python -m twine check dist/*.whl dist/*.tar.gz

publish:
	$(VENV_BIN)/python -m twine upload dist/*.whl dist/*.tar.gz

release: clean update-version build check-wheel check-dist publish

coverage:
	@set -e; \
	if [ -n "$(COVERAGE_EXTRA_POSITIONAL_ARGS)" ]; then \
		echo "Usage: make coverage [<test_file> <covered_file>]"; \
		echo "Or: make coverage COVERAGE_TEST_FILE=<test_file> COVERAGE_SOURCE_FILE=<covered_file>"; \
		exit 1; \
	fi; \
	$(VENV_BIN)/coverage erase; \
	if [ -n "$(COVERAGE_TEST_FILE)" ] || [ -n "$(COVERAGE_SOURCE_FILE)" ]; then \
		if [ -z "$(COVERAGE_TEST_FILE)" ] || [ -z "$(COVERAGE_SOURCE_FILE)" ]; then \
			echo "Usage: make coverage [<test_file> <covered_file>]"; \
			echo "Or: make coverage COVERAGE_TEST_FILE=<test_file> COVERAGE_SOURCE_FILE=<covered_file>"; \
			exit 1; \
		fi; \
		$(VENV_BIN)/pytest -o addopts="-n $(COVERAGE_WORKERS)" "$(COVERAGE_TEST_FILE)" --cov=src/daktela_paleo --cov-report=; \
		$(VENV_BIN)/coverage report -m --include="$(COVERAGE_SOURCE_FILE)"; \
	else \
		$(VENV_BIN)/pytest -o addopts="-n $(COVERAGE_WORKERS)" --cov=src/daktela_paleo --cov-report=xml:coverage.xml --cov-report=html; \
		$(VENV_BIN)/coverage report -m; \
	fi

coverage-ci: COVERAGE_WORKERS=8
coverage-ci: coverage

cover: coverage

compute-req-tag:
	@echo "REQ_TAG=$(REQ_TAG)" > req.env
	@echo "Wrote req.env (REQ_TAG=$(REQ_TAG))"

ci-build-requirements:
	@set -e; \
	echo "Requirements image: $(REQ_IMG)"; \
	echo "Branch: $(CI_COMMIT_BRANCH)"; \
	if docker manifest inspect "$(REQ_IMG)" >/dev/null 2>&1; then \
		echo "Image already exists in registry - skipping build"; \
	else \
		echo "Image missing -> building & pushing..."; \
		docker build . -f containers/requirements.Dockerfile -t "$(REQ_IMG)"; \
		docker push "$(REQ_IMG)"; \
	fi
