.PHONY: up down logs status setup test test-full pull clean teardown help prereq ngc-login

COMPOSE := docker compose
SHELL := /bin/bash

# Source .env so port and GPU overrides propagate to recipes that don't run
# via docker compose (e.g. setup_sandbox.sh's openshell provider create).
ifneq (,$(wildcard ./.env))
include .env
export
endif

help: ## Show this help
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2}'

# ── Prerequisites & auth ────────────────────────────────────────

prereq: ## Validate Docker, Node.js v22, OpenShell, disk, GPU, port 11434, NGC auth
	@echo "=== Prerequisite checks ==="
	@command -v docker >/dev/null 2>&1 \
		&& echo "  Docker:           ✓ $$(docker info --format '{{.ServerVersion}}' 2>/dev/null)" \
		|| { echo "  Docker:           ✗ not installed"; exit 1; }
	@NODE_MAJ=$$(node --version 2>/dev/null | sed 's/v\([0-9]*\).*/\1/'); \
		if [ -z "$$NODE_MAJ" ]; then echo "  Node.js:          ✗ not installed (need v22+)"; exit 1; \
		elif [ "$$NODE_MAJ" -lt 22 ]; then echo "  Node.js:          ✗ v$$NODE_MAJ found, need v22+. Upgrade: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs"; exit 1; \
		else echo "  Node.js:          ✓ $$(node --version)"; fi
	@command -v openshell >/dev/null 2>&1 \
		&& echo "  OpenShell:        ✓ $$(openshell --version 2>/dev/null)" \
		|| { echo "  OpenShell:        ✗ not installed"; exit 1; }
	@FREE=$$(df -BG / | awk 'NR==2 {print $$4}' | tr -d 'G'); \
		if [ "$$FREE" -lt 200 ]; then echo "  Disk free /:      ⚠ $${FREE}G (need 200G+ for 86G model + images + working space)"; \
		else echo "  Disk free /:      ✓ $${FREE}G"; fi
	@nvidia-smi --query-gpu=name --format=csv,noheader >/dev/null 2>&1 \
		&& echo "  GPU:              ✓ $$(nvidia-smi --query-gpu=name --format=csv,noheader | paste -sd ',')" \
		|| { echo "  GPU:              ✗ nvidia-smi not available"; exit 1; }
	@if ss -tlnp 2>/dev/null | grep -q ':$${OLLAMA_PORT:-11434} '; then \
		echo "  Port $${OLLAMA_PORT:-11434}:        ⚠ already bound (host Ollama?). Stop with 'sudo systemctl stop ollama' or set OLLAMA_PORT in .env"; \
	else \
		echo "  Port $${OLLAMA_PORT:-11434}:        ✓ free"; \
	fi
	@if grep -q '"nvcr.io"' ~/.docker/config.json 2>/dev/null; then \
		echo "  NGC docker login: ✓ (run 'make ngc-login' to refresh)"; \
	else \
		echo "  NGC docker login: ✗ not authenticated. Run 'make ngc-login' (requires NGC_API_KEY in .env)"; \
	fi
	@echo ""
	@echo "Prereqs OK. Run 'make ngc-login' if needed, then 'make up'."

