SHELL := /bin/sh

DOCKER_COMPOSE ?= $(shell \
	if docker compose version >/dev/null 2>&1; then \
		printf 'docker compose'; \
	elif command -v docker-compose >/dev/null 2>&1; then \
		command -v docker-compose; \
	else \
		printf 'docker compose'; \
	fi)

COMPOSE_PHOENIX_PORT ?= 6007

PHOENIX_CONTAINER ?= codex-phoenix
PHOENIX_IMAGE ?= arizephoenix/phoenix:version-15.6.0
PHOENIX_PORT ?= 6006
PHOENIX_URL ?= http://localhost:$(PHOENIX_PORT)
PHOENIX_BASE_URL ?= $(PHOENIX_URL)
PHOENIX_COLLECTOR_ENDPOINT ?= $(PHOENIX_BASE_URL)/v1/traces
PHOENIX_OTLP_ENDPOINT ?= $(PHOENIX_URL)/v1/traces

RUN_DIR ?= .run
NATIVE_OTLP_CAPTURE_DIR ?= $(RUN_DIR)/native-otlp-capture
NATIVE_OTLP_CAPTURE_IMAGE ?=
NATIVE_OTLP_CAPTURE_AUTH_SOURCE ?= $(HOME)/.codex
NATIVE_OTLP_CAPTURE_PROMPT ?= reply with a short deterministic sentence
JSONL_CODEX_HOME ?= $(HOME)/.codex
JSONL_PROJECT ?= codex-local-jsonl-forwarder
JSONL_STATE ?= $(RUN_DIR)/codex-jsonl-forwarder-state.json
JSONL_LOG ?= $(RUN_DIR)/codex-jsonl-forwarder.log
JSONL_PID ?= $(RUN_DIR)/codex-jsonl-forwarder.pid
JSONL_POLL_INTERVAL ?= 1
JSONL_BACKFILL_ACTIVE_GRACE ?= 300
JSONL_TURN_IDLE_TIMEOUT ?= 30
JSONL_FORWARDER_FRESH ?= 0

UV_DEFAULT_INDEX := https://pypi.org/simple
export UV_DEFAULT_INDEX
UV_HTTP_RETRIES ?= 6
UV_CONCURRENT_DOWNLOADS ?= 4
UV_CI_SYNC_ATTEMPTS ?= 6
UV_CI_SYNC_RETRY_DELAY ?= 5

.PHONY: setup setup-ci lint test test-quality test-unit test-integration test-jsonl-forwarder-phoenix test-native-otlp-capture capture-native-otlp-docker test-e2e \
	compose-e2e compose-logs compose-down build flight-check wait-phoenix \
	docker-build-interceptor docker-smoke-interceptor phoenix-start phoenix-stop phoenix-jsonl-start phoenix-jsonl-stop phoenix-jsonl-status \
	jsonl-forwarder-start jsonl-forwarder-stop jsonl-forwarder-status

setup:
	uv sync --extra test

setup-ci:
	@attempt=1; \
	while ! UV_HTTP_RETRIES="$(UV_HTTP_RETRIES)" UV_CONCURRENT_DOWNLOADS="$(UV_CONCURRENT_DOWNLOADS)" uv sync --extra test; do \
		if [ "$$attempt" -ge "$(UV_CI_SYNC_ATTEMPTS)" ]; then \
			exit 1; \
		fi; \
		attempt=$$((attempt + 1)); \
		printf 'uv sync failed; retrying CI setup (%s/%s)\n' "$$attempt" "$(UV_CI_SYNC_ATTEMPTS)"; \
		sleep "$(UV_CI_SYNC_RETRY_DELAY)"; \
	done

lint:
	uv run ruff check .

test:
	uv run python -m pytest

test-unit:
	uv run python -m pytest -m "not integration and not e2e"

test-quality: test-unit

test-integration:
	uv run python -m pytest -m integration

test-native-otlp-capture:
	uv run python -m pytest tests/test_native_otlp_capture.py tests/test_native_otlp_interceptor.py tests/test_native_otlp_feasibility.py

capture-native-otlp-docker:
	@test -n "$(NATIVE_OTLP_CAPTURE_IMAGE)" || { echo "set NATIVE_OTLP_CAPTURE_IMAGE to the container image to exercise" >&2; exit 2; }
	uv run python scripts/capture_native_otlp.py \
		--output-dir "$(NATIVE_OTLP_CAPTURE_DIR)" \
		--timeout-seconds 120 \
		--allow-nonzero \
		--post-command-wait-seconds 3 \
		--auth-source-codex-home "$(NATIVE_OTLP_CAPTURE_AUTH_SOURCE)" \
		--codex-container-image "$(NATIVE_OTLP_CAPTURE_IMAGE)" \
		-- codex exec --skip-git-repo-check "$(NATIVE_OTLP_CAPTURE_PROMPT)"

wait-phoenix:
	@for attempt in $$(seq 1 60); do \
		if curl -fsS "$(PHOENIX_BASE_URL)" >/dev/null 2>&1; then \
			echo "Phoenix is ready at $(PHOENIX_BASE_URL)"; \
			exit 0; \
		fi; \
		sleep 2; \
	done; \
	echo "Phoenix did not become ready at $(PHOENIX_BASE_URL)" >&2; \
	exit 1

