SHELL := /bin/sh

ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
PARENT_ROOT := $(abspath $(ROOT)/..)
WORKSPACE_IS_EMBEDDED := $(shell if [ -d "$(PARENT_ROOT)/charts" ] && [ -d "$(PARENT_ROOT)/internal/dev" ]; then printf 'true'; else printf 'false'; fi)
WORKSPACE_RUNTIME_NAME ?= $(shell if [ "$(WORKSPACE_IS_EMBEDDED)" = true ]; then basename "$(PARENT_ROOT)"; else basename "$(ROOT)"; fi)
WORKSPACE_IS_GREENFIELD := $(if $(filter %-greenfield,$(WORKSPACE_RUNTIME_NAME)),true,false)
WORKSPACE_PORT_BASE ?= $(shell if [ "$(WORKSPACE_IS_EMBEDDED)" = true ]; then if [ "$(WORKSPACE_IS_GREENFIELD)" = true ]; then printf '6200'; else printf '6100'; fi; else printf '6000'; fi)
BUILDX_CONFIG ?= $(ROOT)/.run/buildx
COMPOSE_PROJECT_NAME ?= $(WORKSPACE_RUNTIME_NAME)-openinference

ifeq ($(shell uname -s),Darwin)
COLIMA_HOME ?= $(HOME)/.config/colima
COLIMA_PROFILE ?= $(WORKSPACE_RUNTIME_NAME)
DOCKER_HOST ?= unix://$(COLIMA_HOME)/$(COLIMA_PROFILE)/docker.sock
export COLIMA_HOME COLIMA_PROFILE DOCKER_HOST
endif

export BUILDX_CONFIG COMPOSE_PROJECT_NAME

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 ?= $(shell expr $(WORKSPACE_PORT_BASE) + 7)

PHOENIX_CONTAINER ?= $(WORKSPACE_RUNTIME_NAME)-codex-phoenix
PHOENIX_IMAGE ?= arizephoenix/phoenix:version-15.6.0
PHOENIX_PORT ?= $(shell expr $(WORKSPACE_PORT_BASE) + 6)
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 ?= $(WORKSPACE_RUNTIME_NAME)-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

PACKAGE_INDEX_URL ?= $(or $(UV_DEFAULT_INDEX),$(PIP_INDEX_URL),https://pypi.org/simple)
UV_HTTP_RETRIES ?= 6
UV_CONCURRENT_DOWNLOADS ?= 4
UV_CI_SYNC_ATTEMPTS ?= 6
UV_CI_SYNC_RETRY_DELAY ?= 5
INTERCEPTOR_IMAGE_REPOSITORY ?= $(if $(and $(filter true,$(WORKSPACE_IS_EMBEDDED)),$(filter-out true,$(WORKSPACE_IS_GREENFIELD))),openinference-codex-otlp-interceptor,$(WORKSPACE_RUNTIME_NAME)-openinference-codex-otlp-interceptor)
INTERCEPTOR_IMAGE_TAG ?= local
INTERCEPTOR_IMAGE_REF := $(INTERCEPTOR_IMAGE_REPOSITORY):$(INTERCEPTOR_IMAGE_TAG)

.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 --frozen --extra test

setup-ci:
	@attempt=1; \
	while ! UV_HTTP_RETRIES="$(UV_HTTP_RETRIES)" UV_CONCURRENT_DOWNLOADS="$(UV_CONCURRENT_DOWNLOADS)" uv sync --frozen --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 --frozen ruff check .

test:
	uv run --frozen python -m pytest

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

test-quality: test-unit

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

test-native-otlp-capture:
	uv run --frozen 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; }
	bash scripts/capture_native_otlp.sh \
		--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 --frozen 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
	bash scripts/check_public_artifacts.sh dist
	@wheel="$$(find dist -maxdepth 1 -name '*.whl' -print -quit)"; \
		test -n "$$wheel"; \
		uv run --isolated --no-project --python 3.10 --with "$$wheel" \
			python -c 'from openinference.instrumentation.codex.jsonl_forwarder import _toml_parser; assert _toml_parser().__name__ == "tomli"'

docker-build-interceptor:
	docker build --build-arg PIP_INDEX_URL="$(PACKAGE_INDEX_URL)" -f Dockerfile.interceptor -t "$(INTERCEPTOR_IMAGE_REF)" .

docker-smoke-interceptor: docker-build-interceptor
	bash scripts/smoke_interceptor_container.sh --image "$(INTERCEPTOR_IMAGE_REF)"

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:
	@bash scripts/jsonl_forwarder.sh start \
		--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:
	@bash scripts/jsonl_forwarder.sh stop --state-path "$(JSONL_STATE)" --pid-path "$(JSONL_PID)"

jsonl-forwarder-status:
	@bash scripts/jsonl_forwarder.sh status --state-path "$(JSONL_STATE)" --pid-path "$(JSONL_PID)"

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
