APP_NAME={{WORKER_NAME}}
WORKTREE_ROOT ?=$(shell git rev-parse --show-toplevel 2>/dev/null || pwd)
WORKTREE_LABEL ?=$(shell basename "$(WORKTREE_ROOT)" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-//; s/-$$//')
WORKTREE_ID ?=$(shell printf '%s' "$(WORKTREE_ROOT)" | shasum | cut -c1-8)
WORKTREE_SLUG ?=$(APP_NAME)-$(WORKTREE_ID)
COMPOSE_PROJECT_NAME ?=$(WORKTREE_SLUG)
IMAGE ?=$(WORKTREE_SLUG)
TAG ?=dev
IMAGE_REF := $(IMAGE):$(TAG)
DEV_IMAGE ?=$(WORKTREE_SLUG)-dev
DEV_TAG ?=dev
DEV_IMAGE_REF := $(DEV_IMAGE):$(DEV_TAG)
COMPOSE ?=COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT_NAME) docker compose
DEV_COMPOSE_FILE ?=compose.dev.yaml
DEV_SERVICE ?=app-dev
GOPROXY ?=https://proxy.golang.org,direct
GOSUMDB ?=sum.golang.org
BUILDER_IMAGE ?=golang:1.26-alpine
RUNTIME_IMAGE ?=alpine:3.20
WORKER_RUN_MODE ?={{RUN_MODE}}
WORKER_TICK_INTERVAL_SECONDS ?={{TICK_INTERVAL_SECONDS}}
WORKER_SHUTDOWN_TIMEOUT_SECONDS ?={{SHUTDOWN_TIMEOUT_SECONDS}}
WORKER_RETRY_MAX_ATTEMPTS ?=3
WORKER_RETRY_INITIAL_BACKOFF_SECONDS ?=1
WORKER_RETRY_MAX_BACKOFF_SECONDS ?=30
GOCACHE ?= $(CURDIR)/.cache/go-build
GOMODCACHE ?= $(CURDIR)/.cache/go-mod
export COMPOSE_PROJECT_NAME
export DEV_IMAGE
export DEV_TAG
export WORKER_RUN_MODE
export WORKER_TICK_INTERVAL_SECONDS
export WORKER_SHUTDOWN_TIMEOUT_SECONDS
export WORKER_RETRY_MAX_ATTEMPTS
export WORKER_RETRY_INITIAL_BACKOFF_SECONDS
export WORKER_RETRY_MAX_BACKOFF_SECONDS
export GOCACHE
export GOMODCACHE

.PHONY: worktree-info worktree-doctor worktree-compose-config clean-worktree bootstrap doctor dev dev-shell lint test verify run build clean help docker-build docker-run

worktree-info:
	@printf '%s\n' "Worktree root: $(WORKTREE_ROOT)"
	@printf '%s\n' "Worktree label: $(WORKTREE_LABEL)"
	@printf '%s\n' "Worktree ID: $(WORKTREE_ID)"
	@printf '%s\n' "Worktree slug: $(WORKTREE_SLUG)"
	@printf '%s\n' "Compose project: $(COMPOSE_PROJECT_NAME)"
	@printf '%s\n' "Dev image ref: $(DEV_IMAGE_REF)"
	@printf '%s\n' "Runtime image ref: $(IMAGE_REF)"
	@printf '%s\n' "Go cache: $(GOCACHE)"
	@printf '%s\n' "Go module cache: $(GOMODCACHE)"
	@printf '%s\n' "Worker run mode: $(WORKER_RUN_MODE)"
	@printf '%s\n' "Worker retry attempts: $(WORKER_RETRY_MAX_ATTEMPTS)"

