SHELL := /bin/bash
.DEFAULT_GOAL := build

KVPROTO_LOCK ?= third_party/kvproto.lock
KVPROTO_DIR ?= $(abspath .kvproto)
KVPROTO_REPO ?=
KVPROTO_COMMIT ?=
IMAGE_REPO ?= hub-new.pingcap.net/kvaas/pd-rs
PD_REAL_ETCD_ENDPOINTS ?= http://127.0.0.1:2379
PD_GO_TSO_ENDPOINT ?= http://127.0.0.1:2479
PD_GO_TSO_ENDPOINT_N_MINUS_1 ?=
PD_GO_TSO_ENDPOINT_N_MINUS_2 ?=
PD_ALLOW_MISSING_GO_TSO_ENDPOINT ?= 1
PD_TSO_STORE ?= in-memory
PD_TSO_ADMIN_AUTH_ENABLED ?= 0
PD_TSO_ADMIN_REQUIRE_MTLS_IDENTITY ?= 0

HOST_OS := $(shell uname -s)
HOST_ARCH := $(shell uname -m)
PD_TSO_GIT_HASH ?= $(shell git rev-parse --short=12 HEAD 2>/dev/null || echo None)
PD_TSO_GIT_REF ?= $(shell git symbolic-ref --short -q HEAD 2>/dev/null || git describe --tags --exact-match 2>/dev/null || git rev-parse --abbrev-ref HEAD 2>/dev/null || echo None)
# Use the commit timestamp from Git (not local wall-clock time) so the same
# revision always reports the same build metadata across machines/CI jobs.
PD_TSO_BUILD_TIME ?= $(shell TZ=UTC git show -s --date=format-local:%Y-%m-%dT%H:%M:%SZ --format=%cd HEAD 2>/dev/null || echo None)

ifeq ($(HOST_ARCH),x86_64)
IMAGE_TAG ?= latest-amd64
else ifeq ($(HOST_ARCH),amd64)
IMAGE_TAG ?= latest-amd64
else ifeq ($(HOST_ARCH),aarch64)
IMAGE_TAG ?= latest-arm64
else ifeq ($(HOST_ARCH),arm64)
IMAGE_TAG ?= latest-arm64
else
$(error Unsupported architecture: $(HOST_ARCH))
endif

KVPROTO_FETCH_ARGS :=
ifneq ($(strip $(KVPROTO_REPO)),)
KVPROTO_FETCH_ARGS += --repo $(KVPROTO_REPO)
endif
ifneq ($(strip $(KVPROTO_COMMIT)),)
KVPROTO_FETCH_ARGS += --commit $(KVPROTO_COMMIT)
endif

NEXTEST ?= cargo nextest
NEXTEST_INSTALL ?= cargo install cargo-nextest --locked
INTEGRATION_TEST_PACKAGE_MANIFESTS := $(sort $(wildcard testing/*/Cargo.toml))
INTEGRATION_TEST_PACKAGES := $(patsubst testing/%/Cargo.toml,%,$(INTEGRATION_TEST_PACKAGE_MANIFESTS))
INTEGRATION_TEST_NEXTEST_ARGS := $(foreach pkg,$(INTEGRATION_TEST_PACKAGES),-p $(pkg))
WORKSPACE_UNIT_TEST_EXCLUDES := $(foreach pkg,$(INTEGRATION_TEST_PACKAGES),--exclude $(pkg))

.PHONY: kvproto build build-debug fmt clippy install-nextest unit-test check image clean integration-test

kvproto:
	./scripts/fetch-kvproto.sh --lock-file $(KVPROTO_LOCK) --dest $(KVPROTO_DIR) $(KVPROTO_FETCH_ARGS)

build: kvproto
	KVPROTO_ROOT=$(KVPROTO_DIR) \
	PD_TSO_GIT_HASH="$(PD_TSO_GIT_HASH)" \
	PD_TSO_GIT_REF="$(PD_TSO_GIT_REF)" \
	PD_TSO_BUILD_TIME="$(PD_TSO_BUILD_TIME)" \
	cargo build --locked --release -p pd-tso

build-debug: kvproto
	KVPROTO_ROOT=$(KVPROTO_DIR) \
	PD_TSO_GIT_HASH="$(PD_TSO_GIT_HASH)" \
	PD_TSO_GIT_REF="$(PD_TSO_GIT_REF)" \
	PD_TSO_BUILD_TIME="$(PD_TSO_BUILD_TIME)" \
	cargo build --locked -p pd-tso

fmt:
	cargo fmt --all --check

clippy: kvproto
	KVPROTO_ROOT=$(KVPROTO_DIR) cargo clippy --locked --workspace --all-targets -- -D warnings

install-nextest:
	@if $(NEXTEST) --version >/dev/null 2>&1; then \
		echo "cargo-nextest already installed"; \
	else \
		$(NEXTEST_INSTALL); \
	fi

unit-test: install-nextest kvproto
	KVPROTO_ROOT=$(KVPROTO_DIR) $(NEXTEST) run --locked --workspace $(WORKSPACE_UNIT_TEST_EXCLUDES)

check: fmt clippy

image:
	@if [ "$(HOST_OS)" = "Darwin" ]; then \
		echo "Error: darwin is not supported for image build/push"; \
		exit 1; \
	fi
	DOCKER_BUILDKIT=1 docker build \
		--build-arg PD_TSO_GIT_HASH="$(PD_TSO_GIT_HASH)" \
		--build-arg PD_TSO_GIT_REF="$(PD_TSO_GIT_REF)" \
		--build-arg PD_TSO_BUILD_TIME="$(PD_TSO_BUILD_TIME)" \
		-t $(IMAGE_REPO):$(IMAGE_TAG) .
	docker push $(IMAGE_REPO):$(IMAGE_TAG)

# Use the `integration-tests` skill to run `make integration-test`.
# Example prompt:
#   "Run integration tests. PD located at ~/workspace/pd-cse"
# The skill handles `PD` discovery/build, temp dir cleanup, PD + TSO
# startup, port checks, and repeat/stability runs before it invokes this target.
integration-test: kvproto
	KVPROTO_ROOT=$(KVPROTO_DIR) \
	PD_REAL_ETCD_ENDPOINTS="$(PD_REAL_ETCD_ENDPOINTS)" \
	PD_GO_TSO_ENDPOINT="$(PD_GO_TSO_ENDPOINT)" \
	PD_GO_TSO_ENDPOINT_N_MINUS_1="$(PD_GO_TSO_ENDPOINT_N_MINUS_1)" \
	PD_GO_TSO_ENDPOINT_N_MINUS_2="$(PD_GO_TSO_ENDPOINT_N_MINUS_2)" \
	PD_ALLOW_MISSING_GO_TSO_ENDPOINT="$(PD_ALLOW_MISSING_GO_TSO_ENDPOINT)" \
	PD_TSO_STORE="$(PD_TSO_STORE)" \
	PD_TSO_ADMIN_AUTH_ENABLED="$(PD_TSO_ADMIN_AUTH_ENABLED)" \
	PD_TSO_ADMIN_REQUIRE_MTLS_IDENTITY="$(PD_TSO_ADMIN_REQUIRE_MTLS_IDENTITY)" \
	$(NEXTEST) run --locked $(INTEGRATION_TEST_NEXTEST_ARGS)

clean:
	cargo clean
