# Makefile for iap_messenger — local development & test packaging.
#
# Common workflow:
#   make venv        # create .venv with all build + runtime deps
#   make develop     # editable install (rebuilds the Rust extension in place)
#   make wheel       # build a release abi3 wheel into dist/
#   make sdist       # build a source distribution into dist/
#   make package     # wheel + sdist
#   make test        # run cargo tests + pytest against the installed wheel
#   make clean       # remove dist/, target/, build/, *.egg-info, __pycache__

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------

PYTHON     ?= python3
VENV       ?= .venv
VENV_BIN   := $(VENV)/bin
PIP        := $(VENV_BIN)/pip
MATURIN    := $(VENV_BIN)/maturin
PYTEST     := $(VENV_BIN)/pytest
PY         := $(VENV_BIN)/python

# `maturin develop` and `maturin build` need to know which interpreter
# to target.  We always use the venv's Python so the abi3 wheel matches.
export VIRTUAL_ENV := $(abspath $(VENV))

# Version pinned into Cargo.toml when building.  Defaults to 0.0.0 for
# local test builds; CI overrides via `make wheel BUILD_VERSION=1.2.3`.
BUILD_VERSION ?= 0.0.0

# Manylinux compatibility target for release wheels.  "manylinux2014"
# (glibc 2.17) is the broadest practical baseline and works in all common
# Docker base images (Debian bullseye+, Ubuntu 20.04+, Alpine via glibc-compat).
# Override with e.g. `make wheel MANYLINUX=manylinux_2_28`.
MANYLINUX ?= manylinux2014

# Docker image used by `make wheel-manylinux` to cross-build a portable wheel
# without needing an old glibc on the host.
MATURIN_IMAGE ?= ghcr.io/pyo3/maturin:latest

# ---------------------------------------------------------------------------
# Phony targets
# ---------------------------------------------------------------------------

.PHONY: help venv develop wheel wheel-manylinux sdist package test cargo-test pytest \
        clean clean-dist clean-target distclean version-pin version-reset

help:
	@echo "Targets:"
	@echo "  venv             Create $(VENV) with build + runtime deps"
	@echo "  develop          Editable install (fast iteration)"
	@echo "  wheel            Build host-native abi3 wheel into dist/"
	@echo "  wheel-manylinux  Build portable $(MANYLINUX) wheel via Docker (recommended for release)"
	@echo "  sdist            Build source distribution into dist/"
	@echo "  package          wheel-manylinux + sdist"
	@echo "  test             cargo tests + pytest against the installed wheel"
	@echo "  cargo-test       Rust unit tests only"
	@echo "  pytest           Python tests only (requires installed wheel)"
	@echo "  clean            Remove build artefacts"
	@echo "  distclean        clean + remove .venv"
	@echo ""
	@echo "Variables: PYTHON=$(PYTHON)  VENV=$(VENV)  BUILD_VERSION=$(BUILD_VERSION)  MANYLINUX=$(MANYLINUX)"

# ---------------------------------------------------------------------------
# Virtualenv
# ---------------------------------------------------------------------------

$(VENV)/bin/python:
	$(PYTHON) -m venv $(VENV)
	$(PIP) install --upgrade pip
	$(PIP) install "maturin>=1.7,<2.0" pytest
	$(PIP) install \
	    "nats-py~=2.12.0" "pillow~=10.4.0" "pyyaml~=6.0.2" "yamlcore~=0.0.4" \
	    "asyncio~=3.4.3" "json-tricks~=3.17.3" "msgpack~=1.1.0" \
	    "msgpack-numpy~=0.4.8" "urllib3~=2.5.0" "lz4~=4.4.4" "pyzmq~=26.4.0"

venv: $(VENV)/bin/python

# ---------------------------------------------------------------------------
# Version pinning helpers
# ---------------------------------------------------------------------------
#
# `maturin` reads the wheel version from Cargo.toml.  For local test builds
# we leave Cargo.toml alone (BUILD_VERSION=0.0.0 by default).  For tagged
# builds, override with: `make wheel BUILD_VERSION=1.2.3`.

version-pin:
	@if [ "$(BUILD_VERSION)" != "0.0.0" ]; then \
	    echo ">>> Pinning Cargo.toml version to $(BUILD_VERSION)"; \
	    cp Cargo.toml Cargo.toml.bak; \
	    sed -i.tmp -E 's/^version = "[^"]+"/version = "$(BUILD_VERSION)"/' Cargo.toml; \
	    rm -f Cargo.toml.tmp; \
	fi

version-reset:
	@if [ -f Cargo.toml.bak ]; then \
	    echo ">>> Restoring Cargo.toml"; \
	    mv Cargo.toml.bak Cargo.toml; \
	fi

# ---------------------------------------------------------------------------
# Build targets
# ---------------------------------------------------------------------------

develop: venv
	$(MATURIN) develop --release

wheel: venv version-pin
	-$(MATURIN) build --release --strip --out dist/ --interpreter $(PY) \
	    --compatibility $(MANYLINUX)
	@$(MAKE) version-reset
	@ls -la dist/

# Portable build: runs inside the official maturin manylinux2014 container
# so the wheel is linked against glibc 2.17 and installs everywhere.
# Docker must be available on the host.  The container's ENTRYPOINT is
# `maturin`, so we override it to bash for the build script.
wheel-manylinux: version-pin
	@mkdir -p dist
	docker run --rm \
	    -v "$(CURDIR):/io" \
	    -w /io \
	    --entrypoint bash \
	    $(MATURIN_IMAGE) \
	    -c "maturin build --release --strip --out dist/ --interpreter python3.10 --compatibility $(MANYLINUX) && maturin sdist --out dist/"
	@$(MAKE) version-reset
	@ls -la dist/

sdist: venv version-pin
	-$(MATURIN) sdist --out dist/
	@$(MAKE) version-reset
	@ls -la dist/

package: wheel-manylinux

# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------

cargo-test:
	cargo test --lib

pytest: develop
	$(PYTEST) tests/test_uid_extraction.py -v

test: cargo-test pytest

# ---------------------------------------------------------------------------
# Cleanup
# ---------------------------------------------------------------------------

clean: clean-dist
	rm -rf build/ src/*.egg-info src/iap_messenger/__pycache__ \
	       tests/__pycache__ .pytest_cache

clean-dist:
	rm -rf dist/ target/wheels/

clean-target:
	cargo clean

distclean: clean clean-target
	rm -rf $(VENV)
