# Chanakya agent launcher
#
# Run from the PROJECT ROOT:
#   make gmail

ROOT ?= .

# ── Ports / hosts (mirror AGENT_REGISTRY defaults in config.py) ───────────
GMAIL_AGENT_HOST ?= 0.0.0.0
GMAIL_AGENT_PORT ?= 8001

JIRA_AGENT_HOST  ?= 0.0.0.0
JIRA_AGENT_PORT  ?= 8002

USER_AWARE_AGENT_HOST ?= 0.0.0.0
USER_AWARE_AGENT_PORT ?= 8003

INSURANCE_AGENT_HOST ?= 0.0.0.0
INSURANCE_AGENT_PORT ?= 8004

TATASTEEL_AGENT_HOST ?= 0.0.0.0
TATASTEEL_AGENT_PORT ?= 7005

UI_AGENT_HOST ?= 0.0.0.0
UI_AGENT_PORT ?= 7011

CHANAKYA_UI_PORT ?= 7010

# Uvicorn flags
RELOAD   ?= --reload
LOG_LEVEL ?= info

# Logs directory
LOGS_DIR = logs

# ── Derived uvicorn base command ───────────────────────────────────────────
UVICORN = uvicorn

.PHONY: gmail jira user-aware insurance tatasteel ui-agent agents stop \
        chanakya-ui ui \
        docker-build docker-up docker-up-github docker-ui \
        docker-run docker-run-github docker-down docker-logs \
        docs-md-diff docs-md-merge docs-md-sync docs-md-sync-commit docs-md-clean \
        help


# ── Individual agents ──────────────────────────────────────────────────────

## gmail  : Launch the Gmail A2A agent (port $(GMAIL_AGENT_PORT))
gmail:
	@set -a && . ./.env && set +a; \
	$(UVICORN) backend.chanakya.gmail.agent:app \
		--host $(GMAIL_AGENT_HOST) \
		--port $(GMAIL_AGENT_PORT) \
		--log-level $(LOG_LEVEL) \
		$(RELOAD)

## jira   : Launch the Jira A2A agent (port $(JIRA_AGENT_PORT))
jira:
	@set -a && . ./.env && set +a; \
	$(UVICORN) backend.chanakya.jira.agent:app \
		--host $(JIRA_AGENT_HOST) \
		--port $(JIRA_AGENT_PORT) \
		--log-level $(LOG_LEVEL) \
		$(RELOAD)

## user-aware : Launch the User Aware A2A agent (port $(USER_AWARE_AGENT_PORT))
user-aware:
	@set -a && . ./.env && set +a; \
	$(UVICORN) backend.chanakya.user_aware.agent:app \
		--host $(USER_AWARE_AGENT_HOST) \
		--port $(USER_AWARE_AGENT_PORT) \
		--log-level $(LOG_LEVEL) \
		$(RELOAD)

## insurance : Launch the Insurance DB A2A agent (port $(INSURANCE_AGENT_PORT))
insurance:
	@set -a && . ./.env && set +a; \
	INSURANCE_AGENT_HOST=$(INSURANCE_AGENT_HOST) \
	INSURANCE_AGENT_PORT=$(INSURANCE_AGENT_PORT) \
	$(UVICORN) backend.chanakya.insurance.agent:app \
		--host $(INSURANCE_AGENT_HOST) \
		--port $(INSURANCE_AGENT_PORT) \
		--log-level $(LOG_LEVEL) \
		$(RELOAD)

## tatasteel : Launch the Tatasteel DB A2A agent (port $(TATASTEEL_AGENT_PORT))
tatasteel:
	@set -a && . ./.env && set +a; \
	TATASTEEL_AGENT_HOST=$(TATASTEEL_AGENT_HOST) \
	TATASTEEL_AGENT_PORT=$$TATASTEEL_AGENT_PORT \
	$(UVICORN) backend.chanakya.tatasteel.server:app \
		--host $(TATASTEEL_AGENT_HOST) \
		--port $$TATASTEEL_AGENT_PORT \
		--log-level $(LOG_LEVEL) \
		$(RELOAD)

