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

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
ENV_FILE="${1:-$ROOT_DIR/.env.production}"
BACKUP_REF="${2:-latest}"
BACKUP_ROOT="${3:-$ROOT_DIR/backups}"
COMPOSE_FILE="$ROOT_DIR/infra/docker-compose.prod.yml"
DRILL_PROJECT_NAME="${DRILL_PROJECT_NAME:-productier-drill-$(date -u +%Y%m%d%H%M%S)}"
DRILL_CLEANUP_ON_EXIT="${DRILL_CLEANUP_ON_EXIT:-1}"
DRILL_WEBHOOK_URL="${DRILL_WEBHOOK_URL:-${OPS_ALERT_WEBHOOK_URL:-}}"
DRILL_WEBHOOK_BEARER_TOKEN="${DRILL_WEBHOOK_BEARER_TOKEN:-${OPS_ALERT_WEBHOOK_BEARER_TOKEN:-}}"
DRILL_NOTIFY_ON_SUCCESS="${DRILL_NOTIFY_ON_SUCCESS:-1}"
DRILL_WEBHOOK_TIMEOUT_SECONDS="${DRILL_WEBHOOK_TIMEOUT_SECONDS:-10}"

result_status="success"
result_message="restore drill completed successfully"
services_started=0

if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
  cat <<'USAGE'
Usage:
  scripts/ops/staging-drill.sh [env-file] [backup-ref|latest] [backup-root]

Examples:
  scripts/ops/staging-drill.sh
  scripts/ops/staging-drill.sh .env.production latest /var/backups/productier
  scripts/ops/staging-drill.sh .env.production 20260401T120000Z

Behavior:
  - Starts isolated drill infra using a temporary COMPOSE_PROJECT_NAME.
  - Runs restore-drill checks against the selected backup.
  - Sends pass/fail webhook notifications when configured.
  - Tears down drill infra by default (set DRILL_CLEANUP_ON_EXIT=0 to keep it).
USAGE
  exit 0
fi

if [[ ! -f "$ENV_FILE" ]]; then
  echo "[error] env file not found: $ENV_FILE" >&2
  exit 1
fi

if ! command -v docker >/dev/null 2>&1; then
  echo "[error] docker CLI is required" >&2
  exit 1
fi

json_escape() {
  local value="$1"
  value="${value//\\/\\\\}"
  value="${value//\"/\\\"}"
  value="${value//$'\n'/\\n}"
  value="${value//$'\r'/\\r}"
  printf '%s' "$value"
}

send_webhook() {
  local status="$1"
  local message="$2"
  if [[ -z "$DRILL_WEBHOOK_URL" ]]; then
    return
  fi
  if ! command -v curl >/dev/null 2>&1; then
    echo "[warn] DRILL_WEBHOOK_URL is set but curl is unavailable; skipping webhook"
    return
  fi

  local payload
  payload="$(cat <<EOF
{"service":"productier-restore-drill","status":"$(json_escape "$status")","project":"$(json_escape "$DRILL_PROJECT_NAME")","finishedAt":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","message":"$(json_escape "$message")"}
EOF
)"

  local auth_header=()
  if [[ -n "$DRILL_WEBHOOK_BEARER_TOKEN" ]]; then
    auth_header=(-H "Authorization: Bearer $DRILL_WEBHOOK_BEARER_TOKEN")
  fi

  if ! curl -fsS -m "$DRILL_WEBHOOK_TIMEOUT_SECONDS" \
    -H "Content-Type: application/json" \
    "${auth_header[@]}" \
    -d "$payload" \
    "$DRILL_WEBHOOK_URL" >/dev/null; then
    echo "[warn] failed to deliver restore drill webhook"
  fi
}

cleanup() {
  if [[ "$DRILL_CLEANUP_ON_EXIT" == "1" && "$services_started" == "1" ]]; then
    echo "[step] tearing down drill stack (project: $DRILL_PROJECT_NAME)"
    COMPOSE_PROJECT_NAME="$DRILL_PROJECT_NAME" \
      docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" down -v --remove-orphans >/dev/null 2>&1 || true
  fi

  if [[ "$result_status" == "success" ]]; then
    if [[ "$DRILL_NOTIFY_ON_SUCCESS" == "1" || "$DRILL_NOTIFY_ON_SUCCESS" == "true" ]]; then
      send_webhook "success" "$result_message"
    fi
  else
    send_webhook "failure" "$result_message"
  fi
}

on_error() {
  local exit_code="$1"
  result_status="failure"
  result_message="restore drill failed with exit code ${exit_code}"
}

trap cleanup EXIT
trap 'on_error $?' ERR

node "$ROOT_DIR/scripts/check-production-env.mjs" "$ENV_FILE"

echo "[step] starting drill infra (project: $DRILL_PROJECT_NAME)"
COMPOSE_PROJECT_NAME="$DRILL_PROJECT_NAME" \
  docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d postgres rustfs rustfs-init >/dev/null
services_started=1

echo "[step] waiting for postgres readiness..."
for _ in $(seq 1 60); do
  if COMPOSE_PROJECT_NAME="$DRILL_PROJECT_NAME" \
    docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" exec -T postgres \
    pg_isready -U productier -d productier >/dev/null 2>&1; then
    break
  fi
  sleep 1
done

echo "[step] running restore drill against backup ref: $BACKUP_REF"
COMPOSE_PROJECT_NAME="$DRILL_PROJECT_NAME" \
  bash "$ROOT_DIR/scripts/ops/restore-drill.sh" "$ENV_FILE" "$BACKUP_REF" "$BACKUP_ROOT"

result_status="success"
result_message="restore drill completed successfully using backup ref ${BACKUP_REF}"
echo "[ok] staging drill completed"
