#!/usr/bin/env bash
# =============================================================================
# Scrum4Me — API curl test script
# =============================================================================
# See scripts/README.md for full setup instructions.
#
# Quick start:
#   1. npx prisma db seed
#   2. npm run dev
#   3. Log in as "lars", go to Settings → API Tokens, create a token
#   4. Paste it in TOKEN below
#   5. Fill in the four IDs (see README for how to find them)
#   6. Optionally: log in as "demo", create a token, paste in DEMO_TOKEN
#   7. bash scripts/test-api.sh
# =============================================================================

TOKEN="9c839ecd03590d2e37a331ca6701f79ada64ce0fef6942040e02723111952167"        # API token for "lars" (full-permission user)
DEMO_TOKEN=""   # API token for "demo" (read-only — used for 403 tests, optional)
BASE_URL="http://localhost:3001"

# IDs — see scripts/README.md for how to find these
PRODUCT_ID="cmoentdso0002541783aehb6j"   # A product owned by lars
SPRINT_ID="cmoepgsr7000a5417lygh1ggq"    # An active sprint in that product
STORY_ID="cmoepj1g8000c5417x29drkhy"     # A story in that sprint (IN_SPRINT status)
TASK_ID="cmod3elvd000004gtntw9u5gs"                               # Fill in after creating a task via Sprint Planning UI

# =============================================================================
# Helpers
# =============================================================================

PASS=0
FAIL=0

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

# Passes if actual matches any of the remaining arguments
check_one_of() {
  local label="$1"
  local actual="$2"
  shift 2
  for expected in "$@"; do
    if [ "$actual" = "$expected" ]; then
      echo "  PASS  $label"
      PASS=$((PASS + 1))
      return
    fi
  done
  echo "  FAIL  $label (expected one of [$*], got $actual)"
  FAIL=$((FAIL + 1))
}

header() {
  echo ""
  echo "── $1 ──────────────────────────────────────────────────────────"
}

