#!/usr/bin/env bash
# Apply the committed redacted P0-005 credential escrow closeout receipt to
# host 110 as non-secret marker files. This script never reads credential
# values; it only forwards non-secret evidence refs that already passed the
# repository-side closeout contract.

set -euo pipefail

TARGET_HOST="${TARGET_HOST:-wooo@192.168.0.110}"
SSH_CONNECT_TIMEOUT="${SSH_CONNECT_TIMEOUT:-15}"
SSH_STRICT_HOST_KEY_CHECKING="${SSH_STRICT_HOST_KEY_CHECKING:-accept-new}"
RECEIPT_PATH="${RECEIPT_PATH:-docs/operations/awoooi-credential-escrow-evidence-controlled-closeout-receipt.snapshot.json}"
REMOTE_MARKER_SCRIPT="${REMOTE_MARKER_SCRIPT:-/backup/scripts/mark-credential-escrow-verified.sh}"
REMOTE_ESCROW_DIR="${REMOTE_ESCROW_DIR:-/backup/escrow-evidence}"
NOTE="${NOTE:-p0-005-controlled-closeout-receipt}"
MODE="check"
ROLLBACK_DIR=""

SSH_OPTS=(
  -n
  -o BatchMode=yes
  -o ConnectTimeout="$SSH_CONNECT_TIMEOUT"
  -o ConnectionAttempts=1
  -o ServerAliveInterval=5
  -o ServerAliveCountMax=1
  -o StrictHostKeyChecking="$SSH_STRICT_HOST_KEY_CHECKING"
)

usage() {
  cat <<'USAGE'
Usage:
  apply-credential-escrow-closeout-receipt-to-110.sh --check
  apply-credential-escrow-closeout-receipt-to-110.sh --dry-run
  apply-credential-escrow-closeout-receipt-to-110.sh --apply
  apply-credential-escrow-closeout-receipt-to-110.sh --rollback --rollback-dir <dir>

Rules:
  - Reads only the committed redacted closeout receipt.
  - Sends only non-secret evidence refs to host 110.
  - Does not read passwords, tokens, private keys, .env, auth, sessions, or SQLite.
USAGE
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --check|--dry-run|--apply|--rollback)
      MODE="${1#--}"
      shift
      ;;
    --rollback-dir)
      ROLLBACK_DIR="${2:-}"
      shift 2
      ;;
    --receipt)
      RECEIPT_PATH="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

if [ ! -f "$RECEIPT_PATH" ]; then
  echo "receipt not found: $RECEIPT_PATH" >&2
  exit 66
fi

receipt_items() {
  python3 - "$RECEIPT_PATH" <<'PY'
import json
import re
import sys
from pathlib import Path

path = Path(sys.argv[1])
data = json.loads(path.read_text(encoding="utf-8"))
expected = [
    "restic_repository_password",
    "offsite_provider_credentials",
    "break_glass_admin_credentials",
    "dns_registrar_recovery",
    "oauth_ai_provider_recovery",
]
if data.get("schema_version") != "credential_escrow_evidence_controlled_closeout_receipt_v1":
    raise SystemExit("receipt schema mismatch")
if data.get("status") != "ready_for_p0_005_controlled_closeout":
    raise SystemExit("receipt status is not closeout-ready")
result = data.get("result") or {}
if result.get("accepted_item_count") != len(expected):
    raise SystemExit("receipt accepted item count mismatch")
if result.get("projected_effective_escrow_missing_count") != 0:
    raise SystemExit("receipt projected missing count is not zero")
if result.get("secret_value_collection_allowed") is not False:
    raise SystemExit("receipt secret collection flag is not false")
if result.get("runtime_gate_count") != 0:
    raise SystemExit("receipt runtime gate count is not zero")
items = data.get("evidence_refs") or []
if [item.get("item_id") for item in items] != expected:
    raise SystemExit("receipt item order mismatch")
safe_ref = re.compile(r"^[A-Za-z0-9._:-]{6,160}$")
for item in items:
    item_id = str(item.get("item_id") or "")
    ref = str(item.get("non_secret_evidence_ref") or "")
    if item.get("contains_secret_value") is not False:
        raise SystemExit(f"{item_id}: contains_secret_value must be false")
    if not safe_ref.match(ref):
        raise SystemExit(f"{item_id}: unsafe evidence ref")
    print(f"{item_id}\t{ref}")
PY
}

