#!/usr/bin/env bash
# Read-only operator checklist for completing AWOOOI DR offsite readiness.
#
# 2026-05-07 ogt + Codex:
# - 只讀彙整 110 Google Drive/rclone offsite/escrow 狀態與 Prometheus scorecard。
# - 不讀、不列印、不寫入任何 credential。
# - 不上傳資料、不寫 success marker；所有寫入動作只輸出給 operator 在 110 TTY 明確執行。

set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
REMOTE_110="${REMOTE_110:-wooo@192.168.0.110}"
PROMETHEUS_URL="${PROMETHEUS_URL:-http://192.168.0.110:9090}"
ALERTMANAGER_URL="${ALERTMANAGER_URL:-http://192.168.0.110:9093}"
SSH_BATCH_MODE="${SSH_BATCH_MODE:-yes}"
SSH_STRICT_HOST_KEY_CHECKING="${SSH_STRICT_HOST_KEY_CHECKING:-accept-new}"

MODE="check"
REQUIRE_DR=0
NO_COLOR=0

usage() {
  cat <<'USAGE'
Usage:
  bash scripts/reboot-recovery/dr-offsite-operator-checklist.sh [--check] [--no-color]
  bash scripts/reboot-recovery/dr-offsite-operator-checklist.sh --commands-only
  bash scripts/reboot-recovery/dr-offsite-operator-checklist.sh --require-dr

Purpose:
  Produce a read-only, secret-safe handoff for finishing Google Drive/rclone offsite backup and
  credential escrow after core reboot recovery is already green.

Rules:
  - This script never prints credential values.
  - This script never uploads backup data.
  - This script never writes provider credentials, escrow, partial-sync, or full-sync markers.
  - Operator must run the printed write commands directly on 110 TTY.
  - --require-dr is the final post-escrow gate: it also requires the repo scorecard,
    Prometheus recovery recording rule, and backup alert visibility contract to agree.

Environment:
  REMOTE_110, PROMETHEUS_URL, ALERTMANAGER_URL, SSH_BATCH_MODE,
  SSH_STRICT_HOST_KEY_CHECKING.
USAGE
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --check)
      MODE="check"
      shift
      ;;
    --commands-only)
      MODE="commands-only"
      shift
      ;;
    --require-dr)
      MODE="check"
      REQUIRE_DR=1
      shift
      ;;
    --no-color)
      NO_COLOR=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

if [ "${NO_COLOR}" = "1" ]; then
  green=""
  yellow=""
  red=""
  reset=""
else
  green="$(printf '\033[32m')"
  yellow="$(printf '\033[33m')"
  red="$(printf '\033[31m')"
  reset="$(printf '\033[0m')"
fi

ok() {
  printf "%sOK%s %s\n" "${green}" "${reset}" "$*"
}

warn() {
  printf "%sWARN%s %s\n" "${yellow}" "${reset}" "$*"
}

block() {
  printf "%sBLOCKED%s %s\n" "${red}" "${reset}" "$*"
}

section() {
  echo
  echo "== $* =="
}

kv_from_file() {
  local path="$1"
  local key="$2"
  awk -F= -v key="$key" '$1 == key {print $2; found=1; exit} END {if (!found) print ""}' "$path"
}

print_secret_rules() {
  section "安全邊界"
  cat <<'TEXT'
- 不要把 Google Drive OAuth token、rclone.conf、restic password、OAuth recovery code、private key 貼到聊天、repo、LOGBOOK、Telegram 或 Prometheus label。
- evidence-id 只能是密碼管理器項目 ID、工單 ID、sealed envelope ID 或 recovery checklist ID。
- 這份 checklist 只讀；看到命令後，仍需 operator 在 110 TTY 明確執行。
TEXT
}

