.PHONY: build install test lint tidy clean fmt fmt-check spell secrets-scan check

BIN_DIR := cmd/bin
BINARY := $(BIN_DIR)/agentctl
GOPATH_BIN := $(shell go env GOPATH)/bin
# Coverage merges via covdata; with GOTOOLCHAIN=auto the fetched toolchain can fail on
# packages with no tests ("go: no such tool covdata"). Pin to the exact toolchain line in go.mod
# (e.g. go1.26.0) — the bare language version (go1.26) is not a valid toolchain name.
# https://github.com/golang/go/issues/75031
GO_TOOLCHAIN := $(shell awk '/^toolchain / { print $$2; exit }' go.mod)
GOTOOLCHAIN_COVERAGE := $(GO_TOOLCHAIN)+auto
# Embedded in agentctl -version (git describe, or "dev" outside a repo)
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
LDFLAGS := -ldflags "-X main.version=$(VERSION)"

# Build the cmd binary into cmd/bin (default: `make` with no target runs build)
build:
	@echo "==> Building..."
	@mkdir -p $(BIN_DIR)
	go build $(LDFLAGS) -o $(BINARY) ./cmd
	@echo "==> Build complete: $(BINARY)"

# Install agentctl to $(GOPATH)/bin (run agentctl from anywhere if that dir is in PATH)
install: build
	@mkdir -p $(GOPATH_BIN)
	cp $(BINARY) $(GOPATH_BIN)/agentctl
	@echo "Installed to $(GOPATH_BIN)/agentctl"

# Run tests under pkg
test:
	@echo "==> Running tests..."
	go test ./pkg/... -count=1
	go test ./internal/... -count=1
	@echo "==> Tests complete"

# Run before push: lint, test, build, and secrets scan (same core gates as CI; no auto-format).
# Coverage is CI-only (`make test-coverage` when you want the report). If fmt-check fails, run `make fmt`.
check: lint test build secrets-scan
	@echo "==> All checks passed (ready to push)"

# Run tests with coverage
test-coverage:
	@echo "==> Running tests with coverage..."
	GOTOOLCHAIN=$(GOTOOLCHAIN_COVERAGE) go test ./... -count=1 -coverprofile=coverage.out
	@echo "==> Total coverage:"
	@go tool cover -func=coverage.out | grep '^total:'
	go tool cover -html=coverage.out -o coverage.html
	@echo "==> Coverage report: coverage.html"

# Format all Go files (gofmt with simplify; same as Go Report Card / many style checks)
fmt:
	@echo "==> gofmt -s -w"
	gofmt -s -w .
	@echo "==> Format complete"

# Fail if any .go file needs gofmt -s (run `make fmt` to fix)
fmt-check:
	@echo "==> Checking gofmt -s..."
	@files=$$(gofmt -s -l .); \
	if [ -n "$$files" ]; then \
		echo "These files are not gofmt -s formatted. Run: make fmt"; \
		echo "$$files"; \
		exit 1; \
	fi
	@echo "==> gofmt -s OK"

# Typos in tracked source only (skips node_modules, .next, and other gitignored paths).
spell:
	@echo "==> misspell"
	@files=$$(git ls-files -z -- '*.go' '*.md' '*.yaml' '*.yml'); \
	if [ -z "$$files" ]; then \
		echo "No files to spell-check"; \
	else \
		printf '%s' "$$files" | xargs -0 go run github.com/client9/misspell/cmd/misspell@latest -error; \
	fi

# Run linters (gofmt -s, misspell, go vet + golangci-lint).
# Use golangci-lint v2 when go.mod is 1.26+ — v1.x binaries error on newer language targets.
lint: fmt-check spell
	@echo "==> Checking lints (go vet + golangci-lint)..."
	go vet ./...
	golangci-lint run ./...
	@echo "==> Lint complete"

# Tidy module dependencies
tidy:
	@echo "==> Tidying module dependencies..."
	go mod tidy
	@echo "==> Tidy complete"

# Remove built binaries and generated artifacts
clean:
	@echo "==> Cleaning..."
	rm -rf $(BIN_DIR)
	rm -f coverage.out coverage.html
	@echo "==> Clean complete"

# Scan tracked files for leaked secrets (install: https://github.com/gitleaks/gitleaks#installing)
secrets-scan:
	@echo "==> gitleaks detect"
	@if command -v gitleaks >/dev/null 2>&1; then \
		gitleaks detect --source . --verbose --redact; \
	elif command -v docker >/dev/null 2>&1; then \
		docker run --rm -v "$$(pwd):/repo" -w /repo zricethezav/gitleaks:latest detect --source=/repo --verbose --redact; \
	else \
		echo "Install gitleaks or Docker."; \
		exit 1; \
	fi