worktree-doctor:
	@$(MAKE) --no-print-directory worktree-info
	@case "$(GOCACHE)" in "$(WORKTREE_ROOT)"/*) ;; *) printf '%s\n' "GOCACHE should stay inside this worktree: $(GOCACHE)"; exit 1;; esac
	@case "$(GOMODCACHE)" in "$(WORKTREE_ROOT)"/*) ;; *) printf '%s\n' "GOMODCACHE should stay inside this worktree: $(GOMODCACHE)"; exit 1;; esac
	@printf '%s\n' "Worker has no published host ports by default."
	@printf '%s\n' "Compose config check: make worktree-compose-config"

worktree-compose-config:
	@if ! command -v docker >/dev/null 2>&1; then printf '%s\n' "Docker is not available; cannot render Compose config."; exit 1; fi
	$(COMPOSE) -f $(DEV_COMPOSE_FILE) config

clean-worktree:
	$(COMPOSE) -f $(DEV_COMPOSE_FILE) down --remove-orphans --volumes

bootstrap:
	GOPROXY=$(GOPROXY) GOSUMDB=$(GOSUMDB) $(COMPOSE) -f $(DEV_COMPOSE_FILE) build $(DEV_SERVICE)

doctor:
	$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) ./scripts/doctor

lint:
	$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) go vet ./...

dev:
	WORKER_RUN_MODE=$(WORKER_RUN_MODE) WORKER_TICK_INTERVAL_SECONDS=$(WORKER_TICK_INTERVAL_SECONDS) WORKER_SHUTDOWN_TIMEOUT_SECONDS=$(WORKER_SHUTDOWN_TIMEOUT_SECONDS) WORKER_RETRY_MAX_ATTEMPTS=$(WORKER_RETRY_MAX_ATTEMPTS) WORKER_RETRY_INITIAL_BACKOFF_SECONDS=$(WORKER_RETRY_INITIAL_BACKOFF_SECONDS) WORKER_RETRY_MAX_BACKOFF_SECONDS=$(WORKER_RETRY_MAX_BACKOFF_SECONDS) GOPROXY=$(GOPROXY) GOSUMDB=$(GOSUMDB) $(COMPOSE) -f $(DEV_COMPOSE_FILE) up $(DEV_SERVICE)

dev-shell:
	$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) sh

test:
	$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) go test ./...

verify: doctor lint test build

run:
	WORKER_RUN_MODE=$(WORKER_RUN_MODE) WORKER_TICK_INTERVAL_SECONDS=$(WORKER_TICK_INTERVAL_SECONDS) WORKER_SHUTDOWN_TIMEOUT_SECONDS=$(WORKER_SHUTDOWN_TIMEOUT_SECONDS) WORKER_RETRY_MAX_ATTEMPTS=$(WORKER_RETRY_MAX_ATTEMPTS) WORKER_RETRY_INITIAL_BACKOFF_SECONDS=$(WORKER_RETRY_INITIAL_BACKOFF_SECONDS) WORKER_RETRY_MAX_BACKOFF_SECONDS=$(WORKER_RETRY_MAX_BACKOFF_SECONDS) $(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE)

build:
	$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) go build -o bin/$(APP_NAME) ./cmd/worker

clean:
	$(COMPOSE) -f $(DEV_COMPOSE_FILE) down --remove-orphans

help:
	@printf '%s\n' "Common commands:" "  make bootstrap  Prepare the development environment" "  make doctor     Check required tools and project configuration" "  make lint       Run static analysis" "  make test       Run tests" "  make verify     Run the complete local verification contract" "  make build      Build the application" "  make clean      Remove generated runtime state" "  make help       Show this command summary"

docker-build:
	docker build --build-arg BUILDER_IMAGE=$(BUILDER_IMAGE) --build-arg RUNTIME_IMAGE=$(RUNTIME_IMAGE) --build-arg GOPROXY=$(GOPROXY) --build-arg GOSUMDB=$(GOSUMDB) -t $(IMAGE_REF) .

docker-run:
	docker run --rm -e WORKER_RUN_MODE=$(WORKER_RUN_MODE) -e WORKER_TICK_INTERVAL_SECONDS=$(WORKER_TICK_INTERVAL_SECONDS) -e WORKER_SHUTDOWN_TIMEOUT_SECONDS=$(WORKER_SHUTDOWN_TIMEOUT_SECONDS) -e WORKER_RETRY_MAX_ATTEMPTS=$(WORKER_RETRY_MAX_ATTEMPTS) -e WORKER_RETRY_INITIAL_BACKOFF_SECONDS=$(WORKER_RETRY_INITIAL_BACKOFF_SECONDS) -e WORKER_RETRY_MAX_BACKOFF_SECONDS=$(WORKER_RETRY_MAX_BACKOFF_SECONDS) $(IMAGE_REF)
