# Local/shared config — always loaded. Keep remote credentials OUT of here;
# those live in .env.test / .env.prod. (docker compose also reads .env directly
# for ${UID}/${GID} substitution and the travel-memories env_file.)
-include .env

# Remote config — loaded only when targeting an environment. ENV is set
# automatically by the env-suffixed remote targets (e.g. `make remote-install-prod`);
# each .env.<ENV> holds a full, self-contained set of remote vars.
ENV ?=
-include .env.$(ENV)
export

REMOTE_PORT ?= 22
SSH := ssh -p $(REMOTE_PORT) $(REMOTE_USER)@$(REMOTE_HOST)
WEBROOT ?= $(REMOTE_HOME)/public_html
SITE_CONFIG_DIR ?= $(REMOTE_HOME)/site-config
# Hostname Grav uses to pick its per-environment config (user/env/<host>/).
# Defaults to the SSH host; override in .env.<ENV> only if the web hostname
# Grav sees differs from the SSH host (e.g. an addon domain on a shared box).
WEB_HOST ?= $(REMOTE_HOST)

# ── Environment guard + generated per-env remote targets ──────────────────────
# Every remote-* target below gains `-test` / `-prod` variants, e.g.
#   make remote-install-prod   →   runs remote-install with ENV=prod
# Calling a bare remote target (no ENV) fails via guard-env.
REMOTE_TARGETS := remote-env-setup remote-env-remove remote-wipe remote-install \
	remote-fetch remote-fetch-content remote-install-plugins remote-update-plugins \
	remote-upgrade-grav remote-git-sync-disable remote-git-sync-enable \
	remote-content-status remote-clean remote-diag remote-apply-env \
	remote-seed-api-salt remote-secrets-audit \
	remote-gpm-install remote-maintenance-on remote-maintenance-off \
	remote-apply-plugin-patches
ENVS := test prod

guard-env:
	@test -n "$(ENV)"      || { echo "ERROR: no environment. Use an env-suffixed target, e.g. 'make remote-install-prod'."; exit 1; }
	@test -f ".env.$(ENV)" || { echo "ERROR: missing .env.$(ENV)"; exit 1; }

define make-env-target
$(1)-$(2): ; @$$(MAKE) --no-print-directory $(1) ENV=$(2)
endef
$(foreach t,$(REMOTE_TARGETS),$(foreach e,$(ENVS),$(eval $(call make-env-target,$(t),$(e)))))

# ── Tests ─────────────────────────────────────────────────────────────────────

# Local test account — auto-created, never committed (see user/.gitignore).
# Keep the password free of shell/Make/URL-special chars so every consumer agrees.
GRAV_TEST_USER ?= testrunner
GRAV_TEST_PASS ?= Testpass1234

test-account:
	@docker exec intotheeast_grav sh -c 'test -f /var/www/html/user/accounts/$(GRAV_TEST_USER).yaml \
		|| php bin/plugin login new-user -u $(GRAV_TEST_USER) -p "$(GRAV_TEST_PASS)" \
		   -e $(GRAV_TEST_USER)@example.test -N "Test Runner" -P b --admin-type both -s enabled -n'

test-config:
	@bash scripts/test-form-config.sh

test-post: test-account
	@bash scripts/test-post.sh

test-ui: test-account
	@npx playwright test

test: test-config test-post test-ui

# ── Local dev ──────────────────────────────────────────────────────────────────

build:
	docker compose build

build-assets:
	docker run --rm \
	  -v $(PWD)/user/themes/intotheeast:/app \
	  -w /app node:20-alpine \
	  sh -c "npm install && npm run build"

start:
	docker compose up -d

stop:
	docker compose down

setup: build start install-plugins fix-perms

fix-perms:
	docker exec intotheeast_grav bash -c "getent passwd 1000 > /dev/null || useradd -u 1000 -M hostuser"
	docker exec intotheeast_grav chown -R 1000:1000 /var/www/html
	docker exec intotheeast_grav apachectl graceful


install-plugins:
	docker exec -w /var/www/html intotheeast_grav php bin/gpm install $(shell cat plugins.txt | tr '\n' ' ') -y
	$(MAKE) apply-plugin-patches