test-jsonl-forwarder-phoenix: wait-phoenix
	PHOENIX_BASE_URL="$(PHOENIX_BASE_URL)" \
	PHOENIX_COLLECTOR_ENDPOINT="$(PHOENIX_COLLECTOR_ENDPOINT)" \
	uv run python -m pytest tests/integration/test_jsonl_forwarder_phoenix_integration.py

test-e2e: compose-e2e

compose-e2e:
	@status=0; \
	COMPOSE_PHOENIX_PORT="$(COMPOSE_PHOENIX_PORT)" $(DOCKER_COMPOSE) -f docker-compose.phoenix.yml up --build --abort-on-container-exit --exit-code-from codex-live-smoke || status=$$?; \
	if [ $$status -ne 0 ]; then \
		COMPOSE_PHOENIX_PORT="$(COMPOSE_PHOENIX_PORT)" $(DOCKER_COMPOSE) -f docker-compose.phoenix.yml logs --no-color; \
	fi; \
	COMPOSE_PHOENIX_PORT="$(COMPOSE_PHOENIX_PORT)" $(DOCKER_COMPOSE) -f docker-compose.phoenix.yml down -v --remove-orphans; \
	exit $$status

compose-logs:
	COMPOSE_PHOENIX_PORT="$(COMPOSE_PHOENIX_PORT)" $(DOCKER_COMPOSE) -f docker-compose.phoenix.yml logs --no-color

compose-down:
	COMPOSE_PHOENIX_PORT="$(COMPOSE_PHOENIX_PORT)" $(DOCKER_COMPOSE) -f docker-compose.phoenix.yml down -v --remove-orphans

build:
	rm -rf dist
	uv build
	uv run python scripts/check_public_artifacts.py dist

docker-build-interceptor:
	docker build --build-arg PIP_INDEX_URL="$(UV_DEFAULT_INDEX)" -f Dockerfile.interceptor -t openinference-codex-otlp-interceptor:local .

docker-smoke-interceptor: docker-build-interceptor
	uv run python scripts/smoke_interceptor_container.py

flight-check: setup lint test-quality test build compose-e2e

phoenix-start:
	@docker rm -f "$(PHOENIX_CONTAINER)" >/dev/null 2>&1 || true
	@docker run -d --name "$(PHOENIX_CONTAINER)" -p "$(PHOENIX_PORT):6006" "$(PHOENIX_IMAGE)"
	@for attempt in $$(seq 1 60); do \
		if curl -fsS "$(PHOENIX_URL)" >/dev/null 2>&1; then \
			echo "Phoenix is ready at $(PHOENIX_URL)"; \
			exit 0; \
		fi; \
		sleep 1; \
	done; \
	echo "Phoenix did not become ready at $(PHOENIX_URL)" >&2; \
	exit 1

phoenix-stop:
	@docker rm -f "$(PHOENIX_CONTAINER)" >/dev/null 2>&1 || true
	@echo "Stopped Phoenix container $(PHOENIX_CONTAINER)"

jsonl-forwarder-start:
	@uv run python scripts/spawn_jsonl_forwarder.py \
		--codex-home "$(JSONL_CODEX_HOME)" \
		--state-path "$(JSONL_STATE)" \
		--log-path "$(JSONL_LOG)" \
		--pid-path "$(JSONL_PID)" \
		--project "$(JSONL_PROJECT)" \
		--otlp-endpoint "$(PHOENIX_OTLP_ENDPOINT)" \
		--poll-interval "$(JSONL_POLL_INTERVAL)" \
		--backfill-active-grace "$(JSONL_BACKFILL_ACTIVE_GRACE)" \
		--turn-idle-timeout "$(JSONL_TURN_IDLE_TIMEOUT)" \
		$$(if [ "$(JSONL_FORWARDER_FRESH)" = "1" ]; then printf '%s' "--fresh"; fi)

jsonl-forwarder-stop:
	@if [ -f "$(JSONL_PID)" ] && kill -0 "$$(cat "$(JSONL_PID)")" 2>/dev/null; then \
		kill "$$(cat "$(JSONL_PID)")"; \
		echo "Stopped codex-jsonl-forwarder pid $$(cat "$(JSONL_PID)")"; \
	else \
		echo "codex-jsonl-forwarder is not running from $(JSONL_PID)"; \
	fi
	@rm -f "$(JSONL_PID)"

jsonl-forwarder-status:
	@if [ -f "$(JSONL_PID)" ] && kill -0 "$$(cat "$(JSONL_PID)")" 2>/dev/null; then \
		echo "codex-jsonl-forwarder running with pid $$(cat "$(JSONL_PID)")"; \
	else \
		echo "codex-jsonl-forwarder is not running from $(JSONL_PID)"; \
		exit 1; \
	fi

phoenix-jsonl-start:
	@$(MAKE) jsonl-forwarder-stop
	@$(MAKE) phoenix-start
	@$(MAKE) jsonl-forwarder-start JSONL_FORWARDER_FRESH=1

phoenix-jsonl-stop:
	@$(MAKE) jsonl-forwarder-stop
	@$(MAKE) phoenix-stop

phoenix-jsonl-status:
	@curl -fsS "$(PHOENIX_URL)" >/dev/null
	@echo "Phoenix is reachable at $(PHOENIX_URL)"
	@$(MAKE) jsonl-forwarder-status