print_all_commands() {
  section "完整 110 TTY 命令順序"
  cat <<'COMMANDS'
# 0. 登入 110；以下命令都在 110 本機跑。
ssh wooo@192.168.0.110

# 1. 先產出紅acted 狀態，不查 remote、不上傳、不寫 marker。
/backup/scripts/offsite-escrow-evidence-report.sh --no-color

# 2. 設定 Google Drive/rclone。OAuth token 只留在 110 host-local rclone.conf。
/backup/scripts/configure-offsite-rclone.sh --interactive
/backup/scripts/configure-offsite-rclone.sh --status

# 3. Google Drive/rclone 設定後 gate；不可有 BLOCKED。
/backup/scripts/backup-offsite-readiness-gate.sh --status --require-configured --no-color

# 4. 小範圍 dry-run；不會上傳、不寫 marker。
/backup/scripts/backup-offsite-readiness-gate.sh --dry-run-small --no-color
/backup/scripts/sync-offsite-backups.sh --mode dry-run --repos "ai-artifacts public-routes"

# 5. dry-run 成功後才做小範圍 partial sync；這一步會上傳小 repo 並寫 partial marker。
/backup/scripts/sync-offsite-backups.sh --mode sync --repos "ai-artifacts public-routes"
/backup/scripts/backup-offsite-readiness-gate.sh --status --require-configured --no-color

# 6. 人工確認 credential escrow。先列出缺失項目，再把 EVIDENCE_ID_FOR_* 換成不含 secret 的證據 ID。
/backup/scripts/mark-credential-escrow-verified.sh --status
/backup/scripts/mark-credential-escrow-verified.sh --missing-commands

# 7. 全量 offsite sync 前只讀檢查；全綠後才安排低峰 full sync。
/backup/scripts/backup-offsite-readiness-gate.sh --pre-full-sync --require-configured --require-escrow --no-color

# 8. 低峰窗口 full sync；先放明確啟用 marker，這一步會上傳全 13 repo，成功才寫 full marker。
install -d -m 750 /backup/offsite
touch /backup/offsite/enable-rclone-sync
/backup/scripts/sync-offsite-backups.sh --mode sync

# 9. 完成後證據檢查。
/backup/scripts/offsite-escrow-evidence-report.sh --include-remote-status --no-color
/backup/scripts/backup-offsite-readiness-gate.sh --status --require-configured --require-escrow --no-color
grep -E 'awoooi_backup_offsite_|awoooi_backup_credential_escrow_' /home/wooo/node_exporter_textfiles/backup_health.prom
COMMANDS

  section "repo 工作站最終 gate"
  cat <<'COMMANDS'
# 在 /Users/ogt/awoooi repo 工作站跑；DR 完成前 --require-dr 必須失敗。
bash scripts/reboot-recovery/full-stack-recovery-scorecard.sh --require-dr
python3 scripts/ops/recovery-scorecard-contract-check.py --prometheus-url http://192.168.0.110:9090 --expect-core-ready --expect-dr-ready
bash scripts/reboot-recovery/wait-dr-offsite-ready.sh --timeout-seconds 900 --interval-seconds 30 --no-color
COMMANDS
}

print_next_step_commands() {
  local next_step="$1"
  section "依目前 NEXT_STEP 的下一段命令"
  case "${next_step}" in
    configure_google_drive_rclone_on_110_tty|configure_b2_on_110_tty)
      cat <<'COMMANDS'
ssh wooo@192.168.0.110
/backup/scripts/offsite-escrow-evidence-report.sh --no-color
/backup/scripts/configure-offsite-rclone.sh --interactive
/backup/scripts/configure-offsite-rclone.sh --status
/backup/scripts/backup-offsite-readiness-gate.sh --status --require-configured --no-color
COMMANDS
      ;;
    run_small_dry_run_then_partial_sync)
      cat <<'COMMANDS'
ssh wooo@192.168.0.110
/backup/scripts/backup-offsite-readiness-gate.sh --dry-run-small --no-color
/backup/scripts/sync-offsite-backups.sh --mode dry-run --repos "ai-artifacts public-routes"
# 上面兩條都成功後才執行：
/backup/scripts/sync-offsite-backups.sh --mode sync --repos "ai-artifacts public-routes"
/backup/scripts/offsite-escrow-evidence-report.sh --no-color
COMMANDS
      ;;
    complete_credential_escrow_review)
      cat <<'COMMANDS'
