# Build and run helpers for the rea-agent images.
#
# Four images, one engine each - select with ENGINE=all|ghidra|hopper|ida:
#
#   make build ENGINE=ghidra      make up ENGINE=hopper      make verify ENGINE=ida
#   make build-ghidra             make up-hopper             make verify-ghidra
#
# Everything Docker-side uses the HOST path to this project directory when a
# Docker socket is bind-mounted into the caller (e.g. Hermes running in Docker
# with DooD): volume/context sources resolve on the host daemon, not inside the
# caller's container. scripts/build.sh does that translation.
SHELL := /bin/bash

ENGINE ?= all
DOCKER ?= docker
COMPOSE ?= $(DOCKER) compose
TAG_SUFFIX ?= 6.8.0-linux-amd64

# engine -> compose service / profile (the image name comes from
# scripts/image-name.sh, which also honours the REA_*_IMAGE names in .env, so a
# local build tags exactly what `docker compose pull` would fetch)
engine_service = $(if $(filter all,$(1)),rea-agent,rea-$(1))

IMAGE    := $(shell scripts/image-name.sh $(ENGINE))
SERVICE  := $(call engine_service,$(ENGINE))
PROFILE  := $(if $(filter all,$(ENGINE)),,--profile $(ENGINE))
COMPOSE_ENGINE = $(COMPOSE) -f docker-compose.yml

.DEFAULT_GOAL := help

.PHONY: help
help: ## show this help
	@grep -hE '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk 'BEGIN{FS=":.*?## "}{printf "  \033[36m%-18s\033[0m %s\n", $$1, $$2}'
	@echo
	@echo "  ENGINE=$(ENGINE) -> image $(IMAGE), service $(SERVICE)"
	@echo "  images: all=rea-agent (Ghidra+Hopper) | ghidra | hopper | ida (bring your own IDA)"

.PHONY: env
env: ## create .env from .env.example when missing
	@test -f .env || (cp .env.example .env && echo "created .env - review it, then 'make build'")

.PHONY: build
build: env ## build the image for $(ENGINE)
	scripts/build.sh --engine $(ENGINE)

.PHONY: build-ghidra build-hopper build-ida
build-ghidra: ## build the Ghidra-only image
	scripts/build.sh --engine ghidra
build-hopper: ## build the Hopper-only image
	scripts/build.sh --engine hopper
build-ida: ## build the engine-less IDA image (bring your own IDA)
	scripts/build.sh --engine ida

.PHONY: build-all
build-all: ## build all four images
	scripts/build-all.sh

.PHONY: up
up: ## start the long-lived container for $(ENGINE)
	$(COMPOSE_ENGINE) $(PROFILE) up -d $(SERVICE)

.PHONY: up-ghidra up-hopper up-ida
up-ghidra: ## start the Ghidra-only container
	$(COMPOSE_ENGINE) --profile ghidra up -d rea-ghidra
up-hopper: ## start the Hopper-only container
	$(COMPOSE_ENGINE) --profile hopper up -d rea-hopper
up-ida: ## start the IDA container (needs your own IDA install/licence)
	$(COMPOSE_ENGINE) --profile ida up -d rea-ida

.PHONY: down
down: ## stop every compose service of this project
	$(COMPOSE) down

.PHONY: shell
shell: ## interactive shell in the running $(ENGINE) container
	$(COMPOSE) exec $(SERVICE) bash

.PHONY: doctor
doctor: ## REA readiness report from inside the $(ENGINE) container
	$(COMPOSE) exec $(SERVICE) rea doctor --json

.PHONY: providers
providers: ## list analysis providers and their capabilities
	$(COMPOSE) exec $(SERVICE) rea providers --json

.PHONY: verify
verify: ## full in-container verification for $(ENGINE)
	scripts/verify.sh --image $(IMAGE)

.PHONY: verify-quick
verify-quick: ## fast verification (tool presence + static + MCP handshake)
	scripts/verify.sh --image $(IMAGE) --quick

.PHONY: verify-ghidra verify-hopper verify-ida
verify-ghidra: ## full verification of the Ghidra-only image
	scripts/verify.sh --engine ghidra --only tools,analysis,static,clients,mcp
verify-hopper: ## full verification of the Hopper-only image
	scripts/verify.sh --engine hopper --only tools,analysis,static,clients,mcp
verify-ida: ## verification of the engine-less IDA image
	scripts/verify.sh --engine ida --only tools,static,clients,mcp

.PHONY: pull
pull: ## pull the published image for $(ENGINE) from GHCR (no local build)
	$(DOCKER) pull $(IMAGE)

.PHONY: pull-all
pull-all: ## pull all four published images from GHCR
	@for e in all ghidra hopper ida; do \
	  img="$$( scripts/image-name.sh $$e )"; \
	  echo "== pulling $$img"; \
	  $(DOCKER) pull "$$img" || exit 1; \
	done

.PHONY: mcp-stdio
mcp-stdio: ## speak MCP over stdio the way Hermes does
	$(DOCKER) exec -i $(SERVICE) rea mcp

.PHONY: http-up
http-up: ## start the Streamable HTTP bridge for $(ENGINE)
	REA_IMAGE=$(IMAGE) REA_ENGINE=$(ENGINE) $(COMPOSE_ENGINE) $(PROFILE) -f compose.http.yml up -d rea-mcp-http

.PHONY: ida-up
ida-up: ## start the IDA overlay (needs your own IDA install/licence)
	$(COMPOSE_ENGINE) -f compose.ida.yml --profile ida up -d rea-ida

.PHONY: test-host
test-host: ## run the harness in a throwaway container against ./work
	$(DOCKER) run --rm -it --shm-size=1g \
	  --user "$$(id -u):$$(id -g)" \
	  -v $(PWD)/work:/work -v $(PWD)/config:/etc/rea:ro $(IMAGE) \
	  /opt/rea/verify/verify-all.sh

.PHONY: check-updates
check-updates: ## are the pins still current? (upstream + what REA admits)
	scripts/check-updates.py $(ARGS)

.PHONY: check-updates-json
check-updates-json: ## the same check as JSON (for scripts)
	scripts/check-updates.py --json --no-fail

.PHONY: sizes
sizes: ## report the size of every engine image
	@for e in all ghidra hopper ida; do \
	  img="$$( scripts/image-name.sh $$e )"; \
	  bytes="$$( $(DOCKER) image inspect "$$img" --format '{{.Size}}' 2>/dev/null || echo '' )"; \
	  if [ -n "$$bytes" ]; then \
	    human="$$(awk -v b="$$bytes" 'BEGIN{printf "%.2f GB", b/1024/1024/1024}')"; \
	    printf '  %-52s %s (%s bytes)\n' "$$img" "$$human" "$$bytes"; \
	  else \
	    printf '  %-52s %s\n' "$$img" "not built/pulled"; \
	  fi; \
	done

.PHONY: clean
clean: ## remove build output, not the images
	rm -rf work/verify-reports work/tmp
