#!/usr/bin/env bash
# Runs Phase 2 verification checks from docs/plans/phase-2-plan.md.
#
# Prerequisites:
#   docker compose up -d          (PostgreSQL + Redis)
#   dotnet run --project VigilCareRecordsAPI
#   Phase 1 seed data (entry1, entry2, intake1 users)
#
# Environment overrides (same defaults as Phase 1 script):
#   VIGILCARE_API_URL          default: http://localhost:5217
#   VIGILCARE_COMPOSE_FILE     default: <repo>/docker-compose.yml
#   VIGILCARE_PG_HOST          default: localhost
#   VIGILCARE_PG_PORT          default: 5437
#   VIGILCARE_PG_DB            default: vigilcare_records
#   VIGILCARE_PG_USER          default: postgres
#   VIGILCARE_PG_PASSWORD      default: password
#   VIGILCARE_SKIP_DB_CHECKS   set to 1 to skip PostgreSQL assertions

set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
FIXTURE_PDF="$SCRIPT_DIR/fixtures/test-scan.pdf"

API_URL="${VIGILCARE_API_URL:-http://localhost:5217}"
COMPOSE_FILE="${VIGILCARE_COMPOSE_FILE:-$REPO_ROOT/docker-compose.yml}"
COMPOSE=(docker compose -f "$COMPOSE_FILE")
PG_HOST="${VIGILCARE_PG_HOST:-localhost}"
PG_PORT="${VIGILCARE_PG_PORT:-5437}"
PG_DB="${VIGILCARE_PG_DB:-vigilcare_records}"
PG_USER="${VIGILCARE_PG_USER:-postgres}"
PG_PASSWORD="${VIGILCARE_PG_PASSWORD:-password}"
SKIP_DB_CHECKS="${VIGILCARE_SKIP_DB_CHECKS:-0}"

RECORDED_AT="${VIGILCARE_RECORDED_AT:-2025-01-01T10:00:00Z}"

PASS_COUNT=0
FAIL_COUNT=0
FAILED_TESTS=()

log() {
  printf '%s\n' "$*"
}

section() {
  log ""
  log "== $1 =="
}

pass() {
  PASS_COUNT=$((PASS_COUNT + 1))
  log "  PASS: $1"
}

fail() {
  FAIL_COUNT=$((FAIL_COUNT + 1))
  FAILED_TESTS+=("$1")
  log "  FAIL: $1"
}

require_cmd() {
  local cmd="$1"
  if ! command -v "$cmd" >/dev/null 2>&1; then
    log "ERROR: required command not found: $cmd"
    exit 1
  fi
}

compose_service_running() {
  local service="$1"
  "${COMPOSE[@]}" ps --status running --services 2>/dev/null | grep -qx "$service"
}

psql_available() {
  [[ "$SKIP_DB_CHECKS" == "1" ]] && return 1
  command -v psql >/dev/null 2>&1 && return 0
  compose_service_running postgres
}

psql_query() {
  if command -v psql >/dev/null 2>&1; then
    PGPASSWORD="$PG_PASSWORD" psql -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" -Atqc "$1"
  elif compose_service_running postgres; then
    "${COMPOSE[@]}" exec -T postgres \
      psql -U "$PG_USER" -d "$PG_DB" -Atqc "$1"
  else
    return 1
  fi
}

http_code() {
  curl -sS -o /dev/null -w '%{http_code}' "$@"
}

json_post() {
  local url="$1"
  local body="$2"
  local token="${3:-}"
  if [[ -n "$token" ]]; then
    curl -sS -X POST "$url" \
      -H "Authorization: Bearer $token" \
      -H 'Content-Type: application/json' \
      -d "$body"
  else
    curl -sS -X POST "$url" \
      -H 'Content-Type: application/json' \
      -d "$body"
  fi
}

json_put() {
  local url="$1"
  local body="$2"
  local token="$3"
  curl -sS -X PUT "$url" \
    -H "Authorization: Bearer $token" \
    -H 'Content-Type: application/json' \
    -d "$body"
}

login() {
  local username="$1"
  local password="${2:-password}"
  json_post "$API_URL/api/v1/auth/login" \
    "{\"username\":\"$username\",\"password\":\"$password\"}"
}

extract_data_field() {
  local json="$1"
  local field="$2"
  jq -er ".data.$field // empty" <<<"$json"
}

extract_error_code() {
  local json="$1"
  jq -er '.error.code // empty' <<<"$json"
}

extract_error_message() {
  local json="$1"
  jq -er '.error.message // empty' <<<"$json"
}

