#!/usr/bin/env bash
#
# Shared fixtures for REST API contract tests.
# Provides: DB helpers, OAuth login, assertion helpers, and backend lifecycle.
#
# Consumers source this file:
#   source "$(dirname "$0")/fixtures.sh"
#
# Environment (all overridable):
#   BACKEND_HOST  — default 127.0.0.1
#   BACKEND_PORT  — default 3001 (NexusCRM default)
#   TIDB_HOST     — default 127.0.0.1
#   TIDB_PORT     — default 4000 (or 4001 for docker-compose)
#   TIDB_USER     — default root
#   TIDB_PASSWORD — default ""
#   TIDB_DATABASE — default nexuscrm
#   ADMIN_EMAIL   — default admin@example.invalid
#   ADMIN_PASS    — default Admin123!
#   CLIENT_ID     — default test-gosf-client
#   CLIENT_SECRET — default test-gosf-secret-123

set -uo pipefail

: "${BACKEND_HOST:=127.0.0.1}"
: "${BACKEND_PORT:=3001}"
: "${TIDB_HOST:=127.0.0.1}"
: "${TIDB_PORT:=4000}"
: "${TIDB_USER:=root}"
: "${TIDB_PASSWORD:=}"
: "${TIDB_DATABASE:=nexuscrm}"
: "${ADMIN_EMAIL:=admin@example.invalid}"
: "${ADMIN_PASS:=Admin123!}"
: "${CLIENT_ID:=test-gosf-client}"
: "${CLIENT_SECRET:=test-gosf-secret-123}"

export BACKEND_HOST BACKEND_PORT
export TIDB_HOST TIDB_PORT TIDB_USER TIDB_PASSWORD TIDB_DATABASE

BASE_URL="http://${BACKEND_HOST}:${BACKEND_PORT}"
API_VER="v63.0"

# ---------- OAuth login ----------

# login_admin — obtain a Bearer token via password grant.
# Sets BEARER_TOKEN or exits non-zero.
login_admin() {
  local resp
  resp=$(curl -sf -X POST "${BASE_URL}/services/oauth2/token" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=password" \
    -d "username=${ADMIN_EMAIL}" \
    -d "password=${ADMIN_PASS}" \
    -d "client_id=${CLIENT_ID}" \
    -d "client_secret=${CLIENT_SECRET}" 2>/dev/null) || {
    echo "  FAIL: login failed for ${ADMIN_EMAIL}" >&2
    return 1
  }
  BEARER_TOKEN=$(echo "$resp" | jq -r '.access_token // empty')
  if [[ -z "$BEARER_TOKEN" ]]; then
    echo "  FAIL: no access_token in login response" >&2
    return 1
  fi
}

# authenticated_get / authenticated_post — curl wrappers with Bearer header.
authenticated_get() {
  local path="$1"
  shift
  curl -sS -w "\n%{http_code}" -X GET "${BASE_URL}${path}" \
    -H "Authorization: Bearer ${BEARER_TOKEN}" \
    -H "Content-Type: application/json" \
    "$@"
}

authenticated_post() {
  local path="$1" body="$2"
  shift 2
  curl -sS -w "\n%{http_code}" -X POST "${BASE_URL}${path}" \
    -H "Authorization: Bearer ${BEARER_TOKEN}" \
    -H "Content-Type: application/json" \
    -d "$body" \
    "$@"
}

authenticated_delete() {
  local path="$1"
  shift
  curl -sS -w "\n%{http_code}" -X DELETE "${BASE_URL}${path}" \
    -H "Authorization: Bearer ${BEARER_TOKEN}" \
    -H "Content-Type: application/json" \
    "$@"
}

authenticated_patch() {
  local path="$1" body="$2"
  shift 2
  curl -sS -w "\n%{http_code}" -X PATCH "${BASE_URL}${path}" \
    -H "Authorization: Bearer ${BEARER_TOKEN}" \
    -H "Content-Type: application/json" \
    -d "$body" \
    "$@"
}

# ---------- Assertion helpers ----------

# assert_eq — compare two values; print diagnostic and return 1 on mismatch.
assert_eq() {
  local label="$1" want="$2" got="$3"
  if [[ "$got" != "$want" ]]; then
    echo "  FAIL ${label}: got=${got}, want=${want}" >&2
    return 1
  fi
  return 0
}

# assert_has_key — check a JSON object has a top-level key.
assert_has_key() {
  local label="$1" json="$2" key="$3"
  if echo "$json" | jq -e "has(\"${key}\")" >/dev/null 2>&1; then
    return 0
  fi
  echo "  FAIL ${label}: missing key \"${key}\"" >&2
  return 1
}

# assert_json_field_eq — compare a jq-extracted field value.
assert_json_field_eq() {
  local label="$1" json="$2" jq_expr="$3" want="$4"
  local got
  got=$(echo "$json" | jq -r "$jq_expr" 2>/dev/null)
  assert_eq "$label" "$want" "$got"
}
