#!/usr/bin/env bash
#
# Flujo: tenías PostgreSQL 14.x en Docker (p. ej. 14.2), subes compose a 17.7 y el
# volumen antiguo no arranca con la imagen nueva. Este script:
#   1) Arranca un contenedor temporal con la MISMA imagen major que tus datos (PG14)
#      montando el volumen actual y hace pg_dump -Fc.
#   2) Guarda el .dump bajo humand-packages/monolith/.pg-upgrade-dumps/ (repo local).
#   3) Borra el contenedor viejo y el volumen PG14.
#   4) Levanta el servicio db con docker compose (imagen nueva en compose.yml, p. ej. 17.7).
#   5) Restaura con pg_restore (sin psql; evita metacomandos \restrict de dumps SQL).
#
# Antes de ejecutar: deja compose.yml apuntando a postgres:17.7 (o la versión nueva).
#
# Uso (desde humand-packages/monolith):
#   ./scripts/docker-migrate-pg14-to-17.sh
#   ./scripts/docker-migrate-pg14-to-17.sh --volume <id_del_volumen>
#
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MONOLITH_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
COMPOSE_FILE="${COMPOSE_FILE:-${MONOLITH_DIR}/compose.yml}"

# Imagen que coincide con el major del cluster en el volumen (datos creados con PG14).
OLD_IMAGE="${OLD_PG_IMAGE:-postgres:14.2-alpine}"
# Solo informativo; el script usa la imagen definida en compose.yml al hacer up -d.
NEW_IMAGE="${NEW_PG_IMAGE:-postgres:17.7-alpine}"

DUMP_DIR="${DUMP_DIR:-${MONOLITH_DIR}/.pg-upgrade-dumps}"

COMPOSE_SERVICE="db"
CONTAINER_NAME="humand-db"
PG_USER="humand_user"
PG_DB="humand_dev"
PG_PASSWORD="humand_password"
HOST_PORT="5432"

EXPLICIT_VOLUME=""
DRY_RUN=0

usage() {
  sed -n '1,22p' "$0" | grep -E '^#' | sed 's/^# \?//'
  echo ""
  echo "Opciones:"
  echo "  --volume ID                 Volumen Docker con datos PG14 (si no hay contenedor humand-db)"
  echo "  --compose-file RUTA         compose.yml (default: monolith/compose.yml)"
  echo "  --dump-dir RUTA             Dónde guardar los .dump (default: monolith/.pg-upgrade-dumps)"
  echo "  --old-image IMAGEN          Debe coincidir con el major de tus datos (default: postgres:14.2-alpine)"
  echo "  --new-image IMAGEN          Debe coincidir con compose (solo referencia; default: postgres:17.7-alpine)"
  echo "  --dry-run                   Solo mostrar pasos"
  echo "  -h, --help                  Esta ayuda"
}

log() { echo "[migrate-pg] $*"; }
die() { echo "[migrate-pg] ERROR: $*" >&2; exit 1; }

while [[ $# -gt 0 ]]; do
  case "$1" in
    --volume) EXPLICIT_VOLUME="${2:-}"; shift 2 ;;
    --compose-file) COMPOSE_FILE="${2:-}"; shift 2 ;;
    --dump-dir) DUMP_DIR="${2:-}"; shift 2 ;;
    --old-image) OLD_IMAGE="${2:-}"; shift 2 ;;
    --new-image) NEW_IMAGE="${2:-}"; shift 2 ;;
    --dry-run) DRY_RUN=1; shift ;;
    -h|--help) usage; exit 0 ;;
    *) die "argumento desconocido: $1 (usa --help)" ;;
  esac
done

[[ -f "$COMPOSE_FILE" ]] || die "No existe compose: $COMPOSE_FILE"

wait_for_postgres() {
  local container="$1"
  local user="$2"
  local i
  for i in $(seq 1 90); do
    if docker exec "$container" pg_isready -U "$user" -q 2>/dev/null; then
      return 0
    fi
    sleep 1
  done
  die "timeout esperando PostgreSQL en $container"
}

volume_from_container() {
  local cname="$1"
  docker inspect "$cname" --format '{{range .Mounts}}{{if eq .Destination "/var/lib/postgresql/data"}}{{.Name}}{{end}}{{end}}' 2>/dev/null | head -1
}

