#!/usr/bin/env bash
set -euo pipefail

BASE_URL="${1:-http://localhost:8080}"
PROVIDER="${LDAP_SMOKE_PROVIDER:-ldap}"
USERNAME="${LDAP_SMOKE_USERNAME:-}"
PASSWORD="${LDAP_SMOKE_PASSWORD:-}"
RENAMED_USERNAME="${LDAP_SMOKE_RENAMED_USERNAME:-}"
RENAMED_PASSWORD="${LDAP_SMOKE_RENAMED_PASSWORD:-$PASSWORD}"
WRONG_PASSWORD="${LDAP_SMOKE_WRONG_PASSWORD:-skillhub-invalid-password}"
UNKNOWN_USERNAME="${LDAP_SMOKE_UNKNOWN_USERNAME:-${USERNAME}-unknown}"
COOKIE_JAR="$(mktemp)"
RESPONSE_FILE="$(mktemp)"
PASS=0
FAIL=0

cleanup() {
  rm -f "$COOKIE_JAR" "$RESPONSE_FILE"
}
trap cleanup EXIT

if [[ -z "$USERNAME" || -z "$PASSWORD" ]]; then
  echo "ERROR: LDAP_SMOKE_USERNAME and LDAP_SMOKE_PASSWORD are required" >&2
  exit 2
fi

csrf_token() {
  awk '$6 == "XSRF-TOKEN" { print $7 }' "$COOKIE_JAR" | tail -n 1
}

refresh_csrf() {
  # Logout invalidates the server session; warm a fresh anonymous session so
  # the next direct-login request uses a token bound to that new session.
  curl --max-time 10 -s -c "$COOKIE_JAR" \
    "$BASE_URL/api/v1/auth/me" >/dev/null || true
  CSRF_TOKEN="$(csrf_token)"
}

check_status() {
  local description="$1"
  local actual="$2"
  local expected="$3"
  if [[ "$actual" == "$expected" ]]; then
    echo "PASS: $description (HTTP $actual)"
    PASS=$((PASS + 1))
  else
    echo "FAIL: $description (expected HTTP $expected, got $actual)"
    FAIL=$((FAIL + 1))
  fi
}

json_user_id() {
  python3 - "$RESPONSE_FILE" <<'PY'
import json
import sys

try:
    with open(sys.argv[1], encoding="utf-8") as response:
        print(json.load(response)["data"]["userId"])
except (KeyError, TypeError, json.JSONDecodeError):
    raise SystemExit(1)
PY
}

echo "=== SkillHub LDAP Operator Smoke Test ==="
echo "Target: $BASE_URL"
echo "Provider: $PROVIDER"
echo

HEALTH_STATUS="$(curl --retry 3 --retry-delay 1 --max-time 10 -s \
  -o /dev/null -w "%{http_code}" \
  "$BASE_URL/actuator/health" || true)"
check_status "Health endpoint" "$HEALTH_STATUS" "200"

METHODS_STATUS="$(curl --max-time 10 -s \
  -o "$RESPONSE_FILE" -w "%{http_code}" \
  "$BASE_URL/api/v1/auth/methods" || true)"
if [[ "$METHODS_STATUS" == "200" ]] \
  && PROVIDER_VALUE="$PROVIDER" python3 - "$RESPONSE_FILE" <<'PY'
import json
import os
import sys

provider = os.environ["PROVIDER_VALUE"]
try:
    methods = json.load(open(sys.argv[1], encoding="utf-8"))["data"]
except (OSError, KeyError, TypeError, json.JSONDecodeError):
    raise SystemExit(1)

raise SystemExit(0 if any(
    method.get("provider") == provider
    and method.get("methodType") == "DIRECT_PASSWORD"
    for method in methods
) else 1)
PY
then
  echo "PASS: LDAP provider is exposed as a direct-password method"
  PASS=$((PASS + 1))
else
  echo "FAIL: LDAP provider is not exposed as a direct-password method (HTTP $METHODS_STATUS)"
  FAIL=$((FAIL + 1))
