UV ?= uv
PY ?= $(UV) run python
BUNDLE ?= okf
ARTIFACTS_DIR ?= artifacts
RAG_ENV ?= .env
RAG_QUERY ?= okf
PRODUCTION = 1
export PRODUCTION
RUN_HOST ?= 127.0.0.1
RUN_PORT ?= 8000
RUN_READY_TIMEOUT ?= 30
RUN_URL ?= http://$(RUN_HOST):$(RUN_PORT)
FRONTEND_DIR ?= frontend
FRONTEND_HOST ?= 127.0.0.1
FRONTEND_PORT ?= 5202
FRONTEND_URL ?= http://$(FRONTEND_HOST):$(FRONTEND_PORT)
FRONTEND_OKF_BUNDLE ?= $(abspath $(BUNDLE))

OKF_DIRS := \
	$(BUNDLE)/documents \
	$(BUNDLE)/requirements/functions \
	$(BUNDLE)/requirements/flows \
	$(BUNDLE)/requirements/rules \
	$(BUNDLE)/requirements/access \
	$(BUNDLE)/data/entities \
	$(BUNDLE)/api/operations \
	$(BUNDLE)/architecture/adr \
	$(BUNDLE)/ui/ux \
	$(BUNDLE)/ui/design-system \
	$(BUNDLE)/ui/uikit

.PHONY: help init validate run run-compose run-production run-check run-check-compose run-check-production run-frontend frontend-install frontend-check test smoke e2e quality live-agent docker-compose-check rag-check indexes graph 7d-report 7d-dashboard 7d-validate guard-artifacts-dir clean-artifacts clean-project reset-empty

help:
	@echo "Targets:"
	@echo "  make init                 Install deps, create RAG env, validate and refresh RAG"
	@echo "  make validate             Compile MCP modules and validate the OKF bundle"
	@echo "  make run                 Start OKF MCP server and Tolaria frontend"
	@echo "                           Set PRODUCTION=1 in this Makefile to use local backend + Docker frontend"
	@echo "  make run-check           Check running service/infrastructure connectivity"
	@echo "  make run-frontend        Start Tolaria frontend in Docker with ./okf mounted read-only"
	@echo "  make frontend-check      Type-check the Tolaria frontend in Docker"
	@echo "  make test                 Run Python regression tests"
	@echo "  make smoke                Run fast local validation + tests"
	@echo "  make e2e                  Run deterministic local E2E checks"
	@echo "  make quality              Run infrastructure-backed quality checks"
	@echo "  make live-agent           Print gated live-agent acceptance instructions"
	@echo "  make indexes              Regenerate OKF index.md files"
	@echo "  make graph                Generate graph JSON/HTML under artifacts/okf"
	@echo "  make rag-check            Validate OKF, inspect RAG, refresh local RAG index"
	@echo "  make 7d-report           Generate a compact report by 7D stage"
	@echo "  make 7d-dashboard        Generate interactive 7D Kanban HTML dashboard"
	@echo "  make 7d-validate         Validate 7D registry usage"
	@echo "  make clean-artifacts      Remove generated artifacts/caches only"
	@echo "  make clean-project CONFIRM=YES"
	@echo "                            Remove all OKF concepts + artifacts; keep empty bundle skeleton"

init:
	@command -v $(UV) >/dev/null || { echo "ERROR: uv is required"; exit 2; }
	$(UV) sync
	@test -f $(RAG_ENV) || cp .env.example $(RAG_ENV)
	@mkdir -p $(ARTIFACTS_DIR)/rag
	$(MAKE) rag-check