get()   { curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" "$@"; }
post()  { curl -s -o /dev/null -w "%{http_code}" -X POST  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$1" "${@:2}"; }
patch() { curl -s -o /dev/null -w "%{http_code}" -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$1" "${@:2}"; }

get_demo()   { curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $DEMO_TOKEN" "$@"; }
post_demo()  { curl -s -o /dev/null -w "%{http_code}" -X POST  -H "Authorization: Bearer $DEMO_TOKEN" -H "Content-Type: application/json" -d "$1" "${@:2}"; }
patch_demo() { curl -s -o /dev/null -w "%{http_code}" -X PATCH -H "Authorization: Bearer $DEMO_TOKEN" -H "Content-Type: application/json" -d "$1" "${@:2}"; }

no_auth_get()   { curl -s -o /dev/null -w "%{http_code}" "$@"; }
no_auth_post()  { curl -s -o /dev/null -w "%{http_code}" -X POST  -H "Content-Type: application/json" -d "$1" "${@:2}"; }
no_auth_patch() { curl -s -o /dev/null -w "%{http_code}" -X PATCH -H "Content-Type: application/json" -d "$1" "${@:2}"; }

skip_if_empty() {
  local var_name="$1"
  local var_val="$2"
  if [ -z "$var_val" ]; then
    echo "  SKIP  $var_name not set — see scripts/README.md"
    return 1
  fi
  return 0
}

# =============================================================================
# GET /api/products
# =============================================================================

test_products() {
  header "GET /api/products"

  # TC-P-09  happy path
  check "TC-P-09  happy path (lars)" 200 \
    "$(get "$BASE_URL/api/products")"

  # TC-P-01  no token
  check "TC-P-01  no token → 401" 401 \
    "$(no_auth_get "$BASE_URL/api/products")"

  # TC-P-02  invalid token
  check "TC-P-02  invalid token → 401" 401 \
    "$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer invalid-token-xyz" "$BASE_URL/api/products")"

  # Print the product list so the user can copy IDs if needed
  echo ""
  echo "  Product list:"
  curl -s -H "Authorization: Bearer $TOKEN" "$BASE_URL/api/products" | \
    grep -o '"id":"[^"]*"\|"name":"[^"]*"' | paste - - | \
    sed 's/"id":"//;s/","name":"/ → /;s/"//' | \
    while read -r line; do echo "    $line"; done
  echo ""
}

# =============================================================================
# GET /api/products/:id/next-story
# =============================================================================

test_next_story() {
  header "GET /api/products/:id/next-story"
  skip_if_empty "PRODUCT_ID" "$PRODUCT_ID" || return

  # TC-NS-08  happy path — 200 if active sprint with stories, 404 if not
  check_one_of "TC-NS-08  happy path (lars, 200 or 404 both valid)" 200 404 \
    "$(get "$BASE_URL/api/products/$PRODUCT_ID/next-story")"

  # TC-NS-01  no token
  check "TC-NS-01  no token → 401" 401 \
    "$(no_auth_get "$BASE_URL/api/products/$PRODUCT_ID/next-story")"

  # TC-NS-02  invalid token
  check "TC-NS-02  invalid token → 401" 401 \
    "$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer invalid-token" "$BASE_URL/api/products/$PRODUCT_ID/next-story")"

  # TC-NS-07  cross-user: unknown product
  check "TC-NS-07  unknown product id → 404" 404 \
    "$(get "$BASE_URL/api/products/nonexistent-product-id/next-story")"
}

# =============================================================================
# GET /api/sprints/:id/tasks
# =============================================================================

test_sprint_tasks() {
  header "GET /api/sprints/:id/tasks"
  skip_if_empty "SPRINT_ID" "$SPRINT_ID" || return

  # TC-ST-09  happy path with limit=10
  check "TC-ST-09  happy path limit=10 → 200" 200 \
    "$(get "$BASE_URL/api/sprints/$SPRINT_ID/tasks?limit=10")"

  # TC-ST-06  custom limit
  check "TC-ST-06  limit=3 → 200" 200 \
    "$(get "$BASE_URL/api/sprints/$SPRINT_ID/tasks?limit=3")"

  # TC-ST-01  no token
  check "TC-ST-01  no token → 401" 401 \
    "$(no_auth_get "$BASE_URL/api/sprints/$SPRINT_ID/tasks")"

  # TC-ST-03  unknown sprint
  check "TC-ST-03  unknown sprint id → 404" 404 \
    "$(get "$BASE_URL/api/sprints/nonexistent-sprint-id/tasks")"
}

# =============================================================================
# POST /api/stories/:id/log  (all 3 log types)
# =============================================================================

test_story_log() {
  header "POST /api/stories/:id/log"
  skip_if_empty "STORY_ID" "$STORY_ID" || return

  # TC-L-17  IMPLEMENTATION_PLAN
  check "TC-L-17  IMPLEMENTATION_PLAN → 201" 201 \
    "$(post '{"type":"IMPLEMENTATION_PLAN","content":"Aanpak: stap 1 implementeer, stap 2 test."}' \
      "$BASE_URL/api/stories/$STORY_ID/log")"

  # TC-L-18  TEST_RESULT PASSED
  check "TC-L-18  TEST_RESULT PASSED → 201" 201 \
    "$(post '{"type":"TEST_RESULT","content":"Alle tests geslaagd.","status":"PASSED"}' \
      "$BASE_URL/api/stories/$STORY_ID/log")"

  # TC-L-19  COMMIT
  check "TC-L-19  COMMIT → 201" 201 \
    "$(post '{"type":"COMMIT","content":"feat: implementatie afgerond","commit_hash":"abc1234","commit_message":"feat(ST-001): account aanmaken"}' \
      "$BASE_URL/api/stories/$STORY_ID/log")"

  # TC-L-07  invalid type
  check "TC-L-07  invalid type → 400" 400 \
    "$(post '{"type":"UNKNOWN","content":"test"}' \
      "$BASE_URL/api/stories/$STORY_ID/log")"

  # TC-L-08  IMPLEMENTATION_PLAN missing content
  check "TC-L-08  missing content → 400" 400 \
    "$(post '{"type":"IMPLEMENTATION_PLAN"}' \
      "$BASE_URL/api/stories/$STORY_ID/log")"

  # TC-L-10  TEST_RESULT missing status
  check "TC-L-10  TEST_RESULT missing status → 400" 400 \
    "$(post '{"type":"TEST_RESULT","content":"done"}' \
      "$BASE_URL/api/stories/$STORY_ID/log")"

  # TC-L-01  no token
  check "TC-L-01  no token → 401" 401 \
    "$(no_auth_post '{"type":"IMPLEMENTATION_PLAN","content":"test"}' \
      "$BASE_URL/api/stories/$STORY_ID/log")"

  # TC-L-03  demo user → 403
  if [ -n "$DEMO_TOKEN" ]; then
    check "TC-L-03  demo user → 403" 403 \
      "$(post_demo '{"type":"IMPLEMENTATION_PLAN","content":"test"}' \
        "$BASE_URL/api/stories/$STORY_ID/log")"
  else
    echo "  SKIP  TC-L-03  demo token not set (set DEMO_TOKEN to enable)"
  fi
}

# =============================================================================
# PATCH /api/stories/:id/tasks/reorder
# =============================================================================

test_reorder() {
  header "PATCH /api/stories/:id/tasks/reorder"
  skip_if_empty "STORY_ID" "$STORY_ID" || return
  skip_if_empty "TASK_ID"  "$TASK_ID"  || return

  # TC-RO-10  happy path — single task is a valid reorder
  check "TC-RO-10  happy path → 200" 200 \
    "$(patch "{\"task_ids\":[\"$TASK_ID\"]}" \
      "$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"

  # TC-RO-06  empty task_ids
  check "TC-RO-06  empty task_ids → 400" 400 \
    "$(patch '{"task_ids":[]}' \
      "$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"

  # TC-RO-08  task ID not belonging to this story
  check "TC-RO-08  foreign task id → 400" 400 \
    "$(patch '{"task_ids":["nonexistent-task-id-xyz"]}' \
      "$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"

  # TC-RO-01  no token
  check "TC-RO-01  no token → 401" 401 \
    "$(no_auth_patch "{\"task_ids\":[\"$TASK_ID\"]}" \
      "$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"

  # TC-RO-03  demo user → 403
  if [ -n "$DEMO_TOKEN" ]; then
    check "TC-RO-03  demo user → 403" 403 \
      "$(patch_demo "{\"task_ids\":[\"$TASK_ID\"]}" \
        "$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"
  else
    echo "  SKIP  TC-RO-03  demo token not set (set DEMO_TOKEN to enable)"
  fi
}

# =============================================================================
# PATCH /api/tasks/:id
# =============================================================================

test_tasks() {
  header "PATCH /api/tasks/:id"
  skip_if_empty "TASK_ID" "$TASK_ID" || return

  # TC-T-12  status → IN_PROGRESS
  check "TC-T-12  status → IN_PROGRESS" 200 \
    "$(patch '{"status":"IN_PROGRESS"}' "$BASE_URL/api/tasks/$TASK_ID")"

  # TC-T-13  status → DONE
  check "TC-T-13  status → DONE" 200 \
    "$(patch '{"status":"DONE"}' "$BASE_URL/api/tasks/$TASK_ID")"

  # Reset to TO_DO for repeatability
  patch '{"status":"TO_DO"}' "$BASE_URL/api/tasks/$TASK_ID" > /dev/null

  # TC-T-06  invalid status
  check "TC-T-06  invalid status → 400" 400 \
    "$(patch '{"status":"INVALID"}' "$BASE_URL/api/tasks/$TASK_ID")"

  # TC-T-07  empty body
  check "TC-T-07  empty body → 400" 400 \
    "$(patch '{}' "$BASE_URL/api/tasks/$TASK_ID")"

  # TC-T-01  no token
  check "TC-T-01  no token → 401" 401 \
    "$(no_auth_patch '{"status":"DONE"}' "$BASE_URL/api/tasks/$TASK_ID")"

  # TC-T-03  demo user → 403
  if [ -n "$DEMO_TOKEN" ]; then
    check "TC-T-03  demo user → 403" 403 \
      "$(patch_demo '{"status":"DONE"}' "$BASE_URL/api/tasks/$TASK_ID")"
  else
    echo "  SKIP  TC-T-03  demo token not set (set DEMO_TOKEN to enable)"
  fi
}

# =============================================================================
# POST /api/todos
# Note: product_id is REQUIRED by the API (z.string().min(1)).
#       TC-TD-09 ("without product_id") therefore returns 400, not 201.
# =============================================================================

test_todos() {
  header "POST /api/todos"
  skip_if_empty "PRODUCT_ID" "$PRODUCT_ID" || return

  # TC-TD-10  happy path — product_id required
  check "TC-TD-10  happy path with product_id → 201" 201 \
    "$(post "{\"title\":\"Test todo $(date +%s)\",\"product_id\":\"$PRODUCT_ID\"}" \
      "$BASE_URL/api/todos")"

  # TC-TD-06  product_id missing → 400 (required by schema, not optional)
  check "TC-TD-06  missing product_id → 400" 400 \
    "$(post '{"title":"Todo without product"}' \
      "$BASE_URL/api/todos")"

  # TC-TD-04  title missing
  check "TC-TD-04  missing title → 400" 400 \
    "$(post "{\"product_id\":\"$PRODUCT_ID\"}" \
      "$BASE_URL/api/todos")"

  # TC-TD-05  empty title
  check "TC-TD-05  empty title → 400" 400 \
    "$(post "{\"title\":\"\",\"product_id\":\"$PRODUCT_ID\"}" \
      "$BASE_URL/api/todos")"

  # TC-TD-01  no token
  check "TC-TD-01  no token → 401" 401 \
    "$(no_auth_post "{\"title\":\"Test\",\"product_id\":\"$PRODUCT_ID\"}" \
      "$BASE_URL/api/todos")"

  # TC-TD-03  demo user → 403
  if [ -n "$DEMO_TOKEN" ]; then
    check "TC-TD-03  demo user → 403" 403 \
      "$(post_demo "{\"title\":\"Test\",\"product_id\":\"$PRODUCT_ID\"}" \
        "$BASE_URL/api/todos")"
  else
    echo "  SKIP  TC-TD-03  demo token not set (set DEMO_TOKEN to enable)"
  fi
}

# =============================================================================
# Entry point
# =============================================================================

echo "============================================================"
echo "  Scrum4Me API Test Suite"
echo "  Base URL : $BASE_URL"
echo "  Token    : ${TOKEN:0:8}... (lars)"
[ -n "$DEMO_TOKEN" ] && echo "  Demo     : ${DEMO_TOKEN:0:8}... (403 tests active)"
echo "============================================================"

if [ -z "$TOKEN" ]; then
  echo ""
  echo "ERROR: TOKEN is not set. See scripts/README.md."
  exit 1
fi

test_products
test_next_story
test_sprint_tasks
test_story_log
test_reorder
test_tasks
test_todos

echo ""
echo "============================================================"
echo "  Results: $PASS passed, $FAIL failed"
echo "============================================================"

[ "$FAIL" -eq 0 ] && exit 0 || exit 1
