#!/usr/bin/env bash
# Deploy the full stack to ambrosio.
#
# Usage:  infra/scripts/deploy-erosi.sh
# Env:    DEPLOY_HOST=ambrosio (override if needed)
#         DEPLOY_PATH=/opt/colectivo
#
# First run:
#   1. rsyncs repo → ambrosio:/opt/colectivo/
#   2. if .env doesn't exist on server, generates secrets and writes it with
#      placeholder values the operator must fill in (external Keycloak URL,
#      Keycloak client secret)
#   3. docker compose build + up -d
#   4. applies DB migrations
#
# Internal edge is a Caddy container listening on host port 3000 — the
# external proxy (TLS terminator, off-stack) forwards plain HTTP to
# ambrosio:3000. This script never touches the host reverse-proxy config —
# it only manages the Docker stack.
#
# Subsequent runs: rsync + rebuild app + rolling restart.

set -euo pipefail

DEPLOY_HOST="${DEPLOY_HOST:-ambrosio}"
DEPLOY_PATH="${DEPLOY_PATH:-/opt/colectivo}"
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"

echo "==> Deploying to $DEPLOY_HOST:$DEPLOY_PATH"

# ── 1. Ensure target dir exists ────────────────────────────────────────────
ssh "$DEPLOY_HOST" "sudo mkdir -p $DEPLOY_PATH && sudo chown \$(id -u):\$(id -g) $DEPLOY_PATH"

# ── 2. rsync repo (excluding node_modules / build artefacts / local env) ──
rsync -az --delete \
	--exclude '.git' \
	--exclude 'node_modules' \
	--exclude '.svelte-kit' \
	--exclude 'apps/web/build' \
	--exclude 'apps/web/.vite' \
	--exclude '**/*.log' \
	--exclude '**/.env' \
	--exclude '**/.env.development' \
	--exclude '**/.env.local' \
	--exclude 'lighthouse-report.html' \
	--exclude 'coverage' \
	--exclude 'test-results' \
	--exclude 'playwright-report' \
	"$REPO_ROOT/" "$DEPLOY_HOST:$DEPLOY_PATH/"

# ── 3. Bootstrap secrets on first run; sanity-check placeholders every run ─
ssh "$DEPLOY_HOST" bash -s << 'REMOTE'
set -euo pipefail
cd /opt/colectivo

if [ ! -f .env ]; then
	echo "--- First deploy: generating secrets"

	# JWT triplet (anon + service_role)
	JWT_OUT=$(bash infra/scripts/rotate-jwt.sh)
	SUPABASE_JWT_SECRET=$(echo "$JWT_OUT" | awk -F= '/^SUPABASE_JWT_SECRET=/{print substr($0, index($0,$2))}')
	PUBLIC_SUPABASE_ANON_KEY=$(echo "$JWT_OUT" | awk -F= '/^PUBLIC_SUPABASE_ANON_KEY=/{print substr($0, index($0,$2))}')
	SUPABASE_SERVICE_ROLE_KEY=$(echo "$JWT_OUT" | awk -F= '/^SUPABASE_SERVICE_ROLE_KEY=/{print substr($0, index($0,$2))}')

	# Postgres + Realtime secrets
	POSTGRES_PASSWORD=$(openssl rand -hex 24)
	REALTIME_ENC_KEY=$(openssl rand -hex 8)       # 16 chars
	REALTIME_SECRET_KEY_BASE=$(openssl rand -hex 48) # 96 chars

	cat > .env <<EOF
# Generated on $(date -u +%Y-%m-%dT%H:%M:%SZ). Keep this file mode 600.
PUBLIC_APP_URL=https://erosi.limonia.net
PUBLIC_SUPABASE_URL=https://erosi.limonia.net

# External Keycloak — FILL THESE IN before the stack will boot usefully.
PUBLIC_KEYCLOAK_URL=FILL_IN_KEYCLOAK_URL
PUBLIC_KEYCLOAK_REALM=colectivo
PUBLIC_KEYCLOAK_CLIENT_ID=colectivo-web
KEYCLOAK_CLIENT_SECRET=FILL_IN_CLIENT_SECRET