resolve_volume() {
  if [[ -n "$EXPLICIT_VOLUME" ]]; then
    echo "$EXPLICIT_VOLUME"
    return
  fi
  docker inspect "$CONTAINER_NAME" &>/dev/null || die "No hay contenedor '$CONTAINER_NAME'. Indica --volume con el id del volumen PG14."
  local v
  v="$(volume_from_container "$CONTAINER_NAME")"
  [[ -n "$v" ]] || die "No se encontró volumen en /var/lib/postgresql/data para $CONTAINER_NAME"
  echo "$v"
}

migrate_db() {
  local ts
  local backup_file
  local temp_name
  local data_vol

  ts="$(date +%Y%m%d-%H%M%S)"
  backup_file="${DUMP_DIR}/${PG_DB}-${ts}.dump"
  temp_name="${CONTAINER_NAME}-pg14-migrate-$$"

  log "=== Migrando servicio compose: $COMPOSE_SERVICE ($CONTAINER_NAME) ==="

  data_vol="$(resolve_volume)"
  log "Volumen de datos: $data_vol"
  log "Dump persistente: $backup_file"

  if [[ "$DRY_RUN" -eq 1 ]]; then
    log "[dry-run] mkdir -p $DUMP_DIR"
    log "[dry-run] docker compose -f $COMPOSE_FILE stop $COMPOSE_SERVICE"
    log "[dry-run] docker rm -f $CONTAINER_NAME"
    log "[dry-run] docker run ... $OLD_IMAGE con volumen $data_vol → pg_dump -Fc → $backup_file"
    log "[dry-run] docker volume rm $data_vol"
    log "[dry-run] docker compose -f $COMPOSE_FILE up -d $COMPOSE_SERVICE (imagen de compose, p. ej. $NEW_IMAGE)"
    log "[dry-run] pg_restore desde $backup_file"
    return 0
  fi

  mkdir -p "$DUMP_DIR"

  log "Deteniendo servicio $COMPOSE_SERVICE..."
  docker compose -f "$COMPOSE_FILE" stop "$COMPOSE_SERVICE" 2>/dev/null || true

  if docker inspect "$CONTAINER_NAME" &>/dev/null; then
    log "Eliminando contenedor $CONTAINER_NAME (se conserva el volumen hasta el dump)..."
    docker rm -f "$CONTAINER_NAME"
  fi

  log "Levantando contenedor temporal $OLD_IMAGE para volcar datos (volumen PG14)..."
  docker rm -f "$temp_name" 2>/dev/null || true
  docker run -d \
    --name "$temp_name" \
    -e "POSTGRES_USER=$PG_USER" \
    -e "POSTGRES_PASSWORD=$PG_PASSWORD" \
    -e "POSTGRES_DB=$PG_DB" \
    -v "$data_vol:/var/lib/postgresql/data" \
    "$OLD_IMAGE" >/dev/null

  wait_for_postgres "$temp_name" "$PG_USER"

  log "Generando dump (pg_dump -Fc, formato custom)..."
  docker exec "$temp_name" pg_dump -U "$PG_USER" -d "$PG_DB" \
    --no-owner --no-acl --format=custom --verbose \
    --file=/tmp/migrate.dump
  docker cp "$temp_name:/tmp/migrate.dump" "$backup_file"
  log "Dump guardado en el repo: $backup_file"

  docker rm -f "$temp_name" >/dev/null

  log "Eliminando volumen antiguo (PG14)..."
  docker volume rm "$data_vol"

  log "Creando cluster nuevo (docker compose; imagen según compose.yml)..."
  docker compose -f "$COMPOSE_FILE" up -d "$COMPOSE_SERVICE"

  wait_for_postgres "$CONTAINER_NAME" "$PG_USER"

  log "Restaurando dump en el nuevo PostgreSQL (pg_restore)..."
  set +e
  docker exec -i "$CONTAINER_NAME" pg_restore \
    -U "$PG_USER" \
    -d "$PG_DB" \
    --no-owner \
    --no-acl \
    --verbose \
    <"$backup_file"
  local prc=$?
  set -e
  if [[ "$prc" -ne 0 && "$prc" -ne 1 ]]; then
    die "pg_restore falló con código $prc (el dump sigue en $backup_file)"
  fi
  if [[ "$prc" -eq 1 ]]; then
    log "pg_restore terminó con advertencias (código 1); revisa el log arriba."
  fi

  log "Comprobación: $(docker exec "$CONTAINER_NAME" psql -U "$PG_USER" -d "$PG_DB" -tAc "SELECT version();" | tr -d '\r')"
  log "Listo: $COMPOSE_SERVICE en puerto host $HOST_PORT (contenedor $CONTAINER_NAME)."
  log "Archivo de respaldo conservado: $backup_file"
}

migrate_db
