.DEFAULT_GOAL := help

UV          := $(shell command -v uv 2>/dev/null)
PROJECT_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
USER        := $(shell id -un)
PORT        ?= 8000
SERVICE     := osiris
UNIT_FILE   := /etc/systemd/system/$(SERVICE).service
CRON_SCHED  ?= * * * * *
CRON_LOG    ?= $(PROJECT_DIR)/reminders.log
MANAGE      := $(UV) run python manage.py
# The reminder job as one line: cron's environment is nearly empty, so uv is
# called by absolute path and loads .env (VAPID keys) itself via --env-file.
# --no-sync: don't resolve dependencies (needs network) on a cron tick.
REMINDER_CMD := cd $(PROJECT_DIR) && $(UV) run --no-sync --env-file .env python manage.py send_reminders

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

# --- Setup -----------------------------------------------------------------

.PHONY: install
install: check-uv frontend ## Install dependencies, build the frontend, migrate, collect static files
	$(UV) sync
	@$(MAKE) --no-print-directory env   # after sync: it needs Django importable
	$(MANAGE) migrate
	$(MANAGE) collectstatic --noinput
	@echo "Installed. Next: 'make superuser' (once), then 'make service' and 'make cron'."

.PHONY: check-uv
check-uv:
	@test -n "$(UV)" || { echo "uv is not installed: https://docs.astral.sh/uv/"; exit 1; }

.PHONY: env
env: ## Create .env with a fresh SECRET_KEY and VAPID keys (keeps an existing one)
	@if [ -f .env ]; then \
		echo ".env already exists — leaving it alone."; \
	else \
		cp .env.example .env; \
		secret=$$($(UV) run python -c "import secrets; print(secrets.token_urlsafe(64))"); \
		sed -i "s|^DJANGO_SECRET_KEY=.*|DJANGO_SECRET_KEY=$$secret|" .env; \
		$(MAKE) --no-print-directory vapid; \
		echo "Wrote .env — review DJANGO_ALLOWED_HOSTS before going live."; \
	fi

.PHONY: vapid
vapid: ## Generate VAPID keys and write them into .env
	@test -f .env || cp .env.example .env
	@keys=$$($(MANAGE) generate_vapid_keys 2>/dev/null | grep '^VAPID_'); \
	pub=$$(echo "$$keys" | grep '^VAPID_PUBLIC_KEY=' | cut -d= -f2); \
	priv=$$(echo "$$keys" | grep '^VAPID_PRIVATE_KEY=' | cut -d= -f2); \
	test -n "$$pub" || { echo "Key generation failed."; exit 1; }; \
	sed -i "s|^VAPID_PUBLIC_KEY=.*|VAPID_PUBLIC_KEY=$$pub|" .env; \
	sed -i "s|^VAPID_PRIVATE_KEY=.*|VAPID_PRIVATE_KEY=$$priv|" .env; \
	echo "VAPID keys written to .env. Restart the service, then re-enable reminders on each device."

.PHONY: superuser
superuser: ## Create the login account (there is no registration)
	$(MANAGE) createsuperuser

# --- systemd ---------------------------------------------------------------

.PHONY: service
service: ## Install, enable and start the systemd service (needs sudo)
	@sed -e 's|__USER__|$(USER)|g' \
	     -e 's|__PROJECT_DIR__|$(PROJECT_DIR)|g' \
	     -e 's|__UV__|$(UV)|g' \
	     -e 's|__PORT__|$(PORT)|g' \
	     deploy/osiris.service.template > /tmp/$(SERVICE).service
	sudo install -m 644 /tmp/$(SERVICE).service $(UNIT_FILE)
	@rm -f /tmp/$(SERVICE).service
	sudo systemctl daemon-reload
	sudo systemctl enable --now $(SERVICE)
	@sudo systemctl --no-pager --lines=0 status $(SERVICE) || true

.PHONY: restart
restart: ## Restart the service (do this after changing .env)
	sudo systemctl restart $(SERVICE)

.PHONY: logs
logs: ## Follow the service log
	journalctl -u $(SERVICE) -f

.PHONY: service-uninstall
service-uninstall: ## Stop and remove the systemd service
	-sudo systemctl disable --now $(SERVICE)
	sudo rm -f $(UNIT_FILE)
	sudo systemctl daemon-reload

# --- cron ------------------------------------------------------------------

# 'send[-_]reminders' is the marker identifying our line, so reinstalling stays
# idempotent and also cleans up entries from the old wrapper-script era.
.PHONY: cron
cron: ## Install the reminder cron job (idempotent)
	@( crontab -l 2>/dev/null | grep -vE 'send[-_]reminders' ; \
	   echo "$(CRON_SCHED) $(REMINDER_CMD) >> $(CRON_LOG) 2>&1" ) | crontab -
	@echo "Installed:"
	@crontab -l | grep -F 'send_reminders'

.PHONY: cron-remove
cron-remove: ## Remove the reminder cron job
	@crontab -l 2>/dev/null | grep -vE 'send[-_]reminders' | crontab -
	@echo "Removed."

.PHONY: cron-test
cron-test: ## Run the reminder job once, reporting what it would send
	@$(REMINDER_CMD) --dry-run

# --- Frontend --------------------------------------------------------------

.PHONY: frontend
frontend: ## Install frontend dependencies (pnpm) and build the Vue frontend
	cd frontend && pnpm install && pnpm run build

# Only build when no bundle exists yet: tests render the shell template, which
# needs the Vite manifest, but should not pay for a rebuild on every run.
frontend/dist/.vite/manifest.json:
	@$(MAKE) --no-print-directory frontend

.PHONY: front-dev
front-dev: ## Run the Vite dev server with hot reload (pair with: DJANGO_VITE_DEV=1 make run)
	cd frontend && pnpm run dev

.PHONY: api-client
api-client: ## Regenerate the typed TS API client (needs 'make run' in another terminal)
	cd frontend && pnpm run generate:api

# --- Development -----------------------------------------------------------

.PHONY: run
run: ## Run the development server
	$(MANAGE) runserver $(PORT)

.PHONY: test
test: frontend/dist/.vite/manifest.json ## Run the test suite
	$(MANAGE) test

.PHONY: lint
lint: ## Check formatting and lints
	$(UV) run ruff format --check .
	$(UV) run ruff check .

.PHONY: format
format: ## Reformat and autofix
	$(UV) run ruff format .
	$(UV) run ruff check --fix .

.PHONY: deploy
deploy: install restart ## Pull dependencies, migrate, collect static, restart
	@echo "Deployed."
