# Homelab Blueprint Makefile

.PHONY: help check-env status deploy-caddy deploy-ha deploy-arr deploy-immich deploy-dns deploy-postgres deploy-gramps deploy-beszel deploy-beszel-hub deploy-proxy deploy-youtarr deploy-bento-pdf deploy-it-tools deploy-paperless deploy-vaultwarden deploy-koffan deploy-forgejo

# Default shell
SHELL := /bin/bash

# Configuration
ENV_FILE ?= .env
STACKS_DIR := docker-compose-files
SUBSTITUTE_SCRIPT := ./substitute_env.sh

help:
	@echo "Homelab Blueprint Management"
	@echo ""
	@echo "Usage: make <target>"
	@echo ""
	@echo "Deploy Targets:"
	@echo "  deploy-caddy      - Deploy Caddy Reverse Proxy"
	@echo "  deploy-ha         - Deploy Home Assistant (uses setup script)"
	@echo "  deploy-arr        - Deploy Arr Stack (Media Management)"
	@echo "  deploy-immich     - Deploy Immich (Photos)"
	@echo "  deploy-dns        - Deploy Technitium DNS"
	@echo "  deploy-postgres   - Deploy PostgreSQL"
	@echo "  deploy-gramps     - Deploy Gramps Web"
	@echo "  deploy-beszel     - Deploy Beszel Agent"
	@echo "  deploy-beszel-hub - Deploy Beszel Hub (dashboard)"
	@echo "  deploy-proxy      - Deploy Beszel Socket Proxy"
	@echo "  deploy-youtarr    - Deploy Youtarr"
	@echo "  deploy-bento-pdf  - Deploy BentoPDF"
	@echo "  deploy-it-tools   - Deploy IT-Tools"
	@echo "  deploy-paperless  - Deploy Paperless-ngx"
	@echo "  deploy-vaultwarden - Deploy Vaultwarden"
	@echo "  deploy-koffan     - Deploy Koffan (grocery list)"
	@echo "  deploy-forgejo    - Deploy Forgejo (self-hosted Git)"
	@echo ""
	@echo "Utility Targets:"
	@echo "  status            - Show status of all deployed stacks"
	@echo "  check-env         - Validate .env file against templates"
	@echo "  ip-check          - Check IP leak protection for VPN containers"
	@echo "  clean             - Remove generated docker-compose.*.yml files"

check-env:
	@target_dir=$$( [ -n "$(STACK)" ] && echo "$(STACKS_DIR)/$(STACK)" || echo "$(STACKS_DIR)/*" ); \
	for dir in $$target_dir; do \
		if [ -d "$$dir" ]; then \
			stack=$$(basename $$dir); \
			local_env="$$dir/.env"; \
			placeholders=$$(find "$$dir" -type f \( -name '*template*' -o -name '*.yaml' -o -name '*.yml' \) -print0 | \
				xargs -0 awk '!/^[[:space:]]*#/ { while (match($$0, /\{\{[A-Za-z_][A-Za-z0-9_]*\}\}/)) { print substr($$0, RSTART + 2, RLENGTH - 4); $$0 = substr($$0, RSTART + RLENGTH) } }' | \
				sort -u || true); \
			if [ -n "$$placeholders" ]; then \
				echo "Validating environment for: $$stack"; \
				ERR=0; \
				for var in $$placeholders; do \
					if ! grep -qE "^$${var}=" $(ENV_FILE) 2>/dev/null && ! grep -qE "^$${var}=" "$$local_env" 2>/dev/null; then \
						echo "  [MISSING] $$var"; \
						ERR=1; \
					fi; \
				done; \
				if [ $$ERR -eq 1 ]; then echo "Error: Missing variables for $$stack. Check your .env files."; exit 1; fi; \
			fi; \
		fi; \
	done

status:
	@echo "--- Stack Status ---"
	@for f in docker-compose.*.yml; do \
		if [ -f "$$f" ]; then \
			echo "Stack: $$f"; \
			docker compose -f "$$f" ps; \
			echo ""; \
		fi \
	done

ip-check:
	@test -x ./ipfconfig || { echo "Error: ipfconfig script not found or not executable." >&2; exit 1; }
	@./ipfconfig

clean:
	@echo "Removing generated compose files..."
	@rm -f docker-compose.*.yml

