#!/usr/bin/env bash
# One-shot integration test only on isolated YMServer DB. No production writes.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
DB=yachtmemory_catalog_v2_test
VESSEL=4b4fba28-49b7-4d18-87fb-63a1a5c1930e
SID=a60af109-47ac-44d2-b081-c4f7b71e1643
R="$ROOT/receiver/ym-sync-catalog-v2-atomic-review.php"
[[ "$(id -un)" != root ]] || { echo 'ABORT: run as normal operator'; exit 1; }
grep -Fxq "const DB_NAME = 'yachtmemory_catalog_v2_test';" "$R" || exit 1
php -l "$R"
[[ "$(sudo mysql -N -e "SELECT COUNT(*) FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='$DB'")" == 1 ]] || { echo 'ABORT: missing isolated DB'; exit 1; }
[[ "$(sudo mysql -N -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='$DB' AND TABLE_NAME='sync_receipts'")" == 1 ]] || { echo 'ABORT: test receipt table absent'; exit 1; }
q() { sudo mysql -N "$DB" -e "$1"; }
[[ "$(q "SELECT COUNT(*) FROM telemetry_vessels WHERE vessel_id=UUID_TO_BIN('$VESSEL')")" == 0 ]] || { echo 'ABORT: synthetic test vessel exists; one-shot only'; exit 1; }
[[ "$(q "SELECT COUNT(*) FROM signalk_catalog_snapshots_v2 WHERE snapshot_id=UUID_TO_BIN('$SID')")" == 0 ]] || { echo 'ABORT: synthetic snapshot already exists'; exit 1; }
[[ "$(q "SELECT COUNT(*) FROM sync_receipts WHERE vessel_id=UUID_TO_BIN('$VESSEL')")" == 0 ]] || { echo 'ABORT: synthetic receipts exist'; exit 1; }
sudo mysql "$DB" -e "INSERT INTO telemetry_vessels(vessel_id,vessel_key,created_at_utc) VALUES(UUID_TO_BIN('$VESSEL'),'catalog-v2-atomic-review',UTC_TIMESTAMP(3))"
run() { sudo -n env -u YM_CATALOG_ATOMIC_FAULT /usr/bin/php "$R" --authenticated-vessel "$VESSEL" < "$1"; }
assert_sql() { local got; got="$(q "$1")"; [[ "$got" == "$2" ]] || { echo "FAIL: expected $2, got $got"; exit 1; }; }
expect() {
  local name=$1 wanted=$2 data
  data="$(run "fixtures/atomic-$name.json")"
  echo "$name: $data"
  python3 - "$wanted" "$data" <<'PY'
import json,sys
p=json.loads(sys.argv[2]);assert p.get('status')==sys.argv[1],p
PY
}
printf '\n=== A. Manifest and partial chunk ACK atomic ===\n'
expect header received
expect chunk-000 received
assert_sql "SELECT COUNT(*) FROM sync_receipts WHERE vessel_id=UUID_TO_BIN('$VESSEL')" 2
expect chunk-000 already_received
printf '\n=== B. Incomplete finalize is not receipted ===\n'
expect finalize incomplete
assert_sql "SELECT COUNT(*) FROM sync_receipts WHERE vessel_id=UUID_TO_BIN('$VESSEL')" 2
expect chunk-001 received
printf '\n=== C. Rollback before COMMIT also rolls back receipt ===\n'
set +e
err="$(sudo -n env YM_CATALOG_ATOMIC_FAULT=throw-before-commit /usr/bin/php "$R" --authenticated-vessel "$VESSEL" < fixtures/atomic-finalize.json 2>&1)"
rc=$?
set -e
printf '%s\n' "$err"
[[ "$rc" -ne 0 && "$err" == *INJECTED_ATOMIC_FAULT_BEFORE_COMMIT* ]] || { echo 'FAIL: injection'; exit 1; }
assert_sql "SELECT COUNT(*) FROM sync_receipts WHERE vessel_id=UUID_TO_BIN('$VESSEL')" 3
assert_sql "SELECT status FROM signalk_catalog_snapshots_v2 WHERE snapshot_id=UUID_TO_BIN('$SID')" staging
printf '\n=== D. Commit with lost ACK and recovery by receipt ===\n'
set +e
err="$(sudo -n env YM_CATALOG_ATOMIC_FAULT=exit-after-commit /usr/bin/php "$R" --authenticated-vessel "$VESSEL" < fixtures/atomic-finalize.json 2>&1)"
rc=$?
set -e
printf '%s\n' "$err"
[[ "$rc" -ne 0 && "$err" == *INJECTED_ATOMIC_LOST_ACK_AFTER_COMMIT* ]] || { echo 'FAIL: lost ACK simulation'; exit 1; }
assert_sql "SELECT status FROM signalk_catalog_snapshots_v2 WHERE snapshot_id=UUID_TO_BIN('$SID')" active
assert_sql "SELECT COUNT(*) FROM sync_receipts WHERE vessel_id=UUID_TO_BIN('$VESSEL')" 4
expect finalize already_received
assert_sql "SELECT revision FROM signalk_catalog_active_v2 WHERE vessel_id=UUID_TO_BIN('$VESSEL')" 1
assert_sql "SELECT COUNT(*) FROM signalk_catalog_snapshots_v2 WHERE snapshot_id=UUID_TO_BIN('$SID') AND status='active'" 1
printf '\n=== ATOMIC RECEIPT MYSQL TEST PASS ===\n'