# Re-apply local fixes to git-ignored, GPM-managed third-party plugins. Run this
# AFTER install-plugins (which overwrites them). See deploy/patches/README.md.
apply-plugin-patches:
	@for p in deploy/patches/*.patch; do \
	  [ -f "$$p" ] || continue; \
	  if git apply --check "$$p" >/dev/null 2>&1; then \
	    git apply "$$p" && echo "applied $$p"; \
	  else \
	    echo "skipped $$p (already applied or does not match)"; \
	  fi; \
	done

# ── Demo content ──────────────────────────────────────────────────────────────

demo-load:
	# Load every fixture trip under docs/demo/trips/ into the pages tree.
	# Source uses dailies/ + 04.stories/; dailies/ maps to 01.dailies/ on copy.
	# All copies are `|| true` so a fixture absent from an older user/ is skipped.
	docker exec intotheeast_grav bash -c 'for src in /var/www/html/user/docs/demo/trips/*/; do \
		slug=$$(basename "$$src"); dst=/var/www/html/user/pages/01.trips/$$slug; \
		mkdir -p "$$dst/01.dailies" "$$dst/04.stories"; \
		cp "$$src/trip.md"    "$$dst/trip.md"               2>/dev/null || true; \
		cp "$$src/stories.md" "$$dst/04.stories/stories.md" 2>/dev/null || true; \
		cp -r "$$src/04.stories/." "$$dst/04.stories/"      2>/dev/null || true; \
		cp -r "$$src/dailies/."    "$$dst/01.dailies/"      2>/dev/null || true; \
		cp "$$src"/*.gpx "$$dst/"                           2>/dev/null || true; \
		chown -R 1000:1000 "$$dst"; \
	done; cd /var/www/html && php bin/grav clearcache'

demo-reset:
	docker exec intotheeast_grav bash -c 'for src in /var/www/html/user/docs/demo/trips/*/; do \
		rm -rf /var/www/html/user/pages/01.trips/$$(basename "$$src"); \
	done; cd /var/www/html && php bin/grav clearcache'

pixelfed-import:
	docker exec intotheeast_grav bash -c "which python3 || apt-get install -y python3 --no-install-recommends -q"
	docker cp /home/mischa/Nextcloud/Downloads/pixelfed/pixelfed-statuses.json intotheeast_grav:/tmp/pixelfed-statuses.json
	docker cp scripts/pixelfed-import.py intotheeast_grav:/tmp/pixelfed-import.py
	docker exec -w /var/www/html intotheeast_grav python3 /tmp/pixelfed-import.py

# ── Content sync (user repo ↔ Gitea) ──────────────────────────────────────────

content-push:
	git -C user push origin main

content-pull:
	git -C user pull origin main

# ── Remote credentials ─────────────────────────────────────────────────────────

remote-env-setup: guard-env
	@$(SSH) "printf 'GITEA_HOST=%s\nGITEA_USER=%s\nGITEA_TOKEN=%s\n' \
		'$(GITEA_HOST)' '$(GITEA_USER)' '$(GITEA_TOKEN)' > ~/.env-intotheeast && chmod 600 ~/.env-intotheeast"
	@echo "Credentials written to server. Run 'make remote-env-remove' when done."

remote-env-remove: guard-env
	@$(SSH) "rm -f ~/.env-intotheeast"
	@echo "Credentials removed from server."

# ── Remote: initial install ────────────────────────────────────────────────────

remote-wipe: guard-env
	$(SSH) "cd $(WEBROOT) && rm -rf assets backup bin cache images logs system tmp vendor webserver-configs index.php .htaccess CHANGELOG.md LICENSE.txt README.md"

remote-install: guard-env
	$(SSH) "WEBROOT=$(WEBROOT) \
		SITE_CONFIG_DIR=$(SITE_CONFIG_DIR) \
		USER_REPO=$(USER_REPO) \
		MAIN_REPO=$(MAIN_REPO) \
		GRAV_VERSION=$(GRAV_VERSION) \
		PLUGINS='$(shell cat plugins.txt | tr '\n' ' ')' \
		GITEA_HOST=$(GITEA_HOST) \
		GITEA_USER=$(GITEA_USER) \
		GITEA_TOKEN=$(GITEA_TOKEN) \
		bash -s" < scripts/server-install.sh

# ── Remote: ongoing maintenance ────────────────────────────────────────────────

remote-fetch: guard-env
	$(SSH) "git -C $(SITE_CONFIG_DIR) checkout main && git -C $(SITE_CONFIG_DIR) pull"

