#!/usr/bin/env bash

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COMPOSE_FILE="${COMPOSE_FILE:-${SCRIPT_DIR}/../docker-compose.yml}"

BASE_URL="${BASE_URL:-http://localhost:5270}"
REDIS_PORT="${REDIS_PORT:-6382}"
REDIS_KEY="${REDIS_KEY:-threshold:HEART_RATE}"
RECORDED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"

TMP_FILES=()

cleanup() {
  local f
  for f in "${TMP_FILES[@]}"; do
    rm -f "${f}" "${f}.status"
  done
}
trap cleanup EXIT

if ! command -v curl >/dev/null 2>&1; then
  echo "Missing dependency: curl"
  exit 1
fi

if ! command -v jq >/dev/null 2>&1; then
  echo "Missing dependency: jq"
  exit 1
fi

redis_cmd() {
  if command -v redis-cli >/dev/null 2>&1; then
    redis-cli -p "${REDIS_PORT}" "$@"
  elif command -v docker >/dev/null 2>&1 && [[ -f "${COMPOSE_FILE}" ]]; then
    docker compose -f "${COMPOSE_FILE}" exec -T redis redis-cli "$@"
  else
    echo "Missing dependency: redis-cli (or docker compose with redis service)"
    exit 1
  fi
}

request() {
  local method="$1"
  local url="$2"
  local body="${3:-}"
  local tmp_body
  tmp_body="$(mktemp)"
  TMP_FILES+=("${tmp_body}")
  local status

  if [[ -n "${body}" ]]; then
    status="$(curl -sS -o "${tmp_body}" -w "%{http_code}" -X "${method}" "${url}" \
      -H "Content-Type: application/json" -d "${body}")"
  else
    status="$(curl -sS -o "${tmp_body}" -w "%{http_code}" -X "${method}" "${url}")"
  fi

  echo "${status}" > "${tmp_body}.status"
  echo "${tmp_body}"
}

assert_status() {
  local expected="$1"
  local body_file="$2"
  local status
  status="$(cat "${body_file}.status")"
  if [[ "${status}" != "${expected}" ]]; then
    echo "Expected HTTP ${expected}, got ${status}"
    echo "Response body:"
    cat "${body_file}"
    echo
    return 1
  fi
}

assert_json() {
  local body_file="$1"
  local jq_expr="$2"
  local expected="$3"
  local actual
  actual="$(jq -r "${jq_expr}" "${body_file}")"
  if [[ "${actual}" != "${expected}" ]]; then
    echo "Expected ${jq_expr} = ${expected}, got ${actual}"
    echo "Response body:"
    cat "${body_file}"
    echo
    return 1
  fi
}

TOTAL_STEPS=16

echo "Running API + Redis verification against ${BASE_URL}"
echo "Recorded-at timestamp: ${RECORDED_AT}"

echo ""
echo "[0/${TOTAL_STEPS}] Preflight — API reachable"
preflight_status="$(curl -sS -o /dev/null -w "%{http_code}" "${BASE_URL}/api/v1/alert-thresholds" || true)"
if [[ "${preflight_status}" != "200" ]]; then
  echo "API not reachable at ${BASE_URL} (HTTP ${preflight_status})."
  echo "Start the API with: dotnet run --project VigilCareClinicalAPI"
  exit 1
fi
echo "OK: API is up"

echo ""
echo "[1/${TOTAL_STEPS}] Listing thresholds"
resp="$(request GET "${BASE_URL}/api/v1/alert-thresholds")"
assert_status "200" "${resp}"
threshold_count="$(jq -r '.data | length' "${resp}")"
if [[ "${threshold_count}" -lt 12 ]]; then
  echo "Expected at least 12 alert thresholds, found ${threshold_count}."
  exit 1
fi
echo "OK: ${threshold_count} threshold(s) configured"
threshold_id="$(jq -r '.data[] | select(.observationCode=="HEART_RATE") | .id' "${resp}" | head -n 1)"
if [[ -z "${threshold_id}" || "${threshold_id}" == "null" ]]; then
  echo "Could not find HEART_RATE threshold id."
  exit 1