ssh wooo@192.168.0.110
/backup/scripts/mark-credential-escrow-verified.sh --status
# 將輸出的 EVIDENCE_ID_FOR_* 換成不含 secret 的密碼管理器項目 ID、工單 ID、sealed envelope ID 或 recovery checklist ID。
/backup/scripts/mark-credential-escrow-verified.sh --missing-commands
/backup/scripts/offsite-escrow-evidence-report.sh --no-color

# 5 個 marker 寫完後，回到 repo 工作站等待 Prometheus / Alertmanager 收斂：
bash scripts/reboot-recovery/wait-dr-offsite-ready.sh --timeout-seconds 900 --interval-seconds 30 --no-color
COMMANDS
      ;;
    pre_full_sync_review)
      cat <<'COMMANDS'
ssh wooo@192.168.0.110
/backup/scripts/backup-offsite-readiness-gate.sh --pre-full-sync --require-configured --require-escrow --no-color
# 上面全綠，且已確認低峰窗口後才執行：
install -d -m 750 /backup/offsite
touch /backup/offsite/enable-rclone-sync
/backup/scripts/sync-offsite-backups.sh --mode sync
/backup/scripts/offsite-escrow-evidence-report.sh --include-remote-status --no-color
COMMANDS
      ;;
    offsite_and_escrow_ready)
      cat <<'COMMANDS'
# 110 側維持每日 evidence report、每週 integrity check、每月 restore drill。
/backup/scripts/offsite-escrow-evidence-report.sh --include-remote-status --no-color

# repo 側確認 DR recording rule 變成 1。
bash scripts/reboot-recovery/full-stack-recovery-scorecard.sh --require-dr
python3 scripts/ops/recovery-scorecard-contract-check.py --prometheus-url http://192.168.0.110:9090 --expect-core-ready --expect-dr-ready
bash scripts/reboot-recovery/wait-dr-offsite-ready.sh --once --no-color
COMMANDS
      ;;
    *)
      warn "NEXT_STEP unknown=${next_step:-empty}; 請照完整 110 TTY 命令順序逐段執行。"
      ;;
  esac
}

if [ "${MODE}" = "commands-only" ]; then
  echo "AWOOOI DR offsite operator checklist"
  date '+%Y-%m-%d %H:%M:%S %Z'
  print_secret_rules
  print_all_commands
  exit 0
fi

tmpdir="$(mktemp -d)"
trap 'rm -rf "${tmpdir}"' EXIT
scorecard_log="${tmpdir}/scorecard.log"
require_dr_scorecard_log="${tmpdir}/scorecard-require-dr.log"
contract_log="${tmpdir}/recovery-scorecard-contract.log"
dr_contract_log="${tmpdir}/recovery-scorecard-contract-dr.log"
backup_visibility_log="${tmpdir}/backup-alert-live-visibility.log"
evidence_log="${tmpdir}/offsite-evidence-report.log"

echo "AWOOOI DR offsite operator checklist"
date '+%Y-%m-%d %H:%M:%S %Z'
echo "REMOTE_110=${REMOTE_110}"
echo "PROMETHEUS_URL=${PROMETHEUS_URL}"
echo "ALERTMANAGER_URL=${ALERTMANAGER_URL}"

print_secret_rules

section "repo scorecard"
if bash "${ROOT_DIR}/scripts/reboot-recovery/full-stack-recovery-scorecard.sh" >"${scorecard_log}" 2>&1; then
  ok "full-stack-recovery-scorecard.sh completed"
else
  warn "full-stack-recovery-scorecard.sh returned non-zero; continuing with collected output"
fi
cat "${scorecard_log}"

recovery_state="$(kv_from_file "${scorecard_log}" RECOVERY_STATE)"
next_step="$(kv_from_file "${scorecard_log}" NEXT_STEP)"