## ui-agent : Launch the UI Agent (port $(UI_AGENT_PORT))
ui-agent:
	@set -a && . ./.env && set +a; \
	UI_AGENT_HOST=$(UI_AGENT_HOST) \
	UI_AGENT_PORT=$$UI_AGENT_PORT \
	$(UVICORN) backend.chanakya.ui_agent.agent:app \
		--host $(UI_AGENT_HOST) \
		--port $$UI_AGENT_PORT \
		--log-level $(LOG_LEVEL) \
		$(RELOAD)

# ── Combined launchers ─────────────────────────────────────────────────────

## agents : Launch Tatasteel + UI agents in the background
agents:
	@echo "Starting Tatasteel agent on port $(TATASTEEL_AGENT_PORT) …"
	@set -a && . ./.env && set +a; \
	TATASTEEL_AGENT_HOST=$(TATASTEEL_AGENT_HOST) \
	TATASTEEL_AGENT_PORT=$$TATASTEEL_AGENT_PORT \
	$(UVICORN) backend.chanakya.tatasteel.server:app \
		--host $(TATASTEEL_AGENT_HOST) --port $$TATASTEEL_AGENT_PORT \
		--log-level $(LOG_LEVEL) $(RELOAD) & \
	echo "Starting UI agent on port $$UI_AGENT_PORT …"; \
	UI_AGENT_HOST=$(UI_AGENT_HOST) \
	UI_AGENT_PORT=$$UI_AGENT_PORT \
	$(UVICORN) backend.chanakya.ui_agent.agent:app \
		--host $(UI_AGENT_HOST) --port $$UI_AGENT_PORT \
		--log-level $(LOG_LEVEL) $(RELOAD) &
	@echo "Agents running. Use 'make stop' to terminate."
	@wait

## chanakya-ui : Run Chanakya A2A + pylogue chat on port $(CHANAKYA_UI_PORT)
chanakya-ui:
	@set -a && . ./.env && set +a; \
	$(UVICORN) backend.chanakya.rt_agent.server:app \
		--host 0.0.0.0 --port $$CHANAKYA_UI_PORT \
		--log-level $(LOG_LEVEL)

## ui     : Launch Tatasteel + UI agents + Chanakya UI; Ctrl+C kills everything
ui:
	@set -a && . ./.env && set +a; \
	trap 'echo "Shutting down…"; kill 0' INT TERM; \
	echo "Starting Tatasteel agent → http://$(TATASTEEL_AGENT_HOST):$$TATASTEEL_AGENT_PORT/chat"; \
	TATASTEEL_AGENT_HOST=$(TATASTEEL_AGENT_HOST) TATASTEEL_AGENT_PORT=$$TATASTEEL_AGENT_PORT \
	$(UVICORN) backend.chanakya.tatasteel.server:app \
		--host $(TATASTEEL_AGENT_HOST) --port $$TATASTEEL_AGENT_PORT \
		--log-level $(LOG_LEVEL) $(RELOAD) & \
	echo "Starting UI agent          → http://$(UI_AGENT_HOST):$$UI_AGENT_PORT/"; \
	UI_AGENT_HOST=$(UI_AGENT_HOST) UI_AGENT_PORT=$$UI_AGENT_PORT \
	$(UVICORN) backend.chanakya.ui_agent.agent:app \
		--host $(UI_AGENT_HOST) --port $$UI_AGENT_PORT \
		--log-level $(LOG_LEVEL) $(RELOAD) & \
	echo "Starting Chanakya UI       → http://0.0.0.0:$$CHANAKYA_UI_PORT/chat"; \
	$(UVICORN) backend.chanakya.rt_agent.server:app \
		--host 0.0.0.0 --port $$CHANAKYA_UI_PORT \
		--log-level $(LOG_LEVEL) $(RELOAD) & \
	wait

# ── Utilities ──────────────────────────────────────────────────────────────

## stop   : Kill all uvicorn processes started by this Makefile
stop:
	@echo "Stopping uvicorn processes …"
	@pkill -f "uvicorn backend.chanakya" && echo "Done." || echo "No matching processes found."

# ── Docker Compose ──────────────────────────────────────────────────────────
COMPOSE = docker compose

## docker-build : Build all Docker images
docker-build:
	$(COMPOSE) build

## docker-up         : Build + start all 3 services detached (local pylogue via override)
docker-up:
	$(COMPOSE) up --build -d

## docker-up-github  : Same but skips override, uses GitHub-pinned pylogue
docker-up-github:
	$(COMPOSE) -f docker-compose.yml up --build -d