ngc-login: ## Authenticate Docker against nvcr.io using NGC_API_KEY from .env
	@if [ -z "$(NGC_API_KEY)" ] || [ "$(NGC_API_KEY)" = "nvapi-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ]; then \
		echo "ERROR: NGC_API_KEY not set in .env. Get one at https://ngc.nvidia.com/setup/api-key"; \
		exit 1; \
	fi
	@echo "$(NGC_API_KEY)" | docker login nvcr.io --username '$$oauthtoken' --password-stdin

# ── Infrastructure ──────────────────────────────────────────────

up: ## Start all services (Ollama + OpenFold3)
	$(COMPOSE) up -d ollama openfold3
	@echo ""
	@echo "Waiting for Ollama health..."
	@$(COMPOSE) up model-pull
	@echo ""
	@echo "Services started. Run 'make status' to check health."

down: ## Stop all services
	$(COMPOSE) down

logs: ## Tail all service logs
	$(COMPOSE) logs -f

status: ## Show service health (uses OLLAMA_PORT/OPENFOLD_PORT from .env)
	@echo "=== Services ==="
	@$(COMPOSE) ps
	@echo ""
	@echo "=== Health Checks ==="
	@OPORT=$$($(COMPOSE) port ollama 11434 2>/dev/null | sed 's/.*://') ; \
		: $${OPORT:=$${OLLAMA_PORT:-11434}} ; \
		curl -sf "http://localhost:$$OPORT/" > /dev/null 2>&1 \
			&& echo "  Ollama (port $$OPORT):     ✓ healthy" || echo "  Ollama (port $$OPORT):     ✗ down"
	@FPORT=$$($(COMPOSE) port openfold3 8000 2>/dev/null | sed 's/.*://') ; \
		: $${FPORT:=$${OPENFOLD_PORT:-8000}} ; \
		curl -sf "http://localhost:$$FPORT/v1/health/ready" > /dev/null 2>&1 \
			&& echo "  OpenFold3 (port $$FPORT):  ✓ healthy" || echo "  OpenFold3 (port $$FPORT):  ✗ down (may still be loading)"
	@echo ""
	@echo "=== GPU ==="
	@nvidia-smi --query-gpu=index,name,memory.used,memory.total --format=csv,noheader 2>/dev/null \
		|| echo "  nvidia-smi not available"

pull: ## Pull/update model in Ollama
	$(COMPOSE) up model-pull

# ── OpenShell Sandbox ───────────────────────────────────────────

setup: ## Create sandbox and deploy all config (run after 'make up')
	@echo "=== Setting up OpenShell sandbox ==="
	@echo "Prerequisites: openshell CLI installed, gateway started"
	@echo ""
	bash scripts/setup_sandbox.sh

setup-local: ## Same as setup but bind gateway to 0.0.0.0 (no SSH tunnel needed)
	bash scripts/setup_sandbox.sh --local

restart: ## Restart OpenClaw gateway inside sandbox
	@export PATH="$$HOME/.local/bin:$$PATH"; \
	ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR \
		-o ConnectTimeout=10 \
		-o "ProxyCommand=openshell ssh-proxy --gateway-name openshell --name $${SANDBOX_NAME:-clinical-sandbox}" \
		"sandbox@openshell-$${SANDBOX_NAME:-clinical-sandbox}" \
		"bash /sandbox/clinical-intelligence/scripts/restart_sandbox.sh"

# ── Testing ─────────────────────────────────────────────────────

check: ## Verify sandbox config matches repo (skills, identity, helpers, memory)
	@export PATH="$$HOME/.local/bin:$$PATH"; \
	bash scripts/check_sandbox_config.sh $${SANDBOX_NAME:-clinical-sandbox}

test: ## Run test suite levels 1-3 (~3 min)
	bash scripts/test-all.sh --level 3 --verbose

test-full: ## Run all test levels including agent tests (~45 min)
	bash scripts/test-all.sh --level 5 --verbose

test-docker: ## Run tests inside a container
	$(COMPOSE) run --rm test --level 3 --verbose

# ── Cleanup ─────────────────────────────────────────────────────

teardown: ## Tear down sandbox, services, and gateway
	openshell sandbox delete $${SANDBOX_NAME:-clinical-sandbox} 2>/dev/null || true
	$(COMPOSE) down
	pkill -f openshell-gateway 2>/dev/null || true
	openshell gateway remove openshell 2>/dev/null || true
	@echo "Teardown complete."

clean: ## Remove test results, PDB caches, and dangling images
	rm -rf test-results/
	$(COMPOSE) down --volumes --remove-orphans
	docker image prune -f