section "Prometheus recovery recording rule"
if python3 "${ROOT_DIR}/scripts/ops/recovery-scorecard-contract-check.py" \
  --prometheus-url "${PROMETHEUS_URL}" \
  --expect-core-ready \
  >"${contract_log}" 2>&1; then
  ok "recovery scorecard live contract passed"
else
  block "recovery scorecard live contract failed"
fi
cat "${contract_log}"

section "110 redacted evidence report"
ssh_opts=(-o BatchMode="${SSH_BATCH_MODE}" -o ConnectTimeout=6 -o StrictHostKeyChecking="${SSH_STRICT_HOST_KEY_CHECKING}")
if ssh "${ssh_opts[@]}" "${REMOTE_110}" '/backup/scripts/offsite-escrow-evidence-report.sh --no-color' >"${evidence_log}" 2>&1; then
  ok "110 offsite evidence report collected"
else
  warn "110 offsite evidence report unavailable; SSH 或 /backup/scripts 需先恢復"
fi
cat "${evidence_log}"

evidence_next_step="$(kv_from_file "${evidence_log}" NEXT_STEP)"
if [ -n "${evidence_next_step}" ]; then
  next_step="${evidence_next_step}"
fi

section "目前判定"
echo "RECOVERY_STATE=${recovery_state:-unknown}"
echo "NEXT_STEP=${next_step:-unknown}"

if [ "${recovery_state:-}" = "CORE_READY_DR_OFFSITE_READY" ] || [ "${next_step:-}" = "offsite_and_escrow_ready" ]; then
  ok "核心恢復與 DR offsite gate 看起來都已完成"
else
  warn "核心恢復可用，但 DR offsite 仍需 operator 完成人工段落"
fi

print_next_step_commands "${next_step:-unknown}"
print_all_commands

if [ "${REQUIRE_DR}" = "1" ]; then
  section "require-dr final contract"
  require_dr_failed=0

  if bash "${ROOT_DIR}/scripts/reboot-recovery/full-stack-recovery-scorecard.sh" \
    --require-dr \
    >"${require_dr_scorecard_log}" 2>&1; then
    ok "full-stack-recovery-scorecard.sh --require-dr passed"
  else
    require_dr_failed=1
    block "full-stack-recovery-scorecard.sh --require-dr failed"
  fi
  cat "${require_dr_scorecard_log}"

  if python3 "${ROOT_DIR}/scripts/ops/recovery-scorecard-contract-check.py" \
    --prometheus-url "${PROMETHEUS_URL}" \
    --expect-core-ready \
    --expect-dr-ready \
    >"${dr_contract_log}" 2>&1; then
    ok "Prometheus recovery recording rule confirms DR ready"
  else
    require_dr_failed=1
    block "Prometheus recovery recording rule does not confirm DR ready"
  fi
  cat "${dr_contract_log}"

  if python3 "${ROOT_DIR}/scripts/ops/backup-alert-live-visibility-check.py" \
    --prometheus-url "${PROMETHEUS_URL}" \
    --alertmanager-url "${ALERTMANAGER_URL}" \
    >"${backup_visibility_log}" 2>&1; then
    ok "backup alert visibility contract passed"
  else
    require_dr_failed=1
    block "backup alert visibility contract failed"
  fi
  cat "${backup_visibility_log}"

  if [ "${recovery_state:-}" != "CORE_READY_DR_OFFSITE_READY" ] && [ "${next_step:-}" != "offsite_and_escrow_ready" ]; then
    require_dr_failed=1
    block "require-dr state check failed: ${recovery_state:-unknown}; NEXT_STEP=${next_step:-unknown}"
  fi

  if [ "${require_dr_failed}" -eq 0 ]; then
    ok "DR offsite final gate passed"
    exit 0
  fi
  block "require-dr failed: ${recovery_state:-unknown}; NEXT_STEP=${next_step:-unknown}"
  exit 1
fi