upload_batch() {
  local token="$1"
  local file_path="${2:-$FIXTURE_PDF}"

  curl -sS -X POST "$API_URL/api/v1/digitization-batches" \
    -H "Authorization: Bearer $token" \
    -F "file=@${file_path};type=application/pdf" \
    -F "batchType=VITALS_SHEET"
}

assign_batch() {
  local token="$1"
  local batch_id="$2"
  local entry_clerk_id="$3"

  curl -sS -X PATCH "$API_URL/api/v1/digitization-batches/$batch_id/assign" \
    -H "Authorization: Bearer $token" \
    -H 'Content-Type: application/json' \
    -d "{\"entryClerkUserId\":\"$entry_clerk_id\"}"
}

assert_api_reachable() {
  local code
  code="$(http_code "$API_URL/swagger/index.html" || true)"
  if [[ "$code" != "200" ]]; then
    log "ERROR: API not reachable at $API_URL (HTTP $code)."
    log "Start infrastructure with: docker compose up -d"
    log "Start API with: dotnet run --project VigilCareRecordsAPI"
    exit 1
  fi
}

# Upload a VITALS_SHEET batch and assign it to entry1.
# Prints the batch id to stdout.
create_assigned_vitals_batch() {
  local intake_token="$1"
  local upload_json batch_id entry_json entry_id

  upload_json="$(upload_batch "$intake_token")"
  if [[ "$(jq -er '.success' <<<"$upload_json")" != "true" ]]; then
    log "ERROR: failed to upload batch for test setup"
    return 1
  fi

  batch_id="$(extract_data_field "$upload_json" id)"
  entry_json="$(login entry1)"
  entry_id="$(extract_data_field "$entry_json" userId)"
  assign_batch "$intake_token" "$batch_id" "$entry_id" >/dev/null

  printf '%s' "$batch_id"
}

test_draft_patient_upsert() {
  section "1. Draft CRUD — patient upsert creates and updates"

  local intake_json intake_token entry_json entry_token batch_id
  local first_json second_json blood_type

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry_json="$(login entry1)"
  entry_token="$(extract_data_field "$entry_json" token)"

  first_json="$(json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/patient" \
    '{"fullName":"Chen Wei-Lin","dateOfBirth":"1985-03-15","sex":"M","noKnownAllergies":true,"noActiveMedications":true}' \
    "$entry_token")"
  if [[ "$(jq -er '.success' <<<"$first_json")" == "true" ]]; then
    pass "first patient PUT creates draft patient (200)"
  else
    fail "first patient PUT creates draft patient (200)"
    return
  fi

  second_json="$(json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/patient" \
    '{"fullName":"Chen Wei-Lin","dateOfBirth":"1985-03-15","sex":"M","bloodType":"O+","noKnownAllergies":true,"noActiveMedications":true}' \
    "$entry_token")"
  blood_type="$(extract_data_field "$second_json" bloodType)"
  if [[ "$(jq -er '.success' <<<"$second_json")" == "true" && "$blood_type" == "O+" ]]; then
    pass "second patient PUT updates draft patient (bloodType added)"
  else
    fail "second patient PUT updates draft patient (bloodType added) (got: ${blood_type:-<none>})"
  fi
}

test_status_transition_to_in_entry() {
  section "2. Status transitions — first draft save moves to IN_ENTRY"

  local intake_json intake_token entry_json entry_token batch_id status_before status_after

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry_json="$(login entry1)"
  entry_token="$(extract_data_field "$entry_json" token)"

  status_before="$(curl -sS "$API_URL/api/v1/digitization-batches/$batch_id" \
    -H "Authorization: Bearer $entry_token" | jq -er '.data.status')"
  if [[ "$status_before" == "UPLOADED" ]]; then
    pass "batch status is UPLOADED before first draft save"
  else
    fail "batch status is UPLOADED before first draft save (got: $status_before)"
  fi

  json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/patient" \
    '{"fullName":"Test Patient","noKnownAllergies":true,"noActiveMedications":true}' \
    "$entry_token" >/dev/null

  status_after="$(curl -sS "$API_URL/api/v1/digitization-batches/$batch_id" \
    -H "Authorization: Bearer $entry_token" | jq -er '.data.status')"
  if [[ "$status_after" == "IN_ENTRY" ]]; then
    pass "batch status transitions to IN_ENTRY after first draft save"
  else
    fail "batch status transitions to IN_ENTRY after first draft save (got: $status_after)"
  fi
}

