#!/usr/bin/env bash
#
# Phase 3 cutover: migrate the running stack from `capakraken` (DB, role,
# volumes, compose project) to `nexus`. Intended to be run inside a brief
# maintenance window — the app is stopped for the duration.
#
# Idempotency: each step checks the current state. Re-running after a
# partial run only does the missing pieces. The script never DROPS the
# legacy `capakraken` DB or role — that's a manual decision after a
# stability window.
#
# Usage:
#   ./tooling/migrate/rename-to-nexus.sh dev       # against docker-compose.yml
#   ./tooling/migrate/rename-to-nexus.sh prod      # against docker-compose.prod.yml
#
# Requires:
#   - POSTGRES_PASSWORD set in env (or .env file picked up by docker compose)
#   - docker compose CLI v2+
#   - the `nexus` branch of code already checked out (compose files reference nexus_*)

set -euo pipefail

MODE="${1:-dev}"
case "$MODE" in
  dev)
    COMPOSE_FILE=docker-compose.yml
    OLD_PROJECT=capakraken
    NEW_PROJECT=nexus
    VOLUMES=(pgdata node_modules next)
    ;;
  prod)
    COMPOSE_FILE=docker-compose.prod.yml
    OLD_PROJECT=capakraken-prod
    NEW_PROJECT=nexus-prod
    VOLUMES=(prod_pgdata prod_redis)
    ;;
  *)
    echo "Usage: $0 [dev|prod]" >&2
    exit 2
    ;;
esac

if [ -z "${POSTGRES_PASSWORD:-}" ]; then
  echo "POSTGRES_PASSWORD must be set in the environment." >&2
  exit 2
fi

DUMP_FILE="/tmp/capakraken-pre-rename-$(date +%Y%m%d-%H%M%S).sql"

echo "=== Phase 3 cutover ($MODE) ==="
echo "compose: $COMPOSE_FILE  project: $OLD_PROJECT → $NEW_PROJECT  dump: $DUMP_FILE"
echo

#───────────────────────────────────────────────────────────────────────────────
# 1. Stop the app (DB stays up so we can dump it).
#───────────────────────────────────────────────────────────────────────────────
echo "[1/7] Stopping app container under old project name..."
docker compose -p "$OLD_PROJECT" -f "$COMPOSE_FILE" stop app 2>/dev/null || true

#───────────────────────────────────────────────────────────────────────────────
# 2. Capture row counts for verification.
#───────────────────────────────────────────────────────────────────────────────
echo "[2/7] Capturing pre-rename row counts..."
PRE_COUNTS=$(docker compose -p "$OLD_PROJECT" -f "$COMPOSE_FILE" exec -T postgres \
  psql -U capakraken -d capakraken -t -c \
  "SELECT relname, n_live_tup FROM pg_stat_user_tables ORDER BY relname;")
echo "$PRE_COUNTS" | head -20
echo "..."

#───────────────────────────────────────────────────────────────────────────────
# 3. Dump existing DB.
#───────────────────────────────────────────────────────────────────────────────
echo "[3/7] pg_dump capakraken → $DUMP_FILE..."
docker compose -p "$OLD_PROJECT" -f "$COMPOSE_FILE" exec -T postgres \
  pg_dump -U capakraken -d capakraken --clean --if-exists > "$DUMP_FILE"
echo "Dump size: $(du -h "$DUMP_FILE" | cut -f1)"

#───────────────────────────────────────────────────────────────────────────────
# 4. Create new role + DB inside the running postgres container.
#───────────────────────────────────────────────────────────────────────────────
echo "[4/7] Creating nexus role + database..."
docker compose -p "$OLD_PROJECT" -f "$COMPOSE_FILE" exec -T postgres \
  psql -U capakraken -d postgres <<SQL
DO \$\$
BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='nexus') THEN
    CREATE ROLE nexus LOGIN PASSWORD '${POSTGRES_PASSWORD}';
  END IF;
END
\$\$;

SELECT 'CREATE DATABASE nexus OWNER nexus'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname='nexus')
\gexec
SQL

#───────────────────────────────────────────────────────────────────────────────
# 5. Restore into new DB.
#───────────────────────────────────────────────────────────────────────────────
echo "[5/7] Restoring dump into nexus DB..."
# Replace OWNER directives so restored objects belong to `nexus`.
sed 's/OWNER TO capakraken/OWNER TO nexus/g' "$DUMP_FILE" | \
  docker compose -p "$OLD_PROJECT" -f "$COMPOSE_FILE" exec -T postgres \
  psql -U nexus -d nexus

#───────────────────────────────────────────────────────────────────────────────
# 6. Volume rename (offline copy).
#───────────────────────────────────────────────────────────────────────────────
echo "[6/7] Stopping old project and copying volumes..."
docker compose -p "$OLD_PROJECT" -f "$COMPOSE_FILE" down --remove-orphans

for v in "${VOLUMES[@]}"; do
  src="${OLD_PROJECT//-/_}_${v}"
  dst="${NEW_PROJECT//-/_}_${v}"
  # Skip dev-mode app overlays (node_modules / next) — they regenerate on startup.
  if [ "$MODE" = "dev" ] && { [ "$v" = "node_modules" ] || [ "$v" = "next" ]; }; then
    echo "  Skipping $v (regenerated on next boot)"
    continue
  fi
  if ! docker volume inspect "$src" >/dev/null 2>&1; then
    echo "  Source volume $src missing — skip"
    continue
  fi
  if docker volume inspect "$dst" >/dev/null 2>&1; then
    echo "  Destination volume $dst already exists — skip"
    continue
  fi
  echo "  $src → $dst"
  docker volume create "$dst" >/dev/null
  docker run --rm \
    -v "${src}:/from:ro" \
    -v "${dst}:/to" \
    alpine sh -c "cd /from && cp -a . /to/"
done

#───────────────────────────────────────────────────────────────────────────────
# 7. Bring up under new compose project name.
#───────────────────────────────────────────────────────────────────────────────
echo "[7/7] Starting stack under new project name '$NEW_PROJECT'..."
PROFILE=""
[ "$MODE" = "dev" ] && PROFILE="--profile full"
# shellcheck disable=SC2086
docker compose -p "$NEW_PROJECT" -f "$COMPOSE_FILE" $PROFILE up -d

echo
echo "Waiting 15s for postgres to be ready..."
sleep 15

echo "=== Verification ==="
POST_COUNTS=$(docker compose -p "$NEW_PROJECT" -f "$COMPOSE_FILE" exec -T postgres \
  psql -U nexus -d nexus -t -c \
  "SELECT relname, n_live_tup FROM pg_stat_user_tables ORDER BY relname;")
echo "Post-rename row counts (sample):"
echo "$POST_COUNTS" | head -20

if diff <(echo "$PRE_COUNTS") <(echo "$POST_COUNTS") >/dev/null; then
  echo "✓ Row counts match — migration verified."
else
  echo "⚠  Row counts differ — review diff:"
  diff <(echo "$PRE_COUNTS") <(echo "$POST_COUNTS") | head
fi

echo
echo "Done. Old DB+role retained for rollback. Dump kept at $DUMP_FILE."
echo "After a stability window, drop with:"
echo "  docker compose -p $NEW_PROJECT -f $COMPOSE_FILE exec postgres psql -U nexus -d postgres \\"
echo "    -c 'DROP DATABASE capakraken; DROP ROLE capakraken;'"