fi

# Obtain a CSRF token before the first state-changing request.
refresh_csrf
if [[ -z "$CSRF_TOKEN" ]]; then
  echo "FAIL: server did not issue an XSRF token"
  FAIL=$((FAIL + 1))
else
  echo "PASS: XSRF token issued"
  PASS=$((PASS + 1))
fi

LOGIN_STATUS="$(curl --max-time 15 -s \
  -o "$RESPONSE_FILE" -w "%{http_code}" \
  -X POST "$BASE_URL/api/v1/auth/direct/login" \
  -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
  -H "X-XSRF-TOKEN: $CSRF_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(python3 - "$PROVIDER" "$USERNAME" "$PASSWORD" <<'PY'
import json
import sys
print(json.dumps({
    "provider": sys.argv[1],
    "username": sys.argv[2],
    "password": sys.argv[3],
}))
PY
)" || true)"
check_status "LDAP first login" "$LOGIN_STATUS" "200"
FIRST_USER_ID=""
if [[ "$LOGIN_STATUS" == "200" ]]; then
  FIRST_USER_ID="$(json_user_id || true)"
  if [[ -n "$FIRST_USER_ID" ]]; then
    echo "PASS: first login returned a platform user id"
    PASS=$((PASS + 1))
  else
    echo "FAIL: first login response did not contain a user id"
    FAIL=$((FAIL + 1))
  fi
fi

LOGOUT_CSRF="$(csrf_token)"
LOGOUT_STATUS="$(curl --max-time 10 -s -o /dev/null -w "%{http_code}" \
  -X POST "$BASE_URL/api/v1/auth/logout" \
  -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
  -H "X-XSRF-TOKEN: $LOGOUT_CSRF" || true)"
if [[ "$LOGIN_STATUS" == "200" ]]; then
  if [[ "$LOGOUT_STATUS" == "200" || "$LOGOUT_STATUS" == "204" || "$LOGOUT_STATUS" == "302" ]]; then
    echo "PASS: logout after first login (HTTP $LOGOUT_STATUS)"
    PASS=$((PASS + 1))
  else
    echo "FAIL: logout after first login (got HTTP $LOGOUT_STATUS)"
    FAIL=$((FAIL + 1))
  fi
fi

refresh_csrf
REPEAT_STATUS="$(curl --max-time 15 -s \
  -o "$RESPONSE_FILE" -w "%{http_code}" \
  -X POST "$BASE_URL/api/v1/auth/direct/login" \
  -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
  -H "X-XSRF-TOKEN: $CSRF_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(python3 - "$PROVIDER" "$USERNAME" "$PASSWORD" <<'PY'
import json
import sys
print(json.dumps({
    "provider": sys.argv[1],
    "username": sys.argv[2],
    "password": sys.argv[3],
}))
PY
)" || true)"
check_status "LDAP repeat login" "$REPEAT_STATUS" "200"
if [[ "$REPEAT_STATUS" == "200" && -n "$FIRST_USER_ID" ]]; then
  REPEAT_USER_ID="$(json_user_id || true)"
  if [[ "$REPEAT_USER_ID" == "$FIRST_USER_ID" ]]; then
    echo "PASS: repeat login resolved the same platform user"
    PASS=$((PASS + 1))
  else
    echo "FAIL: repeat login resolved a different platform user"
    FAIL=$((FAIL + 1))
  fi
fi

if [[ -n "$RENAMED_USERNAME" && "$REPEAT_STATUS" == "200" ]]; then
  LOGOUT_CSRF="$(csrf_token)"
  curl --max-time 10 -s -o /dev/null \
    -X POST "$BASE_URL/api/v1/auth/logout" \
    -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
    -H "X-XSRF-TOKEN: $LOGOUT_CSRF" || true
  refresh_csrf
  RENAMED_STATUS="$(curl --max-time 15 -s \
    -o "$RESPONSE_FILE" -w "%{http_code}" \
    -X POST "$BASE_URL/api/v1/auth/direct/login" \
    -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
    -H "X-XSRF-TOKEN: $CSRF_TOKEN" \
    -H "Content-Type: application/json" \
    -d "$(python3 - "$PROVIDER" "$RENAMED_USERNAME" "$RENAMED_PASSWORD" <<'PY'