POSTGRES_PASSWORD=$POSTGRES_PASSWORD

SUPABASE_JWT_SECRET=$SUPABASE_JWT_SECRET
PUBLIC_SUPABASE_ANON_KEY=$PUBLIC_SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY=$SUPABASE_SERVICE_ROLE_KEY

REALTIME_ENC_KEY=$REALTIME_ENC_KEY
REALTIME_SECRET_KEY_BASE=$REALTIME_SECRET_KEY_BASE
EOF
	chmod 600 .env
	echo "--- Wrote .env (mode 600)."
	echo "    Fill in: PUBLIC_KEYCLOAK_URL, KEYCLOAK_CLIENT_SECRET"
	echo "    then re-run this script."
	exit 0
fi

# Every deploy: fail fast if the operator didn't finish the .env.
if grep -q '^PUBLIC_KEYCLOAK_URL=FILL_IN_' .env \
	|| grep -q '^KEYCLOAK_CLIENT_SECRET=FILL_IN_' .env; then
	echo "ERROR: /opt/colectivo/.env still contains FILL_IN_ placeholders." >&2
	echo "       Fill in PUBLIC_KEYCLOAK_URL, KEYCLOAK_CLIENT_SECRET and retry." >&2
	exit 1
fi
REMOTE

# ── 4. Build + bring up the stack ─────────────────────────────────────────
ssh "$DEPLOY_HOST" bash -s << 'REMOTE'
set -euo pipefail
cd /opt/colectivo

echo "--- Building app image"
docker compose --env-file .env -f infra/docker-compose.erosi.yml build app

echo "--- Bringing stack up (detached)"
docker compose --env-file .env -f infra/docker-compose.erosi.yml up -d

echo "--- Waiting for db to be healthy"
for i in $(seq 1 60); do
	if docker compose --env-file .env -f infra/docker-compose.erosi.yml ps db --format json | grep -q '"Health":"healthy"'; then
		echo "db healthy"; break
	fi
	sleep 2
done

echo "--- Applying migrations"
# Every `docker compose exec -T` call below pipes in `</dev/null` (or the
# migration file for the apply step). This matters because the outer bash
# is reading its own script from stdin (`ssh ... bash -s << REMOTE`); a
# `docker compose exec -T` without its own stdin source drains the heredoc,
# silently eating the remainder of the script — observed as "first iteration
# runs, every subsequent migration vanishes from the log".
docker compose --env-file .env -f infra/docker-compose.erosi.yml exec -T db \
	psql -U postgres -d postgres </dev/null \
	-c "CREATE TABLE IF NOT EXISTS public._applied_migrations (filename TEXT PRIMARY KEY, applied_at TIMESTAMPTZ DEFAULT now());"

for f in supabase/migrations/*.sql; do
	fn=$(basename "$f")
	already=$(docker compose --env-file .env -f infra/docker-compose.erosi.yml exec -T db \
		psql -U postgres -d postgres -tAq </dev/null \
		-c "SELECT count(*) FROM public._applied_migrations WHERE filename='$fn'")
	if [ "${already:-0}" -gt 0 ]; then
		echo "  skip $fn (applied)"
		continue
	fi
	printf "  apply %s ... " "$fn"
	if docker compose --env-file .env -f infra/docker-compose.erosi.yml exec -T db \
			psql -U postgres -d postgres -v ON_ERROR_STOP=1 -q < "$f"; then
		docker compose --env-file .env -f infra/docker-compose.erosi.yml exec -T db \
			psql -U postgres -d postgres </dev/null \
			-c "INSERT INTO public._applied_migrations (filename) VALUES ('$fn') ON CONFLICT DO NOTHING;"
		echo "ok"
	else
		echo "FAIL"; exit 1
	fi
done
REMOTE

echo "==> Deploy complete."
echo "    App:       https://erosi.limonia.net"
echo "    Keycloak:  external — see PUBLIC_KEYCLOAK_URL in $DEPLOY_PATH/.env"