test_plausibility_validation() {
  section "3. Plausibility validation — implausible values rejected"

  local intake_json intake_token entry_json entry_token batch_id
  local bad_json bad_code good_code

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry_json="$(login entry1)"
  entry_token="$(extract_data_field "$entry_json" token)"

  bad_json="$(json_post \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/observations" \
    "{\"observationCode\":\"HEART_RATE\",\"value\":350,\"unit\":\"bpm\",\"recordedAt\":\"$RECORDED_AT\"}" \
    "$entry_token")"
  bad_code="$(extract_error_code "$bad_json")"
  if [[ "$bad_code" == "OBSERVATION_OUT_OF_PLAUSIBLE_RANGE" ]]; then
    pass "heart rate 350 bpm returns OBSERVATION_OUT_OF_PLAUSIBLE_RANGE"
  else
    fail "heart rate 350 bpm returns OBSERVATION_OUT_OF_PLAUSIBLE_RANGE (got: ${bad_code:-<none>})"
  fi

  good_code="$(http_code -X POST \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/observations" \
    -H "Authorization: Bearer $entry_token" \
    -H 'Content-Type: application/json' \
    -d "{\"observationCode\":\"HEART_RATE\",\"value\":78,\"unit\":\"bpm\",\"recordedAt\":\"$RECORDED_AT\"}")"
  if [[ "$good_code" == "201" ]]; then
    pass "heart rate 78 bpm saves successfully (201)"
  else
    fail "heart rate 78 bpm saves successfully (201) (got: $good_code)"
  fi
}

test_incomplete_submit_rejected() {
  section "4. Submit-for-verification — incomplete batch rejected"

  local intake_json intake_token entry_json entry_token batch_id
  local submit_body submit_code error_code error_msg
  local submit_tmp

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry_json="$(login entry1)"
  entry_token="$(extract_data_field "$entry_json" token)"

  json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/patient" \
    '{"fullName":"Test Patient","noKnownAllergies":true,"noActiveMedications":true}' \
    "$entry_token" >/dev/null

  submit_tmp="$(mktemp)"
  submit_code="$(curl -sS -o "$submit_tmp" -w '%{http_code}' -X POST \
    "$API_URL/api/v1/digitization-batches/$batch_id/submit-for-verification" \
    -H "Authorization: Bearer $entry_token")"
  submit_body="$(cat "$submit_tmp")"
  rm -f "$submit_tmp"
  error_code="$(extract_error_code "$submit_body")"
  error_msg="$(extract_error_message "$submit_body")"

  if [[ "$submit_code" == "422" && "$error_code" == "BATCH_INCOMPLETE" ]]; then
    pass "incomplete vitals batch submit returns 422 BATCH_INCOMPLETE"
  else
    fail "incomplete vitals batch submit returns 422 BATCH_INCOMPLETE (http=$submit_code code=${error_code:-<none>})"
    return
  fi

  if [[ "$error_msg" == *"Encounter context is required"* &&
        "$error_msg" == *"At least one observation"* ]]; then
    pass "BATCH_INCOMPLETE message lists missing encounter and observations"
  else
    fail "BATCH_INCOMPLETE message lists missing encounter and observations"
  fi
}

