# ATCR Makefile
# Build targets for the ATProto Container Registry

.PHONY: all build build-appview build-hold build-credential-helper build-oauth-helper \
	build-trixie \
	generate test test-race test-verbose lint lex-lint clean help install-credential-helper \
	develop develop-detached develop-down dev \
	docker docker-appview docker-hold docker-scanner

.DEFAULT_GOAL := help

help: ## Show this help message
	@echo "ATCR Build Targets:"
	@echo ""
	@awk 'BEGIN {FS = ":.*##"; printf ""} /^[a-zA-Z_-]+:.*?##/ { printf "  \033[36m%-28s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

all: generate build ## Generate assets and build all binaries (default)

# Generated asset files
GENERATED_ASSETS = \
	pkg/appview/public/js/htmx.min.js \
	pkg/appview/public/js/lucide.min.js \
	pkg/appview/licenses/spdx-licenses.json

generate: $(GENERATED_ASSETS) ## Run go generate to download vendor assets

$(GENERATED_ASSETS):
	@echo "→ Generating vendor assets and code..."
	go generate ./...

##@ Build Targets

build: build-appview build-hold build-credential-helper ## Build all binaries

# Legal page "Last updated" dates come from the git commit date of the page
# templates. Empty values (e.g., Docker builds without .git) fall back to the
# hardcoded default in legal.go.
LEGAL_PKG := atcr.io/pkg/appview/handlers
PRIVACY_DATE := $(shell git log -1 --format=%cs -- pkg/appview/templates/pages/privacy.html 2>/dev/null)
TERMS_DATE   := $(shell git log -1 --format=%cs -- pkg/appview/templates/pages/terms.html 2>/dev/null)
APPVIEW_LDFLAGS := -X '$(LEGAL_PKG).privacyLastUpdated=$(PRIVACY_DATE)' -X '$(LEGAL_PKG).termsLastUpdated=$(TERMS_DATE)'

build-appview: $(GENERATED_ASSETS) ## Build appview binary only
	@echo "→ Building appview..."
	@mkdir -p bin
	go build -ldflags="$(APPVIEW_LDFLAGS)" -o bin/atcr-appview ./cmd/appview

build-hold: $(GENERATED_ASSETS) ## Build hold binary only
	@echo "→ Building hold..."
	@mkdir -p bin
	go build -o bin/atcr-hold ./cmd/hold

build-credential-helper: ## Build credential helper only
	@echo "→ Building credential helper..."
	@mkdir -p bin
	go build -o bin/docker-credential-atcr ./cmd/credential-helper

build-oauth-helper: ## Build OAuth helper only
	@echo "→ Building OAuth helper..."
	@mkdir -p bin
	go build -o bin/oauth-helper ./cmd/oauth-helper

# Trixie cross-build (Debian 13, glibc 2.41) — produces binaries that run on
# any glibc ≥ 2.41 target, even when the host glibc is newer (e.g. Fedora's
# 2.43, which otherwise stamps sqrtf@GLIBC_2.43 onto cgo-linked output).
TRIXIE_BUILDER_IMAGE ?= golang:1-trixie

build-trixie: $(GENERATED_ASSETS) ## Build all production binaries (appview, hold, credential-helper, scanner, labeler) for linux/amd64 in a Debian 13 (glibc 2.41) container
	@echo "→ Building in $(TRIXIE_BUILDER_IMAGE) for glibc 2.41 compatibility..."
	@mkdir -p bin
	docker run --rm \
		--user $$(id -u):$$(id -g) \
		-v "$(CURDIR)":/src \
		-w /src \
		-e HOME=/tmp \
		-e GOCACHE=/tmp/.gocache \
		-e GOMODCACHE=/tmp/.gomodcache \
		-e CGO_ENABLED=1 \
		-e GOOS=linux \
		-e GOARCH=amd64 \
		$(TRIXIE_BUILDER_IMAGE) \
		bash -c '\
			set -e && \
			go build -trimpath -ldflags="-s -w $(APPVIEW_LDFLAGS)" -o bin/atcr-appview ./cmd/appview && \
			go build -trimpath -ldflags="-s -w" -o bin/atcr-hold ./cmd/hold && \
			go build -trimpath -ldflags="-s -w" -o bin/docker-credential-atcr ./cmd/credential-helper && \
			go build -trimpath -ldflags="-s -w" -o bin/atcr-labeler ./cmd/labeler && \
			cd scanner && go build -trimpath -ldflags="-s -w" -o ../bin/atcr-scanner ./cmd/scanner'
	@echo "✓ Built to bin/ (glibc ≥ 2.41 compatible)"

