# =============================================================================
# FetchML Build System - Streamlined
# =============================================================================

.PHONY: all build prod prod-with-native dev cross-platform build-cli \
        native-build native-release native-debug native-test native-smoke native-clean \
        clean clean-release prepare-release verify-build \
        test test-unit test-integration test-e2e test-coverage \
        test-infra-up test-infra-down \
        lint configlint worker-configlint ci-local ci-checks \
        verify-quick verify-all verify-schema test-schema-validation \
        lint-custom verify-audit verify-audit-chain install-tools \
        security-scan gosec govulncheck check-unsafe security-audit \
        openapi-generate openapi-generate-server openapi-validate \
        openapi-check-ci openapi-check-implementation \
        openapi-generate-clients \
        docs docs-setup docs-build docs-build-prod docs-generate docs-serve \
        benchmark benchmark-local benchmark-native benchmark-compare \
        load-test chaos-test profile-load profile-load-norate profile-ws-queue profile-tools detect-regressions detect-regressions-native \
        clean-benchmarks status size complete-suite \
        dev-up dev-down dev-logs dev-restart \
        staging-up staging-down staging-logs staging-restart staging-status \
        homelab-secure-up homelab-secure-down \
        prod-up prod-down prod-logs prod-restart prod-status \
        status-all clean-deploy rollback-staging rollback-prod deploy-health-check \
        install docker-build dev-smoke prod-smoke test-auth help

# -----------------------------------------------------------------------------
# Variables
# -----------------------------------------------------------------------------

OK := ✓
DOCS_PORT ?= 1313
DOCS_BIND ?= 127.0.0.1
DOCS_BASEURL ?= /
BUILD_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo dev)
BUILD_TIME := $(shell date -u +%Y%m%d.%H%M%S)
LDFLAGS := -X main.BuildHash=$(BUILD_HASH) -X main.BuildTime=$(BUILD_TIME)
LDFLAGS_PROD := -s -w
NPROC := $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
DC := docker compose
TEST_COMPOSE := deployments/docker-compose.test.yml

define test_summary
	@passed=$$(grep -c "^--- PASS:" $(1) 2>/dev/null || echo 0); \
	failed=$$(grep -c "^--- FAIL:" $(1) 2>/dev/null || echo 0); \
	skipped=$$(grep -c "^--- SKIP:" $(1) 2>/dev/null || echo 0); \
	echo "  Passed: $$passed  Failed: $$failed  Skipped: $$skipped"; \
	if [ "$$failed" -gt 0 ]; then exit 1; fi
endef

define ensure_tool
	@if ! command -v $(1) >/dev/null 2>&1; then \
		echo "Installing $(1)..."; \
		go install $(2); \
	fi
endef

# -----------------------------------------------------------------------------
# Build
# -----------------------------------------------------------------------------

all: build

build: native-build openapi-generate-server
	@mkdir -p bin/server bin/cli bin/native
	go build -ldflags="$(LDFLAGS)" -o bin/server/api-server ./cmd/api-server/main.go
	go build -ldflags="$(LDFLAGS)" -o bin/server/worker ./cmd/worker/worker_server.go
	go build -ldflags="$(LDFLAGS)" -o bin/server/data_manager ./cmd/data_manager
	go build -ldflags="$(LDFLAGS)" -o bin/server/user_manager ./cmd/user_manager
	go build -ldflags="$(LDFLAGS)" -o bin/server/tui ./cmd/tui
	@cp native/build/lib*.so native/build/lib*.dylib bin/native/ 2>/dev/null || true
	$(MAKE) -C ./cli all
	@cp cli/zig-out/bin/ml bin/cli/
	@echo "$(OK) All components built"

prod:
	@mkdir -p bin/server bin/cli
	go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/api-server cmd/api-server/main.go
	go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/worker cmd/worker/worker_server.go
	go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/data_manager ./cmd/data_manager
	go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/user_manager ./cmd/user_manager
	go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/tui ./cmd/tui
	$(MAKE) -C cli prod
	@cp cli/zig-out/bin/ml bin/cli/
	@echo "$(OK) Production binaries built"