test_get_draft_payload() {
  section "5. Full draft payload — GET returns patient, encounter, observations"

  local intake_json intake_token entry_json entry_token batch_id draft_json
  local patient_name department obs_count

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry_json="$(login entry1)"
  entry_token="$(extract_data_field "$entry_json" token)"

  json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/patient" \
    '{"fullName":"Chen Wei-Lin","dateOfBirth":"1985-03-15","sex":"M","noKnownAllergies":true,"noActiveMedications":true}' \
    "$entry_token" >/dev/null

  json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/encounter" \
    '{"admissionDate":"2025-01-01T08:00:00Z","department":"ICU","roomBed":"ICU-3B","admissionReason":"Chest pain"}' \
    "$entry_token" >/dev/null

  json_post \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/observations" \
    "{\"observationCode\":\"HEART_RATE\",\"value\":92,\"unit\":\"bpm\",\"recordedAt\":\"$RECORDED_AT\"}" \
    "$entry_token" >/dev/null

  draft_json="$(curl -sS "$API_URL/api/v1/digitization-batches/$batch_id/draft" \
    -H "Authorization: Bearer $entry_token")"
  patient_name="$(jq -er '.data.patient.fullName // empty' <<<"$draft_json")"
  department="$(jq -er '.data.encounter.department // empty' <<<"$draft_json")"
  obs_count="$(jq -er '.data.observations | length' <<<"$draft_json")"

  if [[ "$patient_name" == "Chen Wei-Lin" && "$department" == "ICU" && "$obs_count" -ge 1 ]]; then
    pass "GET /draft returns patient, encounter, and observations"
  else
    fail "GET /draft returns patient, encounter, and observations (patient=$patient_name dept=$department obs=$obs_count)"
  fi
}

test_complete_submit_succeeds() {
  section "6. Full lifecycle — complete vitals batch submits to PENDING_VERIFICATION"

  local intake_json intake_token entry_json entry_token batch_id submit_json status

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry_json="$(login entry1)"
  entry_token="$(extract_data_field "$entry_json" token)"

  json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/patient" \
    '{"fullName":"Chen Wei-Lin","dateOfBirth":"1985-03-15","sex":"M","noKnownAllergies":true,"noActiveMedications":true}' \
    "$entry_token" >/dev/null

  json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/encounter" \
    '{"admissionDate":"2025-01-01T08:00:00Z","department":"ICU","admissionReason":"Chest pain"}' \
    "$entry_token" >/dev/null

  json_post \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/observations" \
    "{\"observationCode\":\"HEART_RATE\",\"value\":92,\"unit\":\"bpm\",\"recordedAt\":\"$RECORDED_AT\"}" \
    "$entry_token" >/dev/null

  submit_json="$(curl -sS -X POST \
    "$API_URL/api/v1/digitization-batches/$batch_id/submit-for-verification" \
    -H "Authorization: Bearer $entry_token")"
  status="$(extract_data_field "$submit_json" status)"

  if [[ "$(jq -er '.success' <<<"$submit_json")" == "true" && "$status" == "PENDING_VERIFICATION" ]]; then
    pass "complete vitals batch submits successfully (PENDING_VERIFICATION)"
  else
    fail "complete vitals batch submits successfully (PENDING_VERIFICATION) (status=${status:-<none>})"
  fi
}

test_observation_crud() {
  section "7. Observation CRUD — add, update, delete"

  local intake_json intake_token entry_json entry_token batch_id
  local add_json obs_id update_json update_value delete_code

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry_json="$(login entry1)"
  entry_token="$(extract_data_field "$entry_json" token)"

  add_json="$(json_post \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/observations" \
    "{\"observationCode\":\"TEMP_C\",\"value\":37.2,\"unit\":\"C\",\"recordedAt\":\"$RECORDED_AT\",\"note\":\"Oral temperature\"}" \
    "$entry_token")"
  obs_id="$(extract_data_field "$add_json" id)"
  if [[ "$(jq -er '.success' <<<"$add_json")" == "true" && -n "$obs_id" ]]; then
    pass "POST observation returns 201 with id"
  else
    fail "POST observation returns 201 with id"
    return
  fi

  update_json="$(json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/observations/$obs_id" \
    "{\"observationCode\":\"TEMP_C\",\"value\":38.1,\"unit\":\"C\",\"recordedAt\":\"$RECORDED_AT\",\"note\":\"Corrected — misread decimal\"}" \
    "$entry_token")"
  update_value="$(extract_data_field "$update_json" value)"
  if [[ "$(jq -er '.success' <<<"$update_json")" == "true" && "$update_value" == "38.1" ]]; then
    pass "PUT observation updates value (200)"
  else
    fail "PUT observation updates value (200) (got: ${update_value:-<none>})"
  fi

  delete_code="$(http_code -X DELETE \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/observations/$obs_id" \
    -H "Authorization: Bearer $entry_token")"
  if [[ "$delete_code" == "204" ]]; then
    pass "DELETE observation returns 204"
  else
    fail "DELETE observation returns 204 (got: $delete_code)"
  fi
}

test_rejected_batch_reentry() {
  section "8. Rejected batch — draft save transitions back to IN_ENTRY"

  if ! psql_available; then
    if [[ "$SKIP_DB_CHECKS" == "1" ]]; then
      log "  SKIP: rejected batch re-entry (VIGILCARE_SKIP_DB_CHECKS=1)"
    else
      log "  SKIP: rejected batch re-entry (postgres not reachable)"
    fi
    return
  fi

  local intake_json intake_token entry_json entry_token batch_id status event_meta

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry_json="$(login entry1)"
  entry_token="$(extract_data_field "$entry_json" token)"

  psql_query "UPDATE digitization_batches SET status = 'REJECTED', rejection_reason = 'Missing encounter details' WHERE id = '$batch_id';" >/dev/null

  json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/encounter" \
    '{"admissionDate":"2025-01-01T08:00:00Z","department":"Emergency Department","roomBed":"ER-7"}' \
    "$entry_token" >/dev/null

  status="$(curl -sS "$API_URL/api/v1/digitization-batches/$batch_id" \
    -H "Authorization: Bearer $entry_token" | jq -er '.data.status')"
  if [[ "$status" == "IN_ENTRY" ]]; then
    pass "REJECTED batch transitions to IN_ENTRY on draft save"
  else
    fail "REJECTED batch transitions to IN_ENTRY on draft save (got: $status)"
  fi

  event_meta="$(psql_query "SELECT metadata_json FROM digitization_events WHERE batch_id = '$batch_id' AND event_type = 'entry_started' ORDER BY occurred_at DESC LIMIT 1;")"
  if [[ "$event_meta" == *"REJECTED"* ]]; then
    pass "entry_started event metadata records previous REJECTED status"
  else
    fail "entry_started event metadata records previous REJECTED status"
  fi
}