fi
echo "OK: HEART_RATE threshold id = ${threshold_id}"

echo ""
echo "[2/${TOTAL_STEPS}] Registering patient"
patient_payload='{"firstName":"Test","lastName":"Runner","dateOfBirth":"1988-01-10","gender":"F"}'
resp="$(request POST "${BASE_URL}/api/v1/patients" "${patient_payload}")"
assert_status "201" "${resp}"
patient_id="$(jq -r '.data.id' "${resp}")"
if [[ -z "${patient_id}" || "${patient_id}" == "null" ]]; then
  echo "Could not parse patient id."
  exit 1
fi
echo "OK: patient id = ${patient_id}"

echo ""
echo "[3/${TOTAL_STEPS}] Opening encounter"
enc_payload='{"encounterType":"Inpatient","department":"ICU","attendingPhysician":"Dr. Script"}'
resp="$(request POST "${BASE_URL}/api/v1/patients/${patient_id}/encounters" "${enc_payload}")"
assert_status "201" "${resp}"
encounter_id="$(jq -r '.data.id' "${resp}")"
if [[ -z "${encounter_id}" || "${encounter_id}" == "null" ]]; then
  echo "Could not parse encounter id."
  exit 1
fi
echo "OK: encounter id = ${encounter_id}"

echo ""
echo "[4/${TOTAL_STEPS}] Verifying illegal status transition returns 409"
transition_payload='{"status":"Scheduled"}'
resp="$(request PATCH "${BASE_URL}/api/v1/encounters/${encounter_id}/status" "${transition_payload}")"
assert_status "409" "${resp}"
error_code="$(jq -r '.error.code' "${resp}")"
echo "OK: illegal transition blocked (${error_code})"

echo ""
echo "[5/${TOTAL_STEPS}] Updating HEART_RATE threshold"
update_payload='{"observationCode":"HEART_RATE","displayName":"Heart Rate","unit":"bpm","criticalLow":30,"warningLow":50,"warningHigh":110,"criticalHigh":160}'
resp="$(request PUT "${BASE_URL}/api/v1/alert-thresholds/${threshold_id}" "${update_payload}")"
assert_status "200" "${resp}"
echo "OK: threshold update accepted"

echo ""
echo "[6/${TOTAL_STEPS}] Verifying Redis invalidation"
redis_value="$(redis_cmd GET "${REDIS_KEY}" | tr -d '\r')"
if [[ "${redis_value}" != "(nil)" && -n "${redis_value}" ]]; then
  echo "Expected Redis key ${REDIS_KEY} to be invalidated, but found value."
  echo "Value: ${redis_value}"
  exit 1
fi
echo "OK: Redis key invalidated (${REDIS_KEY})"

echo ""
echo "[7/${TOTAL_STEPS}] Listing patient"
resp="$(request GET "${BASE_URL}/api/v1/patients/${patient_id}")"
assert_status "200" "${resp}"
echo "OK: patient lookup succeeds"

echo ""
echo "[8/${TOTAL_STEPS}] Ingesting normal observation (no alert)"
normal_obs_payload="$(jq -nc \
  --arg recordedAt "${RECORDED_AT}" \
  '{observations:[{observationCode:"HEART_RATE",value:78,unit:"bpm",source:"DEVICE",recordedAt:$recordedAt}]}')"
resp="$(request POST "${BASE_URL}/api/v1/encounters/${encounter_id}/observations" "${normal_obs_payload}")"
assert_status "201" "${resp}"
assert_json "${resp}" '.data.alertGenerated' 'false'
echo "OK: normal observation ingested without alert"

echo ""
echo "[9/${TOTAL_STEPS}] Ingesting critical potassium (alert expected)"
critical_obs_payload="$(jq -nc \
  --arg recordedAt "${RECORDED_AT}" \
  '{observations:[{observationCode:"POTASSIUM_MEQ_L",value:2.1,unit:"mEq/L",source:"LAB",recordedAt:$recordedAt,idempotencyKey:"script-critical-001"}]}')"