# Individual Stack Deployments
#
# deploy_stack(stack-dir, compose-suffix) - shared recipe for the common case:
#   check-env -> substitute template -> docker compose up -d
define deploy_stack
@$(MAKE) check-env STACK=$(1)
@echo "Deploying $(1)..."
@$(SUBSTITUTE_SCRIPT) $(STACKS_DIR)/$(1)/template.yaml docker-compose.$(2).yml $(ENV_FILE) $(STACKS_DIR)/$(1)/.env
@docker compose -f docker-compose.$(2).yml up -d
endef

# Caddy is special: also renders the Caddyfile and forces an image rebuild.
deploy-caddy:
	@$(MAKE) check-env STACK=caddy
	@echo "Deploying Caddy..."
	@$(SUBSTITUTE_SCRIPT) $(STACKS_DIR)/caddy/Caddyfile_template $(STACKS_DIR)/caddy/Caddyfile $(ENV_FILE) $(STACKS_DIR)/caddy/.env
	@$(SUBSTITUTE_SCRIPT) $(STACKS_DIR)/caddy/template.yaml docker-compose.caddy.yml $(ENV_FILE) $(STACKS_DIR)/caddy/.env
	@chmod 644 $(STACKS_DIR)/caddy/Caddyfile
	@docker compose -f docker-compose.caddy.yml up -d --build

# HA uses an external setup script instead of substitute_env.sh.
deploy-ha:
	@test -x ./setup-homeassistant.sh || { echo "Error: setup-homeassistant.sh not found or not executable." >&2; exit 1; }
	@$(MAKE) check-env STACK=homeassistant
	@echo "Deploying Home Assistant..."
	@./setup-homeassistant.sh
	@docker compose -f docker-compose.homeassistant.yml up -d

deploy-arr:
	$(call deploy_stack,arr-stack,arr-stack)

deploy-immich:
	$(call deploy_stack,immich,immich)

deploy-dns:
	$(call deploy_stack,technitium,technitium)

deploy-postgres:
	$(call deploy_stack,postgres,postgres)

deploy-gramps:
	@$(MAKE) check-env STACK=gramps-web
	@echo "Deploying gramps-web..."
	@mkdir -p gramps_config
	@$(SUBSTITUTE_SCRIPT) $(STACKS_DIR)/gramps-web/config/config_template.cfg gramps_config/config.cfg $(ENV_FILE) $(STACKS_DIR)/gramps-web/.env
	@$(SUBSTITUTE_SCRIPT) $(STACKS_DIR)/gramps-web/template.yaml docker-compose.gramps.yml $(ENV_FILE) $(STACKS_DIR)/gramps-web/.env
	@docker compose -f docker-compose.gramps.yml up -d

deploy-beszel:
	$(call deploy_stack,beszel-agent,beszel)

deploy-beszel-hub:
	$(call deploy_stack,beszel-hub,beszel-hub)

deploy-bento-pdf:
	$(call deploy_stack,bento-pdf,bento-pdf)

deploy-it-tools:
	$(call deploy_stack,it-tools,it-tools)

deploy-paperless:
	$(call deploy_stack,paperless-ngx,paperless)

deploy-vaultwarden:
	$(call deploy_stack,vaultwarden,vaultwarden)

deploy-koffan:
	$(call deploy_stack,koffan,koffan)

deploy-proxy:
	$(call deploy_stack,socket-proxy,proxy)

deploy-forgejo:
	$(call deploy_stack,forgejo,forgejo)

deploy-youtarr:
	$(call deploy_stack,youtarr,youtarr)

reload-caddy:
	@docker compose -f docker-compose.caddy.yml ps --status running --services 2>/dev/null | grep -q '^caddy$$' \
		|| { echo "Error: Caddy container is not running. Run 'make deploy-caddy' first." >&2; exit 1; }
	@$(MAKE) check-env STACK=caddy
	@echo "Performing zero-downtime Caddy reload..."
	@$(SUBSTITUTE_SCRIPT) $(STACKS_DIR)/caddy/Caddyfile_template $(STACKS_DIR)/caddy/Caddyfile $(ENV_FILE) $(STACKS_DIR)/caddy/.env
	@chmod 644 $(STACKS_DIR)/caddy/Caddyfile
	@docker compose -f docker-compose.caddy.yml exec caddy caddy validate --config /etc/caddy/Caddyfile
	@docker compose -f docker-compose.caddy.yml exec caddy caddy reload --config /etc/caddy/Caddyfile