## docker-ui    : Alias for docker-up (all services expose /chat)
docker-ui: docker-up

## docker-run        : Build + start attached, log to logs/YYYYMMDD-HHMMSS.log (local pylogue)
docker-run:
	@mkdir -p $(LOGS_DIR)
	@logfile=$(LOGS_DIR)/$$(date +%Y%m%d-%H%M%S).log; \
	 echo "Logging to $$logfile"; \
	 $(COMPOSE) up --build 2>&1 | tee "$$logfile"

## docker-run-github : Same but skips override, uses GitHub-pinned pylogue
docker-run-github:
	@mkdir -p $(LOGS_DIR)
	@logfile=$(LOGS_DIR)/$$(date +%Y%m%d-%H%M%S).log; \
	 echo "Logging to $$logfile"; \
	 $(COMPOSE) -f docker-compose.yml up --build 2>&1 | tee "$$logfile"

## docker-down  : Stop and remove all containers
docker-down:
	$(COMPOSE) down

## docker-logs  : Tail logs for all running services, write to logs/YYYYMMDD-HHMMSS.log
docker-logs:
	@mkdir -p $(LOGS_DIR)
	@logfile=$(LOGS_DIR)/$$(date +%Y%m%d-%H%M%S).log; \
	 echo "Logging to $$logfile"; \
	 $(COMPOSE) logs -f 2>&1 | tee "$$logfile"

## help   : Show this help message
help:
	@echo ""
	@echo "Usage: make <recipe>"
	@echo ""
	@grep -E '^##' $(MAKEFILE_LIST) | sed 's/## /  /'
	@echo ""
	@echo "Overridable variables (bare-metal):"
	@echo "  ROOT               Project root directory  (default: .)"
	@echo "  GMAIL_AGENT_HOST   Gmail bind host         (default: 0.0.0.0)"
	@echo "  GMAIL_AGENT_PORT   Gmail A2A + chat port   (default: 8001)"
	@echo "  JIRA_AGENT_HOST         Jira bind host               (default: 0.0.0.0)"
	@echo "  JIRA_AGENT_PORT         Jira A2A + chat port         (default: 8002)"
	@echo "  USER_AWARE_AGENT_HOST   User Aware bind host         (default: 0.0.0.0)"
	@echo "  USER_AWARE_AGENT_PORT   User Aware A2A + chat port   (default: 8003)"
	@echo "  CHANAKYA_UI_PORT        Chanakya UI port             (default: 8010)"
	@echo "  RELOAD             Uvicorn reload flag      (default: --reload)"
	@echo "  LOG_LEVEL          Uvicorn log level        (default: info)"
	@echo ""
	@echo "Docker Compose env vars (set in <root>/.env or export before running):"
	@echo "  LITELLM_PROVIDER_BASE_URL    LiteLLM proxy URL"
	@echo "  LITELLM_PROVIDER_MODEL_NAME  Model name string"
	@echo "  LOGFIRE_TOKEN                Logfire observability token (optional)"
	@echo ""

preview:
	# kill any existing process on port 23131
	@lsof -ti:23131 | xargs -r kill -9
	vyasa > /dev/null 2>&1 &

DOCS_BRANCH ?= docs/main
SOURCE_BRANCH ?= HEAD

## docs-md-diff  : Show .md files that differ between $(DOCS_BRANCH) and $(SOURCE_BRANCH)
docs-md-diff:
	@files=$$(git diff --name-only --diff-filter=ACMRD $(DOCS_BRANCH)..$(SOURCE_BRANCH) -- '*.md'); \
	if [ -z "$$files" ]; then \
		echo "No Markdown changes to sync from $(SOURCE_BRANCH) into $(DOCS_BRANCH)."; \
	else \
		printf '%s\n' "$$files"; \
	fi