remote_status() {
  ssh "${SSH_OPTS[@]}" "$TARGET_HOST" "$REMOTE_MARKER_SCRIPT --status"
}

remote_prepare_rollback() {
  local items_shell="$1"
  ssh "${SSH_OPTS[@]}" "$TARGET_HOST" "set -euo pipefail
rollback=\"${REMOTE_ESCROW_DIR}/.rollback-p0-005-closeout-\$(date +%Y%m%d-%H%M%S)\"
mkdir -p \"\$rollback\"
for item in ${items_shell}; do
  marker=\"${REMOTE_ESCROW_DIR}/\${item}.last_verified\"
  if [ -f \"\$marker\" ]; then
    cp -p \"\$marker\" \"\$rollback/\${item}.last_verified\"
  else
    : > \"\$rollback/\${item}.was_missing\"
  fi
done
echo \"ROLLBACK_DIR=\$rollback\""
}

run_marker_command() {
  local item="$1"
  local evidence_ref="$2"
  local mode_flag="$3"
  local quoted_note quoted_item quoted_ref
  printf -v quoted_item '%q' "$item"
  printf -v quoted_ref '%q' "$evidence_ref"
  printf -v quoted_note '%q' "$NOTE"
  ssh "${SSH_OPTS[@]}" "$TARGET_HOST" \
    "$REMOTE_MARKER_SCRIPT --item $quoted_item --evidence-id $quoted_ref --note $quoted_note $mode_flag"
}

rollback_markers() {
  if [ -z "$ROLLBACK_DIR" ]; then
    echo "--rollback requires --rollback-dir" >&2
    exit 2
  fi
  ssh "${SSH_OPTS[@]}" "$TARGET_HOST" "set -euo pipefail
test -d '$ROLLBACK_DIR'
for marker in '$ROLLBACK_DIR'/*.last_verified; do
  [ -e \"\$marker\" ] || continue
  item=\$(basename \"\$marker\" .last_verified)
  cp -p \"\$marker\" '${REMOTE_ESCROW_DIR}/'\${item}.last_verified
done
for missing in '$ROLLBACK_DIR'/*.was_missing; do
  [ -e \"\$missing\" ] || continue
  item=\$(basename \"\$missing\" .was_missing)
  rm -f '${REMOTE_ESCROW_DIR}/'\${item}.last_verified
done
echo ROLLBACK_APPLIED '$ROLLBACK_DIR'
${REMOTE_MARKER_SCRIPT} --status"
}

items_tsv="$(receipt_items)"
items_shell="$(awk '{printf "%s ", $1}' <<<"$items_tsv")"

case "$MODE" in
  check)
    echo "RECEIPT_OK $RECEIPT_PATH"
    echo "$items_tsv" | awk '{print "RECEIPT_ITEM item="$1" evidence_ref="$2}'
    remote_status
    ;;
  dry-run)
    echo "RECEIPT_OK $RECEIPT_PATH"
    while IFS=$'\t' read -r item evidence_ref; do
      run_marker_command "$item" "$evidence_ref" "--dry-run"
    done <<<"$items_tsv"
    ;;
  apply)
    echo "RECEIPT_OK $RECEIPT_PATH"
    remote_prepare_rollback "$items_shell"
    while IFS=$'\t' read -r item evidence_ref; do
      run_marker_command "$item" "$evidence_ref" ""
    done <<<"$items_tsv"
    remote_status
    ;;
  rollback)
    rollback_markers
    ;;
  *)
    echo "unsupported mode: $MODE" >&2
    exit 2
    ;;
esac