dev:
	@mkdir -p bin/server bin/cli
	go build -buildvcs=false -o bin/server/api-server cmd/api-server/main.go
	go build -buildvcs=false -o bin/server/worker cmd/worker/worker_server.go
	go build -buildvcs=false -o bin/server/data_manager ./cmd/data_manager
	go build -buildvcs=false -o bin/server/user_manager ./cmd/user_manager
	go build -buildvcs=false -o bin/server/tui ./cmd/tui
	$(MAKE) -C cli dev
	@cp cli/zig-out/bin/ml bin/cli/
	@echo "$(OK) Development binaries built"

native-build:
	@mkdir -p native/build
	@cd native/build && cmake .. -DCMAKE_BUILD_TYPE=Release && make -j$(NPROC)
	@echo "$(OK) Native libraries built"

native-release:
	@mkdir -p native/build
	@cd native/build && cmake .. -DCMAKE_BUILD_TYPE=Release \
		-DCMAKE_C_FLAGS="-O3 -DNDEBUG -fomit-frame-pointer" \
		-DCMAKE_CXX_FLAGS="-O3 -DNDEBUG -fomit-frame-pointer" && make -j$(NPROC)
	@echo "$(OK) Native libraries built (release)"

native-debug:
	@mkdir -p native/build
	@cd native/build && cmake .. -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON && make -j$(NPROC)
	@echo "$(OK) Native libraries built (debug + ASan)"

native-test: native-build
	@cd native/build && ctest --output-on-failure
	@echo "$(OK) Native tests passed"

native-smoke:
	@bash ./scripts/dev/smoke-test.sh --native
	@echo "$(OK) Native smoke test passed"

native-clean:
	@rm -rf native/build
	@echo "$(OK) Native build cleaned"

prod-with-native: native-release
	@mkdir -p bin/server bin/native
	@cp native/build/lib*.so native/build/lib*.dylib bin/native/ 2>/dev/null || true
	go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/api-server ./cmd/api-server/main.go
	go build -ldflags="$(LDFLAGS_PROD)" -o bin/server/worker ./cmd/worker/worker_server.go
	@echo "$(OK) Production binaries built (with native libs)"