## docs-md-merge : On $(DOCS_BRANCH), copy only .md files from $(SOURCE_BRANCH)
docs-md-merge:
	@current_branch=$$(git rev-parse --abbrev-ref HEAD); \
	if [ "$$current_branch" != "$(DOCS_BRANCH)" ]; then \
		echo "Switch to $(DOCS_BRANCH) before running this target."; exit 1; \
	fi; \
	files=$$(git diff --name-only --diff-filter=ACMRD $(DOCS_BRANCH)..$(SOURCE_BRANCH) -- '*.md'); \
	if [ -z "$$files" ]; then \
		echo "No Markdown changes to sync from $(SOURCE_BRANCH) into $(DOCS_BRANCH)."; exit 0; \
	fi; \
	printf '%s\n' "$$files" | while IFS= read -r file; do \
		if git cat-file -e $(SOURCE_BRANCH):"$$file" 2>/dev/null; then \
			git checkout $(SOURCE_BRANCH) -- "$$file"; \
		else \
			rm -f "$$file"; \
		fi; \
	done; \
	echo "Synced Markdown files from $(SOURCE_BRANCH) into $(DOCS_BRANCH):"; \
	printf '%s\n' "$$files"

## docs-md-sync  : From any branch, sync only .md files into $(DOCS_BRANCH) and return
docs-md-sync:
	@source_branch=$$(git rev-parse --abbrev-ref HEAD); \
	if [ "$$source_branch" = "$(DOCS_BRANCH)" ]; then \
		echo "Already on $(DOCS_BRANCH); use 'make docs-md-merge SOURCE_BRANCH=<branch>'."; exit 1; \
	fi; \
	temp_worktree=$$(mktemp -d /tmp/docs-main-sync.XXXXXX); \
	trap 'git worktree remove --force "$$temp_worktree" >/dev/null 2>&1; rm -rf "$$temp_worktree"' EXIT INT TERM; \
	git worktree add --detach "$$temp_worktree" $(DOCS_BRANCH) >/dev/null; \
	files=$$(git -C "$$temp_worktree" diff --name-only --diff-filter=ACMRD $(DOCS_BRANCH).."$$source_branch" -- '*.md'); \
	if [ -z "$$files" ]; then \
		echo "No Markdown changes to sync from $$source_branch into $(DOCS_BRANCH)."; exit 0; \
	fi; \
	printf '%s\n' "$$files" | while IFS= read -r file; do \
		if git -C "$$temp_worktree" cat-file -e "$$source_branch":"$$file" 2>/dev/null; then \
			git -C "$$temp_worktree" checkout "$$source_branch" -- "$$file"; \
		else \
			rm -f "$$temp_worktree/$$file"; \
		fi; \
	done; \
	echo "Synced Markdown files from $$source_branch into $(DOCS_BRANCH) at $$temp_worktree:"; \
	printf '%s\n' "$$files"

## docs-md-sync-commit : Sync only .md files into $(DOCS_BRANCH) and commit the result
docs-md-sync-commit:
	@source_branch=$$(git rev-parse --abbrev-ref HEAD); \
	temp_worktree=$$(mktemp -d /tmp/docs-main-sync.XXXXXX); \
	trap 'git worktree remove --force "$$temp_worktree" >/dev/null 2>&1; rm -rf "$$temp_worktree"' EXIT INT TERM; \
	git worktree add "$$temp_worktree" $(DOCS_BRANCH) >/dev/null; \
	files=$$(git -C "$$temp_worktree" diff --name-only --diff-filter=ACMRD $(DOCS_BRANCH).."$$source_branch" -- '*.md'); \
	if [ -z "$$files" ]; then echo "No Markdown changes to sync from $$source_branch into $(DOCS_BRANCH)."; exit 0; fi; \
	printf '%s\n' "$$files" | while IFS= read -r file; do \
		if git -C "$$temp_worktree" cat-file -e "$$source_branch":"$$file" 2>/dev/null; then git -C "$$temp_worktree" checkout "$$source_branch" -- "$$file"; else rm -f "$$temp_worktree/$$file"; fi; \
	done; \
	git -C "$$temp_worktree" add --all -- '*.md'; \
	git -C "$$temp_worktree" commit -m "docs: sync markdown from $$source_branch"; \
	echo "Committed Markdown sync onto $(DOCS_BRANCH) from $$source_branch."

## docs-md-clean : Remove leaked temporary docs sync worktrees under /tmp
docs-md-clean:
	@for path in $$(git worktree list --porcelain | awk '/^worktree \/private\/tmp\/docs-main-sync\./{print $$2}'); do \
		git worktree remove --force "$$path" >/dev/null 2>&1 || true; \
		rm -rf "$$path"; \
		echo "Removed $$path"; \
	done