remote-fetch-content: guard-env
	$(SSH) "git -C $(WEBROOT)/user fetch origin main && git -C $(WEBROOT)/user sparse-checkout disable && git -C $(WEBROOT)/user reset --hard origin/main"

remote-install-plugins: guard-env
	$(SSH) "cd $(WEBROOT) && php bin/gpm index -f && php bin/gpm install $(shell cat plugins.txt | tr '\n' ' ') -y"
	$(MAKE) remote-apply-plugin-patches

remote-update-plugins: guard-env
	$(SSH) "cd $(WEBROOT) && php bin/gpm update -y && php bin/grav cache"
	$(MAKE) remote-apply-plugin-patches

# Re-apply local fixes to git-ignored, GPM-managed third-party plugins on the
# remote (pristine after a GPM install/update). Piped over SSH like the git-sync
# scripts — no scp. `--forward` makes it a no-op when already applied. Runs
# automatically after remote-install-plugins / remote-update-plugins; safe to run
# standalone. See deploy/patches/README.md.
remote-apply-plugin-patches: guard-env
	@for p in deploy/patches/*.patch; do \
	  [ -f "$$p" ] || continue; \
	  echo "remote-apply $$p"; \
	  $(SSH) "cd $(WEBROOT) && patch -p1 --forward -r - --no-backup-if-mismatch" < "$$p" || echo "  (already applied or no-op)"; \
	done
	$(SSH) "cd $(WEBROOT) && php bin/grav clearcache"

remote-upgrade-grav: guard-env
	$(SSH) "cd $(WEBROOT) && php bin/gpm self-upgrade -y && php bin/grav cache"

remote-git-sync-disable: guard-env
	$(SSH) "bash -s -- '$(WEBROOT)' false" < scripts/git-sync-toggle.sh

remote-git-sync-enable: guard-env
	$(SSH) "bash -s -- '$(WEBROOT)' true" < scripts/git-sync-toggle.sh

remote-content-status: guard-env
	$(SSH) "cd $(WEBROOT)/user && echo '--- HEAD ---' && git log -1 --oneline && echo '--- working tree ---' && git status --short && echo '--- config diff ---' && git diff -- config/ && echo '--- .gitignore diff ---' && git diff -- .gitignore"

remote-clean: guard-env
	$(SSH) "cd $(WEBROOT) && php bin/grav clearcache"

# Install a single GPM package on the server (e.g. git-sync, which is
# intentionally NOT in plugins.txt — it is remote-only).
# Usage: make remote-gpm-install-prod PKG=git-sync
remote-gpm-install: guard-env
	@test -n "$(PKG)" || { echo "ERROR: set PKG=<plugin-slug>"; exit 1; }
	$(SSH) "cd $(WEBROOT) && php bin/gpm index -f && php bin/gpm install $(PKG) -y && php bin/grav clearcache"

# Deploy per-environment Grav config overrides to the server's
# user/env/<WEB_HOST>/config/ tree (deep-merged over the committed config).
# Source of truth: deploy/env/$(ENV)/system.yaml (version-controlled). This
# tree is outside the content repo, so it is NOT restored by content sync —
# re-run after any fresh install.
remote-apply-env: guard-env
	@test -f deploy/env/$(ENV)/system.yaml || { echo "ERROR: missing deploy/env/$(ENV)/system.yaml"; exit 1; }
	@host="$${WEB_HOST:-$(REMOTE_HOST)}"; \
	  test -n "$$host" || { echo "ERROR: WEB_HOST/REMOTE_HOST unresolved"; exit 1; }; \
	  $(SSH) "mkdir -p $(WEBROOT)/user/env/$$host/config && cat > $(WEBROOT)/user/env/$$host/config/system.yaml && cd $(WEBROOT) && php bin/grav clearcache" < deploy/env/$(ENV)/system.yaml; \
	  echo "Applied deploy/env/$(ENV)/system.yaml -> $(WEBROOT)/user/env/$$host/config/system.yaml"

# Seed a per-host popularity salt into the env override tree so the api plugin
# reads it there instead of appending one to the git-tracked config/plugins/
# api.yaml. That appended salt kept the content working tree dirty, which broke
# git-sync's auto-merge on webhook. Salt is generated server-side and never
# committed (a committed salt would be globally known). Idempotent: an existing
# salt is kept, so re-running never rotates it.
remote-seed-api-salt: guard-env
	@host="$${WEB_HOST:-$(REMOTE_HOST)}"; \
	  test -n "$$host" || { echo "ERROR: WEB_HOST/REMOTE_HOST unresolved"; exit 1; }; \
	  $(SSH) "set -e; \
	    envfile=$(WEBROOT)/user/env/$$host/config/plugins/api.yaml; \
	    mkdir -p \$$(dirname \"\$$envfile\"); \
	    if grep -qE '^[[:space:]]*salt:' \"\$$envfile\" 2>/dev/null; then \
	      echo \"salt already present in \$$envfile — keeping it\"; \
	    else \
	      salt=\$$(openssl rand -hex 32); \
	      printf 'popularity:\n  salt: %s\n' \"\$$salt\" > \"\$$envfile\"; \
	      echo \"seeded new per-host salt into \$$envfile\"; \
	    fi; \
	    git -C $(WEBROOT)/user checkout -- config/plugins/api.yaml 2>/dev/null || true; \
	    cd $(WEBROOT) && php bin/grav clearcache >/dev/null 2>&1 || true; \
	    echo '--- base api.yaml status (expect clean) ---'; \
	    git -C $(WEBROOT)/user status --short config/plugins/api.yaml; \
	    echo '(if the line above is empty, the tree is clean)'"

# Read-only health check: plugin install state, versions, key config, log tail.
remote-diag: guard-env
	$(SSH) "cd $(WEBROOT) && \
		echo '=== Grav version ==='; php bin/grav --version 2>/dev/null; \
		echo '=== installed plugin versions ==='; for p in login admin2 flex-objects form api; do printf '%s: ' \"\$$p\"; grep -m1 '^version:' user/plugins/\$$p/blueprints.yaml 2>/dev/null || echo '(NOT installed)'; done; \
		echo '=== what does GPM say about api? ==='; php bin/gpm info api 2>&1 | head -12; \
		echo '=== api override (enabled/route/session) ==='; grep -nE '^enabled:|^route:|session_enabled:' user/config/plugins/api.yaml 2>&1; \
		echo '=== per-env override present? ==='; for f in user/env/*/config/system.yaml; do echo \"\$$f:\"; cat \"\$$f\" 2>/dev/null | grep -E 'cache:|debug:|auto_reload:'; done; \
		echo '=== twig cache populating? (non-empty => cache on) ==='; ls cache/twig/ 2>/dev/null | head -1 || echo '(empty)'; \
		echo '=== git-sync config (secrets redacted) ==='; grep -vaiE 'password|token|secret' user/config/plugins/git-sync.yaml user/env/*/config/plugins/git-sync.yaml 2>/dev/null; \
		echo '=== grav.log tail ==='; tail -8 logs/grav.log 2>/dev/null"