cross-platform:
	@rm -rf dist && mkdir -p dist
	@echo "Building Linux x86_64 static binaries..."
	@for bin in \
		"fetchml_api-server:cmd/api-server/main.go" \
		"fetchml_worker:cmd/worker/worker_server.go" \
		"fetchml_data_manager:./cmd/data_manager" \
		"fetchml_user_manager:./cmd/user_manager" \
		"fetchml_tui:./cmd/tui"; do \
		name=$${bin%%:*}; src=$${bin##*:}; \
		CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false \
			-ldflags="-s -w -buildid=" -o dist/$${name}_linux_amd64 $$src; \
	done
	@echo "$(OK) Cross-platform binaries in dist/"

build-cli:
	$(MAKE) -C cli all
	@echo "$(OK) CLI built"

verify-build:
	@$(MAKE) build && shasum -a 256 bin/server/* bin/cli/* > /tmp/build_hash_1.txt 2>/dev/null || true
	@$(MAKE) build && shasum -a 256 bin/server/* bin/cli/* > /tmp/build_hash_2.txt 2>/dev/null || true
	@diff /tmp/build_hash_1.txt /tmp/build_hash_2.txt > /dev/null \
		&& echo "$(OK) Build is reproducible" \
		|| (echo "Build differs (expected with timestamps):"; diff /tmp/build_hash_1.txt /tmp/build_hash_2.txt || true)

# -----------------------------------------------------------------------------
# Tests
# -----------------------------------------------------------------------------

test: test-infra-up
	@[ -f bin/cli/ml ] || $(MAKE) build-cli
	@go test -v ./tests/unit/... ./tests/integration/... ./tests/e2e/... 2>&1 | grep -v "redis: connection pool" | tee /tmp/test-all.txt || true
	@echo "\n=== Test Summary ==="
	$(call test_summary,/tmp/test-all.txt)
	@$(MAKE) test-infra-down
	@cd cli && zig build test

test-unit:
	@go test -v -short ./tests/unit/... 2>&1 | tee /tmp/test-unit.txt || true
	@echo "\n=== Unit Test Summary ==="
	$(call test_summary,/tmp/test-unit.txt)
	@cd cli && zig build test

test-integration: test-infra-up
	@go test -v ./tests/integration/... 2>&1 | tee /tmp/test-integration.txt || true
	@echo "\n=== Integration Test Summary ==="
	$(call test_summary,/tmp/test-integration.txt)
	@$(MAKE) test-infra-down

test-e2e: test-infra-up
	@[ -f bin/cli/ml ] || $(MAKE) build-cli
	@go test -v ./tests/e2e/... 2>&1 | tee /tmp/test-e2e.txt || true
	@echo "\n=== E2E Test Summary ==="
	$(call test_summary,/tmp/test-e2e.txt)
	@$(MAKE) test-infra-down

test-coverage:
	@mkdir -p coverage
	go test -coverprofile=coverage/coverage.out ./...
	go tool cover -html=coverage/coverage.out -o coverage/coverage.html
	@echo "$(OK) Coverage report: coverage/coverage.html"

test-infra-up:
	@echo "Starting test infrastructure..."
	@$(DC) -f $(TEST_COMPOSE) up -d
	@echo "$(OK) Test infrastructure started"

test-infra-down:
	@$(DC) -f $(TEST_COMPOSE) down 2>/dev/null || true
	@echo "$(OK) Test infrastructure stopped"

# -----------------------------------------------------------------------------
# Lint & Clean
# -----------------------------------------------------------------------------

lint:
	gofmt -w ./cmd ./internal ./tests || true
	go vet ./...
	cd cli && zig fmt .
	@echo "$(OK) Lint complete"

configlint:
	go run ./cmd/configlint --schema configs/schema/api_server_config.yaml \
		configs/api/dev.yaml \
		configs/api/homelab-secure.yaml \
		configs/api/multi-user.yaml \
		configs/api/prod.yaml

worker-configlint:
	go run ./cmd/configlint --schema configs/schema/worker_config_schema.yaml \
		configs/workers/worker-prod.toml \
		configs/workers/docker.yaml \
		configs/workers/docker-dev.yaml \
		configs/workers/docker-prod.yaml \
		configs/workers/homelab-secure.yaml

ci-checks:
	@bash ./scripts/ci/checks.sh

ci-local: lint configlint worker-configlint ci-checks test
	@mkdir -p coverage
	@echo "Running queue package tests with race detector..."
	go test -v -race -coverprofile=coverage/queue-coverage.out ./internal/queue/...
	$(MAKE) test-coverage

clean:
	rm -rf bin/ coverage/ tests/bin/ dist/
	rm -rf cli/zig-out/ cli/.zig-cache/ .zig-cache/
	go clean
	@echo "$(OK) Cleaned"

clean-release: clean
	rm -rf native/build/
	go clean -cache -testcache
	find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
	find . -name "*.pyc" -delete 2>/dev/null || true
	@./scripts/release/cleanup.sh testdata 2>/dev/null || true
	@./scripts/release/cleanup.sh logs 2>/dev/null || true
	@./scripts/release/cleanup.sh state 2>/dev/null || true
	@echo "$(OK) Release cleanup complete"

prepare-release: clean-release
	@./scripts/release/verify.sh
	@echo "$(OK) Release preparation complete"

# -----------------------------------------------------------------------------
# Verification
# -----------------------------------------------------------------------------

verify-schema:
	@go test ./internal/manifest/... -run TestSchemaUnchanged -v
	@echo "$(OK) Schema validation passed"

test-schema-validation:
	@go test ./internal/manifest/... -run TestSchemaValidatesExampleManifest -v
	@go test ./internal/manifest/... -run TestSchemaRejectsInvalidManifest -v
	@echo "$(OK) Schema tests passed"

lint-custom:
	@mkdir -p bin/tools
	go build -ldflags="-s -w" -o bin/tools/fetchml-vet ./tools/fetchml-vet/cmd/fetchml-vet/
	go vet -vettool=bin/tools/fetchml-vet ./internal/... ./cmd/... 2>/dev/null || true
	@echo "$(OK) Custom lint complete"

verify-audit:
	@go test ./tests/unit/audit/... -run TestChainVerifier -v
	@echo "$(OK) Audit chain verification passed"

verify-audit-chain:
	@if [ -z "$(AUDIT_LOG_PATH)" ]; then \
		echo "Usage: make verify-audit-chain AUDIT_LOG_PATH=/path/to/audit.log"; exit 1; \
	fi
	@mkdir -p bin/tools
	go build -ldflags="-s -w" -o bin/tools/audit-verifier ./cmd/audit-verifier/
	./bin/tools/audit-verifier -log-path=$(AUDIT_LOG_PATH)
	@echo "$(OK) Audit chain integrity verified"

verify-quick: verify-schema

verify-all: verify-schema test-schema-validation lint-custom verify-audit
	@echo "$(OK) All verification checks passed"

# -----------------------------------------------------------------------------
# Security
# -----------------------------------------------------------------------------

security-scan: gosec govulncheck check-unsafe
	@echo "$(OK) Security scan complete"

gosec:
	$(call ensure_tool,gosec,github.com/securego/gosec/v2/cmd/gosec@latest)
	@mkdir -p reports
	gosec -fmt=json -out=reports/gosec-results.json ./... 2>/dev/null || true
	gosec -fmt=sarif -out=reports/gosec-results.sarif ./... 2>/dev/null || true
	gosec ./... 2>/dev/null || echo "Note: gosec found issues (see reports/gosec-results.json)"
	@echo "$(OK) gosec scan complete"

govulncheck:
	$(call ensure_tool,govulncheck,golang.org/x/vuln/cmd/govulncheck@latest)
	govulncheck ./...
	@echo "$(OK) govulncheck complete"

check-unsafe:
	@if grep -r "unsafe\." --include="*.go" ./internal ./cmd 2>/dev/null | grep -v "_test.go"; then \
		echo "WARNING: unsafe package usage found — review required"; exit 1; \
	else \
		echo "$(OK) No unsafe package usage"; \
	fi

security-audit: security-scan
	@go test -v ./tests/security/... 2>/dev/null || echo "Note: No security tests yet"
	@echo "$(OK) Full security audit complete"

# -----------------------------------------------------------------------------
# OpenAPI
# -----------------------------------------------------------------------------

_ensure_oapi:
	$(call ensure_tool,oapi-codegen,github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest)

openapi-generate: _ensure_oapi
	oapi-codegen -package api -generate types api/openapi.yaml > internal/api/types.go
	@echo "$(OK) Generated internal/api/types.go"

openapi-generate-server: _ensure_oapi
	oapi-codegen -package api -generate types,server api/openapi.yaml > internal/api/server_gen.go
	@echo "$(OK) Generated internal/api/server_gen.go"

openapi-validate:
	@command -v openapi-generator >/dev/null 2>&1 \
		&& openapi-generator validate -i api/openapi.yaml 2>/dev/null \
		|| echo "Note: Install openapi-generator for validation"

openapi-check-ci: openapi-generate
	@git diff --exit-code internal/api/types.go 2>/dev/null \
		|| (echo "ERROR: Run 'make openapi-generate' to sync" && exit 1)
	@echo "$(OK) OpenAPI types up to date"

openapi-check-implementation: openapi-generate-server
	@git diff --exit-code internal/api/server_gen.go 2>/dev/null \
		|| (echo "ERROR: Run 'make openapi-generate-server' to sync" && exit 1)
	@echo "$(OK) Spec and implementation in sync"

openapi-generate-clients: openapi-generate-ts openapi-generate-python
	@echo "$(OK) All client SDKs generated"

openapi-generate-ts:
	@mkdir -p sdk/typescript
	@command -v npx >/dev/null 2>&1 || (echo "Note: npx not available" && exit 0)
	npx @openapitools/openapi-generator-cli generate \
		-i api/openapi.yaml -g typescript-fetch -o sdk/typescript \
		--additional-properties=supportsES6=true,npmName=fetchml-client 2>/dev/null \
		|| echo "Note: npm install -g @openapitools/openapi-generator-cli"

openapi-generate-python:
	@mkdir -p sdk/python
	@command -v npx >/dev/null 2>&1 || (echo "Note: npx not available" && exit 0)
	npx @openapitools/openapi-generator-cli generate \
		-i api/openapi.yaml -g python -o sdk/python \
		--additional-properties=packageName=fetchml_client 2>/dev/null \
		|| echo "Note: npm install -g @openapitools/openapi-generator-cli"

# -----------------------------------------------------------------------------
# Documentation
# -----------------------------------------------------------------------------

docs-setup:
	@command -v hugo >/dev/null 2>&1 \
		|| (printf "Hugo not found.\n  macOS: brew install hugo\n  Linux: https://gohugo.io/installation/\n" && exit 1)
	@echo "$(OK) Hugo available"

docs: docs-setup
	cd docs && hugo server --bind "$(DOCS_BIND)" --port "$(DOCS_PORT)" --baseURL "$(DOCS_BASEURL)"

docs-build:
	cd docs && hugo

docs-build-prod:
	cd docs && hugo --minify --baseURL "$(DOCS_PROD_BASEURL)"

docs-generate:
	@mkdir -p docs/api
	@command -v npx >/dev/null 2>&1 \
		&& npx @redocly/cli build-docs api/openapi.yaml \
			--output docs/api/index.html --title "FetchML API" 2>/dev/null \
		|| echo "Note: npm install -g @redocly/cli"

docs-serve:
	@command -v npx >/dev/null 2>&1 \
		&& npx @redocly/cli preview-docs api/openapi.yaml \
		|| echo "Note: npx not available"

# -----------------------------------------------------------------------------
# Performance
# -----------------------------------------------------------------------------

benchmark:
	go test -bench=. -benchmem ./tests/benchmarks/...

benchmark-local:
	@./scripts/benchmarks/run-benchmarks-local.sh

benchmark-native:
	go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/...

benchmark-compare:
	@echo "=== Go ==="
	@go test -bench=. -benchmem ./tests/benchmarks/... 2>&1 \
		| grep -E '(Benchmark|ns/op|allocs/op)' || true
	@echo "\n=== Native ==="
	@go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... 2>&1 \
		| grep -E '(Benchmark|ns/op|allocs/op)' \
		|| echo "Native not available (run: make native-build)"

load-test:
	go test -v ./tests/load/...

chaos-test:
	go test -v ./tests/chaos/...

profile-load:
	@mkdir -p tests/bin
	go test ./tests/load -run TestLoadProfile_Medium -count=1 -cpuprofile tests/bin/cpu_load.out
	@echo "$(OK) Profile → tests/bin/cpu_load.out"

profile-load-norate:
	@mkdir -p tests/bin
	go test ./tests/load -run TestLoadProfile_Medium -count=1 \
		-cpuprofile tests/bin/cpu_load.out -v -args -profile-norate

profile-ws-queue:
	@mkdir -p tests/bin
	go test ./tests/integration -run WebSocketQueue -count=2 -cpuprofile tests/bin/cpu_ws.out
	@echo "$(OK) Profile → tests/bin/cpu_ws.out"

profile-tools:
	@mkdir -p bin/tools
	go build -ldflags="-s -w" -o bin/tools/performance-regression-detector \
		./cmd/performance-regression-detector
	go build -ldflags="-s -w" -o bin/tools/profiler ./cmd/profiler
	@echo "$(OK) Profiling tools in bin/tools/"

detect-regressions: profile-tools
	@mkdir -p tests/bin
	@if [ ! -f tests/bin/baseline.bench.txt ]; then \
		echo "Creating baseline..."; \
		go test -bench=. -benchmem ./tests/benchmarks/... | tee tests/bin/baseline.bench.txt; \
	fi
	go test -bench=. -benchmem ./tests/benchmarks/... | tee tests/bin/current.bench.txt
	./bin/tools/performance-regression-detector \
		-baseline tests/bin/baseline.bench.txt \
		-current tests/bin/current.bench.txt \
		-threshold 10.0

detect-regressions-native: native-build profile-tools
	@mkdir -p tests/bin
	@if [ ! -f tests/bin/baseline-native.bench.txt ]; then \
		echo "Creating native baseline..."; \
		go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... \
			| tee tests/bin/baseline-native.bench.txt; \
	fi
	go test -bench=. -benchmem -tags native_libs ./tests/benchmarks/... \
		| tee tests/bin/current-native.bench.txt
	./bin/tools/performance-regression-detector \
		-baseline tests/bin/baseline-native.bench.txt \
		-current tests/bin/current-native.bench.txt \
		-threshold 10.0

clean-benchmarks:
	@./scripts/maintenance/cleanup-benchmarks.sh benchmarks

status:
	@./scripts/maintenance/cleanup-benchmarks.sh status

size:
	@ls -lh bin/server/* bin/cli/* bin/tools/* 2>/dev/null || true

complete-suite: benchmark load-test chaos-test profile-tools
	@echo "$(OK) Performance suite complete"

# -----------------------------------------------------------------------------
# Deployment
# -----------------------------------------------------------------------------

dev-up:
	$(DC) -f deployments/docker-compose.dev.yml up -d
	@echo "$(OK) Dev environment up  (Caddy: 8080/8443  Redis: 6379  Prometheus: 9090  Grafana: 3000)"

dev-down:
	$(DC) -f deployments/docker-compose.dev.yml down

dev-logs:
	$(DC) -f deployments/docker-compose.dev.yml logs -f

dev-restart:
	$(DC) -f deployments/docker-compose.dev.yml restart

staging-up:
	@if [ ! -f deployments/.env.staging ]; then \
		printf 'DATA_DIR=./data/staging\nLOG_LEVEL=info\nCOMPLIANCE_MODE=standard\n' \
			> deployments/.env.staging; \
		echo "Created deployments/.env.staging with defaults"; \
	fi
	$(DC) -f deployments/docker-compose.staging.yml up -d

staging-down:
	$(DC) -f deployments/docker-compose.staging.yml down

staging-logs:
	$(DC) -f deployments/docker-compose.staging.yml logs -f

staging-restart:
	$(DC) -f deployments/docker-compose.staging.yml restart

staging-status:
	$(DC) -f deployments/docker-compose.staging.yml ps

homelab-secure-up:
	$(DC) -f deployments/docker-compose.homelab-secure.yml up -d

homelab-secure-down:
	$(DC) -f deployments/docker-compose.homelab-secure.yml down

prod-up:
	@echo "⚠  WARNING: This is production. Ensure you have proper backups."
	@read -p "Continue? [y/N] " c && [ "$$c" = "y" ] || exit 1
	$(DC) -f deployments/docker-compose.prod.yml up -d

prod-down:
	$(DC) -f deployments/docker-compose.prod.yml down

prod-logs:
	$(DC) -f deployments/docker-compose.prod.yml logs -f

prod-restart:
	@read -p "Restart production? [y/N] " c && [ "$$c" = "y" ] || exit 1
	$(DC) -f deployments/docker-compose.prod.yml restart

prod-status:
	$(DC) -f deployments/docker-compose.prod.yml ps

status-all:
	@for env in dev staging homelab-secure prod; do \
		f="deployments/docker-compose.$$env.yml"; \
		echo "=== $$env ==="; \
		[ -f "$$f" ] && $(DC) -f "$$f" ps 2>/dev/null || echo "Not running"; \
		echo; \
	done

clean-deploy:
	@echo "Removes all containers and volumes for every environment. Continue? [y/N]"
	@read -r c && [ "$$c" = "y" ] || exit 1
	@for env in dev staging homelab-secure prod; do \
		f="deployments/docker-compose.$$env.yml"; \
		[ -f "$$f" ] && $(DC) -f "$$f" down -v 2>/dev/null || true; \
	done
	docker system prune -f
	@echo "$(OK) All deployments cleaned"

rollback-staging:
	@echo "⚠  Rolls back image only — queue state and audit log are NOT rolled back."
	@read -p "Continue? [y/N] " c && [ "$$c" = "y" ] || exit 1
	$(DC) -f deployments/docker-compose.staging.yml down
	$(DC) -f deployments/docker-compose.staging.yml up -d
	@echo "$$(date -Iseconds) | rollback | staging | actor=$$(whoami)" \
		>> deployments/.staging-audit.log

rollback-prod:
	@echo "⚠  CRITICAL: Image rollback only."
	@echo "   Queue state, audit chain, and storage artifacts are NOT rolled back."
	@read -p "CONFIRM PRODUCTION ROLLBACK? [yes/N] " c && [ "$$c" = "yes" ] || exit 1
	$(DC) -f deployments/docker-compose.prod.yml down
	$(DC) -f deployments/docker-compose.prod.yml up -d
	@echo "$$(date -Iseconds) | rollback | prod | actor=$$(whoami)" \
		>> deployments/.prod-audit.log
	@echo "$(OK) Rollback complete — verify: make prod-status"

deploy-health-check:
	@echo "=== Health Checks ==="
	@for item in "Development=9101" "Staging=9102" "Production=9101"; do \
		label=$${item%%=*}; port=$${item##*=}; \
		printf "%-16s (localhost:$$port): " "$$label"; \
		curl -fsS http://localhost:$$port/health 2>/dev/null && echo "✓" || echo "✗ not responding"; \
	done

# -----------------------------------------------------------------------------
# Install & Misc
# -----------------------------------------------------------------------------

install: prod
	sudo cp bin/server/api-server /usr/local/bin/fetchml-api
	sudo cp bin/server/worker     /usr/local/bin/fetchml-worker
	sudo cp bin/server/tui        /usr/local/bin/fetchml-tui
	sudo cp bin/cli/ml            /usr/local/bin/ml
	@echo "$(OK) Installed"

docker-build:
	docker build -f build/docker/simple.Dockerfile -t fetchml:latest .
	@echo "$(OK) Docker image built"

dev-smoke:
	@bash ./scripts/dev/smoke-test.sh dev

prod-smoke:
	@bash ./scripts/dev/smoke-test.sh prod

test-auth:
	@for role in admin researcher analyst; do \
		echo "Testing $$role user..."; \
		cp ~/.ml/config-$$role.toml ~/.ml/config.toml && ./bin/cli/ml status; \
	done

install-tools:
	$(call ensure_tool,gosec,github.com/securego/gosec/v2/cmd/gosec@latest)
	$(call ensure_tool,govulncheck,golang.org/x/vuln/cmd/govulncheck@latest)
	$(call ensure_tool,go-mutesting,github.com/zimmski/go-mutesting/cmd/go-mutesting@latest)
	$(call ensure_tool,scorecard,github.com/ossf/scorecard/v4/cmd/scorecard@latest)
	$(call ensure_tool,oapi-codegen,github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest)
	@echo "$(OK) All tools installed"

help:
	@printf "FetchML Build System\n\n"
	@printf "Build\n"
	@printf "  build                  Build all components (default)\n"
	@printf "  prod                   Production-optimized binaries\n"
	@printf "  prod-with-native       Production binaries + native C++ libs\n"
	@printf "  dev                    Fast development build\n"
	@printf "  cross-platform         Linux x86_64 static binaries in dist/\n"
	@printf "  build-cli              Build Zig CLI only\n"
	@printf "  clean                  Remove all build artifacts\n"
	@printf "  clean-release          Thorough pre-release cleanup\n"
	@printf "  prepare-release        clean-release + release verification\n"
	@printf "  verify-build           Check build reproducibility\n"
	@printf "\n"
	@printf "Native Libraries\n"
	@printf "  native-build           C++ libs (release)\n"
	@printf "  native-release         C++ libs (fully optimized)\n"
	@printf "  native-debug           C++ libs (debug + ASan)\n"
	@printf "  native-test            Run C++ unit tests\n"
	@printf "  native-smoke           C++ + Go integration smoke test\n"
	@printf "  native-clean           Remove native build artifacts\n"
	@printf "\n"
	@printf "Tests\n"
	@printf "  test                   All tests with infrastructure (CI default)\n"
	@printf "  test-unit              Fast unit tests, no infrastructure\n"
	@printf "  test-integration       Integration tests (infra auto-managed)\n"
	@printf "  test-e2e               E2E tests (CLI auto-built, infra auto-managed)\n"
	@printf "  test-coverage          Generate HTML coverage report\n"
	@printf "  test-infra-up          Start Redis + SSH test containers\n"
	@printf "  test-infra-down        Stop test containers\n"
	@printf "\n"
	@printf "Lint & CI\n"
	@printf "  lint                   gofmt + go vet + zig fmt\n"
	@printf "  configlint             Validate API YAML configs\n"
	@printf "  worker-configlint      Validate worker configs\n"
	@printf "  ci-checks              Maintainability checks\n"
	@printf "  ci-local               Full local CI (lint → config → test → coverage)\n"
	@printf "\n"
	@printf "Verification\n"
	@printf "  verify-quick           Schema check only\n"
	@printf "  verify-all             Schema + custom lint + audit chain\n"
	@printf "  verify-audit-chain     Verify live audit log  AUDIT_LOG_PATH=...\n"
	@printf "  install-tools          Install all dev/CI tools in one shot\n"
	@printf "\n"
	@printf "Security\n"
	@printf "  security-scan          gosec + govulncheck + unsafe check\n"
	@printf "  security-audit         security-scan + security tests\n"
	@printf "\n"
	@printf "OpenAPI\n"
	@printf "  openapi-generate           Regenerate internal/api/types.go\n"
	@printf "  openapi-generate-server    Regenerate internal/api/server_gen.go\n"
	@printf "  openapi-generate-clients   TypeScript + Python SDKs\n"
	@printf "  openapi-check-ci           Fail if types.go out of sync\n"
	@printf "  openapi-check-implementation  Fail if server_gen.go out of sync\n"
	@printf "\n"
	@printf "Performance\n"
	@printf "  benchmark              Go benchmarks\n"
	@printf "  benchmark-native       Benchmarks with native libs\n"
	@printf "  benchmark-compare      Side-by-side Go vs native\n"
	@printf "  load-test / chaos-test Load and chaos suites\n"
	@printf "  detect-regressions     Compare against saved baseline\n"
	@printf "  complete-suite         benchmark + load + chaos + profile tools\n"
	@printf "\n"
	@printf "Deployment\n"
	@printf "  dev-up / dev-down          Development environment\n"
	@printf "  staging-up / staging-down  Staging environment\n"
	@printf "  prod-up / prod-down        Production (confirmation required)\n"
	@printf "  status-all                 Status across all environments\n"
	@printf "  deploy-health-check        HTTP health checks for all environments\n"
	@printf "  rollback-staging           Roll back staging image\n"
	@printf "  rollback-prod              Roll back production image (double-confirmed)\n"
	@printf "  clean-deploy               Tear down all environments + prune Docker\n"
	@printf "\n"
	@printf "Install\n"
	@printf "  install                Install binaries to /usr/local/bin\n"
	@printf "  docker-build           Build Docker image\n"
	@printf "  install-tools          Install all dev/CI tools\n"
	@printf "  size                   Show binary sizes\n"
	@printf "  help                   This message\n"