test_verified_batch_blocks_entry() {
  section "9. Verified batch — data entry blocked with ENTRY_NOT_ALLOWED"

  if ! psql_available; then
    if [[ "$SKIP_DB_CHECKS" == "1" ]]; then
      log "  SKIP: verified batch entry guard (VIGILCARE_SKIP_DB_CHECKS=1)"
    else
      log "  SKIP: verified batch entry guard (postgres not reachable)"
    fi
    return
  fi

  local intake_json intake_token entry_json entry_token batch_id resp_json error_code

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry_json="$(login entry1)"
  entry_token="$(extract_data_field "$entry_json" token)"

  psql_query "UPDATE digitization_batches SET status = 'VERIFIED' WHERE id = '$batch_id';" >/dev/null

  resp_json="$(json_post \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/observations" \
    "{\"observationCode\":\"HEART_RATE\",\"value\":80,\"unit\":\"bpm\",\"recordedAt\":\"$RECORDED_AT\"}" \
    "$entry_token")"
  error_code="$(extract_error_code "$resp_json")"

  if [[ "$error_code" == "ENTRY_NOT_ALLOWED" ]]; then
    pass "verified batch blocks observation add (ENTRY_NOT_ALLOWED)"
  else
    fail "verified batch blocks observation add (ENTRY_NOT_ALLOWED) (got: ${error_code:-<none>})"
  fi
}

test_batch_not_assigned() {
  section "10. Assignment guard — non-assigned clerk receives BATCH_NOT_ASSIGNED"

  local intake_json intake_token entry1_json entry2_json entry2_token batch_id entry1_id resp_json error_code

  intake_json="$(login intake1)"
  intake_token="$(extract_data_field "$intake_json" token)"
  batch_id="$(create_assigned_vitals_batch "$intake_token")" || return

  entry1_json="$(login entry1)"
  entry1_id="$(extract_data_field "$entry1_json" userId)"
  entry2_json="$(login entry2)"
  entry2_token="$(extract_data_field "$entry2_json" token)"

  assign_batch "$intake_token" "$batch_id" "$entry1_id" >/dev/null

  resp_json="$(json_put \
    "$API_URL/api/v1/digitization-batches/$batch_id/draft/patient" \
    '{"fullName":"Blocked Clerk","noKnownAllergies":true,"noActiveMedications":true}' \
    "$entry2_token")"
  error_code="$(extract_error_code "$resp_json")"

  if [[ "$error_code" == "BATCH_NOT_ASSIGNED" ]]; then
    pass "entry2 cannot save draft on batch assigned to entry1 (BATCH_NOT_ASSIGNED)"
  else
    fail "entry2 cannot save draft on batch assigned to entry1 (BATCH_NOT_ASSIGNED) (got: ${error_code:-<none>})"
  fi
}

main() {
  require_cmd curl
  require_cmd jq

  if [[ ! -f "$FIXTURE_PDF" ]]; then
    log "ERROR: missing fixture PDF at $FIXTURE_PDF"
    exit 1
  fi

  log "VigilCare Records — Phase 2 verification"
  log "API: $API_URL"

  assert_api_reachable

  test_draft_patient_upsert
  test_status_transition_to_in_entry
  test_plausibility_validation
  test_incomplete_submit_rejected
  test_get_draft_payload
  test_complete_submit_succeeds
  test_observation_crud
  test_rejected_batch_reentry
  test_verified_batch_blocks_entry
  test_batch_not_assigned

  log ""
  log "Results: $PASS_COUNT passed, $FAIL_COUNT failed"
  if (( FAIL_COUNT > 0 )); then
    log "Failed checks:"
    for item in "${FAILED_TESTS[@]}"; do
      log "  - $item"
    done
    exit 1
  fi

  log "All Phase 2 verification checks passed."
}

main "$@"
