# Developer + CI entrypoints.
#
# These targets are the single source of truth for the checks. The Gitea
# Actions workflow (.gitea/workflows/ci.yaml) invokes the SAME targets, so
# `make ci` locally runs exactly what the pipeline runs — no drift. Until a
# self-hosted runner is registered, `make ci` is the gate (see docs/runbooks/ci.md).

SLN        := register-referentie.slnx
COMPOSE    := infra/docker-compose.yml
# Long-running services with a healthcheck — the smoke waits on these. One-shot
# init jobs (oz-init, nrc-init, flowable-init) are NOT listed: `--wait` fails when
# a one-shot with no `service_completed_successfully` dependant exits (flowable-init),
# so we wait on the durable services instead. See docs/runbooks/gitea-actions-gotchas.md.
WAIT_SVCS  := openzaak nrc-web acl bff
OZ_COMPOSE  := infra/openzaak/docker-compose.yml
OZ_BASE     := http://localhost:8000
NRC_COMPOSE := infra/opennotificaties/docker-compose.yml
NRC_BASE    := http://localhost:8001
KC_COMPOSE  := infra/keycloak/docker-compose.yml
KC_BASE     := http://localhost:8180
FL_COMPOSE  := infra/flowable/docker-compose.yml
FL_BASE     := http://localhost:8090/flowable-rest/service
STACK_FILES := -f $(OZ_COMPOSE) -f $(NRC_COMPOSE)

# On a rootless Podman dev box, point Docker CLI/Compose at the Podman socket —
# but only if that socket exists and DOCKER_HOST isn't already set, so real
# Docker hosts and CI runners are left untouched.
PODMAN_SOCK := /run/user/$(shell id -u)/podman/podman.sock
ifeq ($(wildcard $(PODMAN_SOCK)),$(PODMAN_SOCK))
ifeq ($(origin DOCKER_HOST),undefined)
export DOCKER_HOST := unix://$(PODMAN_SOCK)
endif
endif

.PHONY: ci lint build unit smoke down changelog openzaak-up openzaak-smoke openzaak-seed openzaak-down stack-up stack-smoke stack-down keycloak-up keycloak-smoke keycloak-down flowable-up flowable-smoke flowable-down help

## ci: run the full pipeline — lint, build, unit, smoke (mirrors Gitea Actions)
ci: lint build unit smoke

## lint: verify formatting (no changes)
lint:
	dotnet format $(SLN) --verify-no-changes

## build: release build
build:
	dotnet build $(SLN) -c Release

## unit: run unit tests
unit:
	dotnet test $(SLN) -c Release

## smoke: bring the whole stack up, wait for the health-checked services, tear down
# Step 1 starts EVERYTHING (incl. one-shot init jobs that deploy and exit 0).
# Step 2 waits only for the durable, health-checked services ($(WAIT_SVCS)) — see
# WAIT_SVCS above for why the one-shots are excluded. The healthchecks run inside
# the containers, so this needs no host port access (the CI runner can't reach
# published ports anyway).
smoke:
	docker compose -f $(COMPOSE) up -d --build
	bash -c 'docker compose -f $(COMPOSE) up -d --wait --wait-timeout 420 $(WAIT_SVCS); rc=$$?; docker compose -f $(COMPOSE) down --volumes; exit $$rc'

## down: stop and remove the local stack
down:
	docker compose -f $(COMPOSE) down --volumes

## changelog: regenerate CHANGELOG.md from Conventional Commits (git-cliff)
changelog:
	git-cliff --output CHANGELOG.md

## openzaak-up: start the OpenZaak stack (migrations run on first start)
openzaak-up:
	docker compose -f $(OZ_COMPOSE) up -d