##@ Test Targets

test: ## Run all tests
	@echo "→ Running tests..."
	go test -cover ./...

test-race: ## Run tests with race detector
	@echo "→ Running tests with race detector..."
	go test -race ./...

test-verbose: ## Run tests with verbose output
	@echo "→ Running tests with verbose output..."
	go test -v ./...

integration-test: ## Run in-process smoke test (no docker, fake PDS + gofakes3 + hold + appview)
	@echo "→ Running integration smoke test..."
	go test -tags=integration -count=1 -race -timeout=120s ./test/integration/...

##@ Quality Targets

.PHONY: check-golangci-lint
check-golangci-lint:
	@LINT_PKG=github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest; \
	CUR_GO=$$(go version | grep -oE 'go[0-9]+\.[0-9]+' | head -1 | sed 's/^go//'); \
	if ! command -v golangci-lint > /dev/null 2>&1; then \
		echo "→ Installing golangci-lint..."; \
		go install $$LINT_PKG; \
	else \
		LINT_GO=$$(golangci-lint --version 2>&1 | grep -oE 'built with go[0-9]+\.[0-9]+' | head -1 | sed 's/^built with go//'); \
		if [ -n "$$LINT_GO" ] && [ "$$LINT_GO" != "$$CUR_GO" ] && \
		   [ "$$(printf '%s\n%s\n' $$LINT_GO $$CUR_GO | sort -V | head -1)" = "$$LINT_GO" ]; then \
			echo "→ golangci-lint built with go$$LINT_GO but project targets go$$CUR_GO — reinstalling..."; \
			go install $$LINT_PKG; \
		fi; \
	fi

lint: check-golangci-lint ## Run golangci-lint
	@echo "→ Running golangci-lint..."
	golangci-lint run ./...

lex-lint: ## Lint ATProto lexicon schemas
	goat lex lint ./lexicons/

##@ Install Targets

install-credential-helper: build-credential-helper ## Install credential helper to /usr/local/sbin
	@echo "→ Installing credential helper to /usr/local/sbin..."
	install -m 755 bin/docker-credential-atcr /usr/local/sbin/docker-credential-atcr
	@echo "✓ Installed docker-credential-atcr to /usr/local/sbin/"

##@ Development Targets

dev: $(GENERATED_ASSETS) ## Run AppView locally with Air hot reload
	@which air > /dev/null || (echo "→ Installing Air..." && go install github.com/air-verse/air@latest)
	air -c .air.toml

##@ Docker Targets

docker: docker-appview docker-hold docker-scanner ## Build all Docker images

docker-appview: ## Build appview Docker image
	@echo "→ Building appview Docker image..."
	docker build -f Dockerfile.appview \
		--build-arg PRIVACY_DATE=$(PRIVACY_DATE) \
		--build-arg TERMS_DATE=$(TERMS_DATE) \
		-t atcr.io/atcr.io/appview:latest .

docker-hold: ## Build hold Docker image
	@echo "→ Building hold Docker image..."
	docker build -f Dockerfile.hold -t atcr.io/atcr.io/hold:latest .

docker-scanner: ## Build scanner Docker image
	@echo "→ Building scanner Docker image..."
	docker build -f Dockerfile.scanner -t atcr.io/atcr.io/scanner:latest .

develop: ## Build and start docker-compose with Air hot reload
	@echo "→ Building Docker images..."
	docker-compose build
	@echo "→ Starting docker-compose with hot reload..."
	docker-compose up

develop-detached: ## Build and start docker-compose with hot reload (detached)
	@echo "→ Building Docker images..."
	docker-compose build
	@echo "→ Starting docker-compose with hot reload (detached)..."
	docker-compose up -d
	@echo "✓ Services started in background with hot reload"
	@echo "  AppView: http://localhost:5000"
	@echo "  Hold:    http://localhost:8080"

develop-down: ## Stop docker-compose services
	@echo "→ Stopping docker-compose..."
	docker-compose down

##@ Utility Targets

clean: ## Remove built binaries and generated assets
	@echo "→ Cleaning build artifacts..."
	rm -rf bin/
	rm -f pkg/appview/licenses/spdx-licenses.json
	@echo "✓ Clean complete"