# Secret-safe audit: lists WHERE per-host secret/config files live (config/ vs
# env/<host>/config/) and their sizes — never prints contents. Used to decide
# whether a `reset --hard` would clobber a live runtime secret.
remote-secrets-audit: guard-env
	$(SSH) "cd $(WEBROOT)/user && \
		echo '=== tracked in git? (git ls-files) ==='; git ls-files config/security-private.php config/security.yaml config/versions.yaml config/plugins/api-private.php config/plugins/git-sync.yaml; \
		echo '=== config/ copies (size only) ==='; ls -la config/security.yaml config/security-private.php config/versions.yaml config/plugins/api-private.php config/plugins/git-sync.yaml 2>&1; \
		echo '=== env/<host>/config copies (size only) ==='; ls -la env/*/config/security.yaml env/*/config/security-private.php env/*/config/plugins/api-private.php env/*/config/plugins/git-sync.yaml 2>&1; \
		echo '=== does security.yaml reference the private php? (key names only) ==='; grep -aoE '^[a-z_]+:' config/security.yaml 2>/dev/null; for f in env/*/config/security.yaml; do echo \"\$$f:\"; grep -aoE '^[a-z_]+:' \"\$$f\" 2>/dev/null; done; true"

remote-maintenance-on: guard-env
	$(SSH) "bash -s on $(WEBROOT)" < scripts/server-maintenance.sh

remote-maintenance-off: guard-env
	$(SSH) "bash -s off $(WEBROOT)" < scripts/server-maintenance.sh