resp="$(request POST "${BASE_URL}/api/v1/encounters/${encounter_id}/observations" "${critical_obs_payload}")"
assert_status "201" "${resp}"
assert_json "${resp}" '.data.alertGenerated' 'true'
alert_id="$(jq -r '.data.alertId' "${resp}")"
if [[ -z "${alert_id}" || "${alert_id}" == "null" ]]; then
  echo "Could not parse alert id from critical ingest."
  exit 1
fi
echo "OK: critical alert generated (alert id = ${alert_id})"

echo ""
echo "[10/${TOTAL_STEPS}] Fetching observation history"
resp="$(request GET "${BASE_URL}/api/v1/encounters/${encounter_id}/observations?code=HEART_RATE&limit=10")"
assert_status "200" "${resp}"
history_count="$(jq -r '.data.items | length' "${resp}")"
if [[ "${history_count}" -lt 1 ]]; then
  echo "Expected at least one HEART_RATE observation in history, got ${history_count}"
  exit 1
fi
echo "OK: observation history returned ${history_count} item(s)"

echo ""
echo "[11/${TOTAL_STEPS}] Resolving unacknowledged alert returns 409"
resp="$(request POST "${BASE_URL}/api/v1/alerts/${alert_id}/resolve")"
assert_status "409" "${resp}"
assert_json "${resp}" '.error.code' 'ALERT_NOT_ACKNOWLEDGED'
echo "OK: resolve blocked before acknowledge"

echo ""
echo "[12/${TOTAL_STEPS}] Acknowledging alert"
ack_payload='{"clinicianId":"DR-SCRIPT","note":"Reviewing from verification script."}'
resp="$(request POST "${BASE_URL}/api/v1/alerts/${alert_id}/acknowledge" "${ack_payload}")"
assert_status "200" "${resp}"
assert_json "${resp}" '.data.status' 'Acknowledged'
echo "OK: alert acknowledged"

echo ""
echo "[13/${TOTAL_STEPS}] Resolving acknowledged alert"
resp="$(request POST "${BASE_URL}/api/v1/alerts/${alert_id}/resolve")"
assert_status "200" "${resp}"
assert_json "${resp}" '.data.status' 'Resolved'
echo "OK: alert resolved"

echo ""
echo "[14/${TOTAL_STEPS}] Rejecting implausible observation with 422"
implausible_payload="$(jq -nc \
  --arg recordedAt "${RECORDED_AT}" \
  '{observations:[{observationCode:"HEART_RATE",value:350,unit:"bpm",source:"DEVICE",recordedAt:$recordedAt}]}')"
resp="$(request POST "${BASE_URL}/api/v1/encounters/${encounter_id}/observations" "${implausible_payload}")"
assert_status "422" "${resp}"
assert_json "${resp}" '.error.code' 'OBSERVATION_OUT_OF_PLAUSIBLE_RANGE'
echo "OK: implausible value rejected"

echo ""
echo "[15/${TOTAL_STEPS}] Discharging encounter"
discharge_payload='{"status":"Discharged"}'
resp="$(request PATCH "${BASE_URL}/api/v1/encounters/${encounter_id}/status" "${discharge_payload}")"
assert_status "200" "${resp}"
echo "OK: encounter discharged"

echo ""
echo "[16/${TOTAL_STEPS}] Ingest against discharged encounter returns 409"
post_discharge_payload="$(jq -nc \
  --arg recordedAt "${RECORDED_AT}" \
  '{observations:[{observationCode:"HEART_RATE",value:78,unit:"bpm",source:"DEVICE",recordedAt:$recordedAt}]}')"
resp="$(request POST "${BASE_URL}/api/v1/encounters/${encounter_id}/observations" "${post_discharge_payload}")"
assert_status "409" "${resp}"
assert_json "${resp}" '.error.code' 'ENCOUNTER_NOT_ACTIVE'
echo "OK: ingest blocked for discharged encounter"

echo ""
echo "All ${TOTAL_STEPS} API + Redis checks passed."