import json
import sys
print(json.dumps({
    "provider": sys.argv[1],
    "username": sys.argv[2],
    "password": sys.argv[3],
}))
PY
)" || true)"
  check_status "LDAP login after username change" "$RENAMED_STATUS" "200"
  if [[ "$RENAMED_STATUS" == "200" && -n "$FIRST_USER_ID" ]]; then
    RENAMED_USER_ID="$(json_user_id || true)"
    if [[ "$RENAMED_USER_ID" == "$FIRST_USER_ID" ]]; then
      echo "PASS: username change preserved the stable platform identity"
      PASS=$((PASS + 1))
    else
      echo "FAIL: username change created or resolved another platform identity"
      FAIL=$((FAIL + 1))
    fi
  fi
else
  echo "INFO: LDAP_SMOKE_RENAMED_USERNAME not set; username-change check skipped"
fi

if [[ "$REPEAT_STATUS" == "200" ]]; then
  LOGOUT_CSRF="$(csrf_token)"
  curl --max-time 10 -s -o /dev/null \
    -X POST "$BASE_URL/api/v1/auth/logout" \
    -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
    -H "X-XSRF-TOKEN: $LOGOUT_CSRF" || true
  refresh_csrf
fi

refresh_csrf
INVALID_PASSWORD_STATUS="$(curl --max-time 15 -s \
  -o "$RESPONSE_FILE" -w "%{http_code}" \
  -X POST "$BASE_URL/api/v1/auth/direct/login" \
  -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
  -H "X-XSRF-TOKEN: $CSRF_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(python3 - "$PROVIDER" "$USERNAME" "$WRONG_PASSWORD" <<'PY'
import json
import sys
print(json.dumps({
    "provider": sys.argv[1],
    "username": sys.argv[2],
    "password": sys.argv[3],
}))
PY
)" || true)"
check_status "Invalid LDAP password is rejected" "$INVALID_PASSWORD_STATUS" "401"
if grep -Eiq 'ldap|bind|entryuuid|objectguid|directory|upstream' "$RESPONSE_FILE"; then
  echo "FAIL: invalid-password response leaks upstream details"
  FAIL=$((FAIL + 1))
else
  echo "PASS: invalid-password response contains no upstream detail"
  PASS=$((PASS + 1))
fi

refresh_csrf
UNKNOWN_STATUS="$(curl --max-time 15 -s \
  -o "$RESPONSE_FILE" -w "%{http_code}" \
  -X POST "$BASE_URL/api/v1/auth/direct/login" \
  -b "$COOKIE_JAR" -c "$COOKIE_JAR" \
  -H "X-XSRF-TOKEN: $CSRF_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(python3 - "$PROVIDER" "$UNKNOWN_USERNAME" "$PASSWORD" <<'PY'
import json
import sys
print(json.dumps({
    "provider": sys.argv[1],
    "username": sys.argv[2],
    "password": sys.argv[3],
}))
PY
)" || true)"
check_status "Unknown LDAP identity is rejected" "$UNKNOWN_STATUS" "401"
if grep -Eiq 'ldap|bind|entryuuid|objectguid|directory|upstream' "$RESPONSE_FILE"; then
  echo "FAIL: unknown-identity response leaks upstream details"
  FAIL=$((FAIL + 1))
else
  echo "PASS: unknown-identity response contains no upstream detail"
  PASS=$((PASS + 1))
fi

if [[ "$PASS" -gt 0 && "$FAIL" -eq 0 ]]; then
  echo
  echo "LDAP smoke test passed: $PASS checks"
  exit 0
fi

echo
echo "LDAP smoke test failed: $PASS passed, $FAIL failed"
exit 1
