#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<'EOF'
Usage:
  rollback-node-release --domain DOMAIN [--release TIMESTAMP_OR_PATH] [--previous] [--healthcheck-path /healthz] [--healthcheck-expect TEXT] [--healthcheck-insecure]
  rollback-node-release --help
EOF
}

domain=""
release_arg=""
use_previous=0
healthcheck_path="/healthz"
healthcheck_expect='"ok": true'
healthcheck_insecure=0

while [[ $# -gt 0 ]]; do
  case "$1" in
    --domain) domain="${2:-}"; shift 2 ;;
    --release) release_arg="${2:-}"; shift 2 ;;
    --previous) use_previous=1; shift ;;
    --healthcheck-path) healthcheck_path="${2:-}"; shift 2 ;;
    --healthcheck-expect) healthcheck_expect="${2:-}"; shift 2 ;;
    --healthcheck-insecure) healthcheck_insecure=1; shift ;;
    --help|-h) usage; exit 0 ;;
    *) echo "Unknown argument: $1" >&2; usage; exit 2 ;;
  esac
done

[[ -n "$domain" ]] || { usage; exit 2; }
[[ $(id -u) -eq 0 ]] || { echo 'Run as root' >&2; exit 1; }

env_file="/etc/node-sites/$domain.env"
[[ -f "$env_file" ]] || { echo "Node site env not found: $env_file" >&2; exit 1; }
# shellcheck disable=SC1090
source "$env_file"

: "${SITE_ROOT:?SITE_ROOT is required}"
: "${PORT:?PORT is required}"
releases_dir="$SITE_ROOT/releases"
current_link="$SITE_ROOT/current"
service_name="node-site@$domain.service"
[[ -d "$releases_dir" ]] || { echo "Releases dir not found: $releases_dir" >&2; exit 1; }
[[ -L "$current_link" ]] || { echo "Current symlink missing: $current_link" >&2; exit 1; }

current_target="$(readlink -f "$current_link")"
mapfile -t releases < <(find "$releases_dir" -mindepth 1 -maxdepth 1 -type d | sort)
[[ ${#releases[@]} -ge 1 ]] || { echo "No releases found under $releases_dir" >&2; exit 1; }

target_release=""
if [[ -n "$release_arg" ]]; then
  if [[ -d "$release_arg" ]]; then
    target_release="$(readlink -f "$release_arg")"
  else
    target_release="$releases_dir/$release_arg"
  fi
elif [[ "$use_previous" -eq 1 ]]; then
  prev=""
  for rel in "${releases[@]}"; do
    if [[ "$(readlink -f "$rel")" == "$current_target" ]]; then
      break
    fi
    prev="$rel"
  done
  target_release="$prev"
else
  for (( idx=${#releases[@]}-1; idx>=0; idx-- )); do
    rel="${releases[$idx]}"
    if [[ "$(readlink -f "$rel")" != "$current_target" ]]; then
      target_release="$rel"
      break
    fi
  done
fi

[[ -n "$target_release" ]] || { echo "No rollback target found" >&2; exit 1; }
target_release="$(readlink -f "$target_release")"
[[ -d "$target_release" ]] || { echo "Target release not found: $target_release" >&2; exit 1; }
[[ "$target_release" != "$current_target" ]] || { echo "Target release is already current: $target_release" >&2; exit 1; }

run_healthcheck() {
  local url="http://127.0.0.1:$PORT$healthcheck_path"
  local -a curl_args=(curl -fsS --max-time 10)
  if [[ "$healthcheck_insecure" -eq 1 ]]; then
    curl_args+=(-k)
  fi
  local tmp attempt response
  tmp=$(mktemp)
  for attempt in $(seq 1 20); do
    if response=$("${curl_args[@]}" "$url" 2>"$tmp"); then
      if [[ -z "$healthcheck_expect" ]] || grep -Fq "$healthcheck_expect" <<<"$response"; then
        printf '%s\n' "$response"
        rm -f "$tmp"
        return 0
      fi
      printf 'Rollback healthcheck missing expected text on attempt %s\n' "$attempt" >&2
    else
      cat "$tmp" >&2 || true
    fi
    sleep 1
  done
  rm -f "$tmp"
  return 1
}

previous_target="$current_target"
ln -sfn "$target_release" "$current_link"
restorecon -RF "$SITE_ROOT" >/dev/null 2>&1 || true
systemctl restart "$service_name"
systemctl is-active "$service_name" >/dev/null

health_output="$(run_healthcheck)" || {
  echo "Rollback healthcheck failed, reverting to previous release" >&2
  ln -sfn "$previous_target" "$current_link"
  restorecon -RF "$SITE_ROOT" >/dev/null 2>&1 || true
  systemctl restart "$service_name"
  systemctl is-active "$service_name" >/dev/null || true
  exit 1
}

echo "Rolled back domain: $domain"
echo "Previous current: $previous_target"
echo "Current -> $(readlink -f "$current_link")"
echo "Service restarted: $service_name"
echo "Healthcheck OK: http://127.0.0.1:$PORT$healthcheck_path"
printf '%s\n' "$health_output"