## openzaak-smoke: start OpenZaak, then assert it is up with auth enforced
openzaak-smoke:
	docker compose -f $(OZ_COMPOSE) up -d
	@bash -c 'set -e; \
	  echo "waiting for OpenZaak to respond..."; \
	  for i in $$(seq 1 60); do \
	    code=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/zaken/api/v1/zaken || true); \
	    [ -n "$$code" ] && [ "$$code" != "000" ] && break; sleep 3; \
	  done; \
	  echo "GET /zaken/api/v1/zaken (unauth) -> $$code (expect 403, auth enforced)"; test "$$code" = "403"; \
	  admin=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/admin/); \
	  echo "GET /admin/             -> $$admin (expect 302)"; test "$$admin" = "302"; \
	  root=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/zaken/api/v1/); \
	  echo "GET /zaken/api/v1/      -> $$root (expect 200)"; test "$$root" = "200"; \
	  echo "OpenZaak smoke OK"'

## openzaak-seed: bring OpenZaak up and seed the BIG catalogus (idempotent)
openzaak-seed: openzaak-up
	@bash -c 'for i in $$(seq 1 50); do \
	    c=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/catalogi/api/v1/ || true); \
	    [ "$$c" = "200" ] && break; sleep 3; done; echo "OpenZaak ready ($$c)"'
	python3 infra/openzaak/seed_catalogus.py

## openzaak-down: stop and remove the OpenZaak stack (wipes data)
openzaak-down:
	docker compose -f $(OZ_COMPOSE) down --volumes

## stack-up: start OpenZaak + Open Notificaties together (shared network)
stack-up:
	docker compose $(STACK_FILES) up -d

## stack-smoke: start both, assert OpenZaak (403/302/200) and NRC (302) are reachable
stack-smoke: stack-up
	@bash -c 'set -e; \
	  echo "waiting for OpenZaak + Open Notificaties..."; \
	  for i in $$(seq 1 60); do \
	    oz=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/admin/ || true); \
	    nrc=$$(curl -s -o /dev/null -w "%{http_code}" $(NRC_BASE)/admin/ || true); \
	    [ "$$oz" = "302" ] && [ "$$nrc" = "302" ] && break; sleep 3; done; \
	  z=$$(curl -s -o /dev/null -w "%{http_code}" $(OZ_BASE)/zaken/api/v1/zaken); \
	  echo "OpenZaak /zaken (unauth) -> $$z (expect 403)"; test "$$z" = "403"; \
	  echo "OpenZaak /admin/         -> $$oz (expect 302)"; test "$$oz" = "302"; \
	  echo "Open Notificaties /admin/-> $$nrc (expect 302)"; test "$$nrc" = "302"; \
	  echo "stack smoke OK"'

## stack-down: stop and remove both stacks (wipes data)
stack-down:
	docker compose $(STACK_FILES) down --volumes

## keycloak-up: start Keycloak with the four imported realms
keycloak-up:
	docker compose -f $(KC_COMPOSE) up -d

## keycloak-smoke: start Keycloak, then verify each realm logs in + returns its claim
keycloak-smoke: keycloak-up
	@bash -c 'for i in $$(seq 1 60); do \
	    c=$$(curl -s -o /dev/null -w "%{http_code}" $(KC_BASE)/realms/digid/.well-known/openid-configuration || true); \
	    [ "$$c" = "200" ] && break; sleep 3; done; echo "Keycloak ready ($$c)"'
	python3 infra/keycloak/check_realms.py

## keycloak-down: stop and remove Keycloak
keycloak-down:
	docker compose -f $(KC_COMPOSE) down --volumes

## flowable-up: start Flowable (deploys registratie.bpmn on boot)
flowable-up:
	docker compose -f $(FL_COMPOSE) up -d

## flowable-smoke: start Flowable, then verify a started instance waits on the external task
flowable-smoke: flowable-up
	@bash -c 'for i in $$(seq 1 80); do \
	    c=$$(curl -s -o /dev/null -w "%{http_code}" -u rest-admin:test $(FL_BASE)/repository/process-definitions?key=registratie || true); \
	    [ "$$c" = "200" ] && break; sleep 3; done; echo "Flowable ready ($$c)"'
	python3 infra/flowable/verify.py

## flowable-down: stop and remove Flowable
flowable-down:
	docker compose -f $(FL_COMPOSE) down --volumes

## help: list available targets
help:
	@grep -E '^## ' $(MAKEFILE_LIST) | sed 's/^## //'
