#!/usr/bin/env bash
# rollback.sh — volta para uma versão anterior.
#
# Troca o symlink current e reinicia. Como o código da versão antiga já esta no
# servidor, o caminho todo leva segundos, não minutos.
#
# Uso: rollback.sh --host <ip> --user <deploy> [--app-path /srv/app] [--to <release>] [--key <chave>] --confirmed

set -uo pipefail

HOST=""; USER_NAME="deploy"; PORT=22; KEY_PATH=""
APP_PATH="/srv/app"; TARGET=""; CONFIRMED=0; SERVICE="sshepherd-app"
HEALTH_URL="http://127.0.0.1/"

while [ $# -gt 0 ]; do
  case "$1" in
    --host) HOST="$2"; shift 2 ;;
    --user) USER_NAME="$2"; shift 2 ;;
    --port) PORT="$2"; shift 2 ;;
    --key)  KEY_PATH="$2"; shift 2 ;;
    --app-path) APP_PATH="$2"; shift 2 ;;
    --to) TARGET="$2"; shift 2 ;;
    --service) SERVICE="$2"; shift 2 ;;
    --health) HEALTH_URL="$2"; shift 2 ;;
    --confirmed) CONFIRMED=1; shift ;;
    *) echo "argumento desconhecido: $1" >&2; exit 2 ;;
  esac
done

[ -n "$HOST" ] || { echo "ERRO: --host é obrigatório" >&2; exit 2; }

SSH_OPTS=(-o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ForwardAgent=no -o ConnectTimeout=10 -p "$PORT")
[ -n "$KEY_PATH" ] && SSH_OPTS+=(-i "${KEY_PATH/#\~/$HOME}" -o IdentitiesOnly=yes)
SSH_TARGET="${USER_NAME}@${HOST}"

START=$(date +%s)

ATUAL=$(ssh "${SSH_OPTS[@]}" "$SSH_TARGET" "readlink '${APP_PATH}/current' 2>/dev/null | xargs -r basename" || true)
LISTA=$(ssh "${SSH_OPTS[@]}" "$SSH_TARGET" "ls -1t '${APP_PATH}/releases' 2>/dev/null" || true)

if [ -z "$LISTA" ]; then
  echo "ERRO: não ha nenhuma versão publicada em ${APP_PATH}/releases" >&2
  exit 5
fi

if [ -z "$TARGET" ]; then
  TARGET=$(printf '%s\n' "$LISTA" | grep -v "^${ATUAL}$" | head -n1)
fi

if [ -z "$TARGET" ]; then
  echo "ERRO: não existe versão anterior para a qual voltar." >&2
  echo "Versões disponíveis:" >&2
  printf '%s\n' "$LISTA" | sed 's/^/  /' >&2
  exit 5
fi

if ! printf '%s\n' "$LISTA" | grep -qx "$TARGET"; then
  echo "ERRO: a versão '${TARGET}' não existe no servidor." >&2
  echo "Versões disponíveis:" >&2
  printf '%s\n' "$LISTA" | sed 's/^/  /' >&2
  exit 5
fi

echo "--------------------------------------------"
echo " ROLLBACK em ${HOST}"
echo "  de : ${ATUAL:-nenhuma}"
echo "  para: ${TARGET}"
echo "--------------------------------------------"

if [ "$CONFIRMED" -ne 1 ]; then
  echo "RECUSADO: rollback altera o servidor e exige --confirmed." >&2
  exit 10
fi

ssh "${SSH_OPTS[@]}" "$SSH_TARGET" "
  set -e
  test -d '${APP_PATH}/releases/${TARGET}'
  ln -sfn '${APP_PATH}/releases/${TARGET}' '${APP_PATH}/current.new'
  mv -Tf '${APP_PATH}/current.new' '${APP_PATH}/current'
  sudo -n systemctl restart '${SERVICE}' 2>/dev/null || true
" || { echo "FALHOU o rollback." >&2; exit 6; }

sleep 2
HEALTHY=0
for i in 1 2 3 4 5 6; do
  CODE=$(ssh "${SSH_OPTS[@]}" "$SSH_TARGET" "curl -s -o /dev/null -w '%{http_code}' --max-time 5 '${HEALTH_URL}' 2>/dev/null || echo 000")
  case "$CODE" in 2*|3*) HEALTHY=1; break ;; esac
  sleep 3
done

ELAPSED=$(( $(date +%s) - START ))

echo ""
echo "============================================"
if [ "$HEALTHY" -eq 1 ]; then
  echo " ROLLBACK CONCLUIDO em ${ELAPSED}s"
  echo " Versão ativa: ${TARGET}"
  echo "============================================"
  echo "ROLLBACK=sucesso"
  echo "ACTIVE=${TARGET}"
  exit 0
fi

echo " ROLLBACK APLICADO em ${ELAPSED}s, mas a aplicação ainda não responde" >&2
echo " Versão ativa: ${TARGET}" >&2
echo "" >&2
echo " Isso indica que a causa não era a última publicação." >&2
echo " Rode o diagnóstico: /sshp-doctor" >&2
echo "============================================" >&2
echo "ROLLBACK=aplicado_sem_saude"
echo "ACTIVE=${TARGET}"
exit 8