validate:
	$(PY) -m py_compile okf_mcp/*.py okf_mcp/rag/*.py okf_mcp/rag/chunking/*.py okf_mcp/rag/ingestion/*.py okf_mcp/rag/retrieval/*.py okf_mcp/rag/storage/*.py
	$(PY) -m okf_mcp validate $(BUNDLE)

run:
	@if [ "$(PRODUCTION)" = "1" ]; then \
		$(MAKE) run-production; \
	else \
		$(MAKE) run-compose; \
	fi

run-compose: docker-compose-check
	@echo "Starting Simple OKF with Docker Compose (PRODUCTION=$(PRODUCTION))"
	@mkdir -p $(ARTIFACTS_DIR)/rag
	PRODUCTION=$(PRODUCTION) docker compose up --build -d
	$(MAKE) run-check-compose
	@echo "Simple OKF is reachable at $(RUN_URL). Press Ctrl+C to stop logs; run 'docker compose down' to stop services."
	docker compose logs -f simple-okf

run-production: validate
	@test -f $(RAG_ENV) || { echo "ERROR: $(RAG_ENV) is required for PRODUCTION=1. Copy .env.example to .env and configure startup endpoints."; exit 2; }
	@echo "Checking PRODUCTION=$(PRODUCTION) startup access from $(RAG_ENV)"
	PRODUCTION=$(PRODUCTION) $(PY) -m okf_mcp rag local-readiness --env $(RAG_ENV) --pretty >/dev/null
	PRODUCTION=$(PRODUCTION) $(PY) -m okf_mcp rag infra-readiness --env $(RAG_ENV) --timeout-seconds $(RUN_READY_TIMEOUT) --pretty >/dev/null
	@docker compose stop simple-okf >/dev/null 2>&1 || true
	@echo "Starting Tolaria frontend in Docker at $(FRONTEND_URL)"
	PRODUCTION=$(PRODUCTION) docker compose up --build -d frontend
	@echo "Starting Simple OKF with PRODUCTION=$(PRODUCTION) from $(RAG_ENV) at $(RUN_URL)"
	PRODUCTION=$(PRODUCTION) $(PY) -m okf_mcp server --bundle $(BUNDLE) --transport http --host $(RUN_HOST) --port $(RUN_PORT)

run-check:
	@if [ "$(PRODUCTION)" = "1" ]; then \
		$(MAKE) run-check-production; \
	else \
		$(MAKE) run-check-compose; \
	fi

run-check-production:
	@test -f $(RAG_ENV) || { echo "ERROR: $(RAG_ENV) is required for PRODUCTION=1"; exit 2; }
	@echo "Checking PRODUCTION=$(PRODUCTION) startup access from $(RAG_ENV)"
	PRODUCTION=$(PRODUCTION) $(PY) -m okf_mcp rag local-readiness --env $(RAG_ENV) --pretty >/dev/null
	PRODUCTION=$(PRODUCTION) $(PY) -m okf_mcp rag infra-readiness --env $(RAG_ENV) --timeout-seconds $(RUN_READY_TIMEOUT) --pretty >/dev/null
	@echo "PRODUCTION=$(PRODUCTION) startup access OK"

run-check-compose:
	@echo "Checking Docker Compose service connectivity"
	docker compose ps
	@i=0; max=$(RUN_READY_TIMEOUT); \
	while [ $$i -lt $$max ]; do \
		if $(PY) -c 'import socket; sock=socket.create_connection(("$(RUN_HOST)", int("$(RUN_PORT)")), timeout=2); sock.close()' >/dev/null 2>&1; then \
			echo "OKF MCP HTTP socket reachable at $(RUN_HOST):$(RUN_PORT)"; \
			exit 0; \
		fi; \
		i=$$((i + 1)); \
		sleep 1; \
	done; \
	echo "ERROR: OKF MCP HTTP socket is not reachable at $(RUN_HOST):$(RUN_PORT) after $(RUN_READY_TIMEOUT)s" >&2; \
	exit 2
	docker compose exec -T simple-okf python -m okf_mcp validate /app/okf >/dev/null
	docker compose exec -T simple-okf python -m okf_mcp rag local-readiness --env .env --no-fail --pretty >/dev/null
	@echo "Docker Compose Simple OKF connectivity OK"

frontend-install: docker-compose-check
	@test -f $(FRONTEND_DIR)/package.json || { echo "ERROR: Tolaria frontend is missing at $(FRONTEND_DIR)"; exit 2; }
	docker compose build frontend

frontend-check: docker-compose-check
	@test -f $(FRONTEND_DIR)/package.json || { echo "ERROR: Tolaria frontend is missing at $(FRONTEND_DIR)"; exit 2; }
	docker compose run --rm --no-deps frontend corepack pnpm exec tsc -b --pretty false

run-frontend: docker-compose-check
	@test -f $(FRONTEND_DIR)/package.json || { echo "ERROR: Tolaria frontend is missing at $(FRONTEND_DIR)"; exit 2; }
	@echo "Starting Tolaria frontend in Docker"
	@echo "Mode: OKF read-only adapter"
	@echo "OKF volume: ./$(BUNDLE) -> /okf:ro"
	@echo "URL: $(FRONTEND_URL)"
	PRODUCTION=$(PRODUCTION) docker compose up --build frontend

test:
	$(PY) -m unittest discover -s tests -p 'test_*.py'

smoke: validate 7d-validate test indexes graph
	$(PY) -m okf_mcp rag inspect --env .env.example --pretty >/dev/null
	$(PY) -m okf_mcp rag refresh --env .env.example --pretty >/dev/null
	$(PY) -m okf_mcp rag retrieve "$(RAG_QUERY)" --env .env.example --limit 3 --pretty >/dev/null
	RAG_EVALUATION_MODE=always $(PY) -m okf_mcp rag retrieve "$(RAG_QUERY)" --env .env.example --answer --limit 3 --pretty >/dev/null

docker-compose-check:
	docker compose config >/dev/null

e2e: validate 7d-validate test docker-compose-check
	$(PY) -m unittest discover -s tests -p 'e2e_test_*.py'
	$(PY) -m okf_mcp rag retrieve "$(RAG_QUERY)" --env .env.example --answer --limit 3 --pretty >/dev/null
	@echo "Deterministic local E2E checks passed. See SPEC.md for full profile scope."

quality: docker-compose-check
	@if [ "$(QUALITY_INFRA)" = "1" ]; then \
		$(PY) -m okf_mcp rag refresh --mode hybrid --env $(RAG_ENV) --pretty >/dev/null; \
		RAG_EVALUATION_MODE=always RAG_EVENT_STORAGE_MODE=required RAG_ENABLE_OBSERVABILITY_READS=true $(PY) -m okf_mcp rag retrieve "$(RAG_QUERY)" --mode hybrid --env $(RAG_ENV) --answer --pretty >/dev/null; \
		RAG_ENABLE_OBSERVABILITY_READS=true $(PY) -m okf_mcp rag quality-summary --env $(RAG_ENV) --pretty >/dev/null; \
	else \
		RAG_EVALUATION_MODE=always $(PY) -m okf_mcp rag retrieve "$(RAG_QUERY)" --env .env.example --answer --limit 3 --pretty >/dev/null; \
		echo "Quality profile ran deterministic local evaluator. Set QUALITY_INFRA=1 with running services for hybrid infra checks."; \
	fi

live-agent:
	@test -n "$(LIVE_AGENT_TRANSCRIPT)" || { echo "ERROR: set LIVE_AGENT_TRANSCRIPT to a captured sandbox transcript path"; exit 2; }
	@test -f "$(LIVE_AGENT_TRANSCRIPT)" || { echo "ERROR: transcript not found: $(LIVE_AGENT_TRANSCRIPT)"; exit 2; }
	$(PY) -m okf_mcp.live_agent_gate "$(LIVE_AGENT_TRANSCRIPT)"

rag-check: validate
	@$(PY) -m okf_mcp rag inspect | $(PY) -c 'import json,sys; d=json.load(sys.stdin); print("RAG corpus: {} concepts, {} bytes -> {}".format(d["concept_count"], d["total_bytes"], d["artifacts_dir"]))'
	@$(PY) -m okf_mcp rag refresh | $(PY) -c 'import json,sys; d=json.load(sys.stdin); print("RAG index: {} chunks -> {}".format(d["chunk_count"], d["path"]))'
	@$(PY) -m okf_mcp rag retrieve "$(RAG_QUERY)" --limit 3 | $(PY) -c 'import json,sys; d=json.load(sys.stdin); print("RAG retrieve: {} hit(s) for {!r}".format(len(d["hits"]), d["query"]))'

indexes:
	$(PY) -m okf_mcp indexes $(BUNDLE)

graph:
	$(PY) -m okf_mcp graph $(BUNDLE) --out $(ARTIFACTS_DIR)/okf/graph.json --html-out $(ARTIFACTS_DIR)/okf/graph.html

7d-report:
	$(PY) -m okf_mcp 7d report --bundle $(BUNDLE)

7d-dashboard:
	$(PY) -m okf_mcp 7d dashboard --bundle $(BUNDLE) --out $(ARTIFACTS_DIR)/7d-dashboard.html

7d-validate:
	$(PY) -m okf_mcp 7d validate --bundle $(BUNDLE)

guard-artifacts-dir:
	@test "$(abspath $(ARTIFACTS_DIR))" = "$(abspath artifacts)" || { echo "ERROR: clean targets only support repository artifacts/; got ARTIFACTS_DIR=$(ARTIFACTS_DIR)"; exit 2; }

clean-artifacts: guard-artifacts-dir
	@rm -rf $(ARTIFACTS_DIR) .pytest_cache .mypy_cache .ruff_cache
	@rm -rf $(FRONTEND_DIR)/node_modules $(FRONTEND_DIR)/mcp-server/node_modules $(FRONTEND_DIR)/.pnpm-store $(FRONTEND_DIR)/dist $(FRONTEND_DIR)/dist-ssr $(FRONTEND_DIR)/coverage $(FRONTEND_DIR)/test-results $(FRONTEND_DIR)/playwright-report $(FRONTEND_DIR)/src-tauri/target
	@find okf_mcp tests -type d -name __pycache__ -prune -exec rm -rf {} +
	@find okf_mcp tests -type f \( -name '*.pyc' -o -name '*.pyo' \) -delete
	@echo "Generated artifacts removed."

clean-project reset-empty: guard-artifacts-dir
	@test "$(CONFIRM)" = "YES" || { echo "Destructive reset. Run: make clean-project CONFIRM=YES"; exit 2; }
	@mkdir -p $(OKF_DIRS)
	@find $(BUNDLE) -type f -name '*.md' ! -name index.md ! -name log.md -delete
	@rm -rf $(ARTIFACTS_DIR)
	@test -f $(BUNDLE)/log.md || printf '# Log\n\n' > $(BUNDLE)/log.md
	$(MAKE) indexes
	$(PY) -m okf_mcp validate $(BUNDLE)
	@echo "Project reset to an empty OKF bundle skeleton."
