#!/usr/bin/env bash
# UpServe Agent Runtime API curl quickstart: 키 확인 -> Deployment 조회 -> Session 생성
# (Idempotency-Key) -> 같은 키 재전송 -> Turn 폴링 -> 결과 출력. jq 는 있으면 쓰고 없어도 동작한다.
#
#   export UPSERVE_API_KEY=...            # 키는 환경변수로만 넘긴다(명령줄·로그에 남기지 않는다)
#   export UPSERVE_DEPLOYMENT_ID=...      # 선택. 없으면 GET /v1/deployments 의 첫 항목을 쓴다
#   bash runtime_quickstart.sh "이번 달 매출을 요약해주세요."
set -euo pipefail

BASE="${UPSERVE_API_BASE_URL:-https://api.upserve.app}"
TEXT="${1:-Hello}"
: "${UPSERVE_API_KEY:?Set UPSERVE_API_KEY in the environment}"

# 키가 argv(ps)에 나타나지 않도록 curl 설정은 프로세스 치환으로 넘긴다.
call() { # call METHOD PATH [IDEMPOTENCY_KEY] [JSON_BODY] -> BODY, CODE
  local method=$1 path=$2 key=${3:-} data=${4:-} out
  local args=(--silent --show-error --max-time 30 -X "$method")
  [ -n "$key" ] && args+=(-H "Idempotency-Key: $key")
  [ -n "$data" ] && args+=(-H "Content-Type: application/json" --data "$data")
  out=$(curl "${args[@]}" --config <(printf 'header = "Authorization: Bearer %s"\n' "$UPSERVE_API_KEY") \
        --write-out $'\n%{http_code}' "$BASE$path") || exit 1
  CODE=${out##*$'\n'}
  BODY=${out%$'\n'*}
}

field() { # field NAME: 본문 첫 번째 "NAME":"값"(또는 숫자)
  if command -v jq >/dev/null 2>&1; then
    printf '%s' "$BODY" | jq -r --arg n "$1" '[.. | objects | select(has($n)) | .[$n]][0] // empty'
  else
    # grep -o는 왼쪽부터 겹치지 않는 일치를 모두 내므로 head가 본문의 첫 번째 값을 고른다.
    # (sed의 탐욕적 .*는 마지막 값을 골라 Turn status 대신 usage.status를 읽었다.)
    printf '%s' "$BODY" | grep -o "\"$1\" *: *\"\{0,1\}[^\",}]*" | head -n 1 | sed 's/^[^:]*: *"\{0,1\}//'
  fi
}

# 1) 키 확인과 Deployment 조회. 401 이면 키가 없거나 잘못된 것이다.
DEPLOYMENT_ID="${UPSERVE_DEPLOYMENT_ID:-}"
call GET "/v1/deployments"
[ "$CODE" = 200 ] || { echo "GET /v1/deployments -> $CODE: $BODY" >&2; exit 1; }
[ -n "$DEPLOYMENT_ID" ] || DEPLOYMENT_ID=$(field id)
[ -n "$DEPLOYMENT_ID" ] || { echo "No deployment is available to this key" >&2; exit 1; }
echo "deployment: $DEPLOYMENT_ID"

# 2) Session 생성. 같은 Idempotency-Key 로는 같은 요청만 다시 보낸다.
KEY="quickstart-$(date +%s)-$$"
ESCAPED=$(printf '%s' "$TEXT" | sed 's/\\/\\\\/g; s/"/\\"/g' | tr '\n\t' '  ')  # 한 줄 텍스트용 최소 이스케이프
REQUEST="{\"input\":[{\"type\":\"TEXT\",\"text\":\"$ESCAPED\"}]}"
call POST "/v1/deployments/$DEPLOYMENT_ID/sessions" "$KEY" "$REQUEST"
[ "$CODE" = 202 ] || { echo "create session -> $CODE: $BODY" >&2; exit 1; }
FIRST=$BODY
SESSION_ID=$(field session_id)
TURN_ID=$(field turn_id)
echo "accepted: session=$SESSION_ID turn=$TURN_ID"

# 3) 통신 실패를 가정한 재전송: 같은 키·같은 본문이면 같은 receipt 가 돌아온다.
call POST "/v1/deployments/$DEPLOYMENT_ID/sessions" "$KEY" "$REQUEST"
# (JSON 키 순서는 다를 수 있으므로 식별 값으로 비교한다.)
if [ "$CODE" = 202 ] && [ "$(field turn_id)" = "$TURN_ID" ] && [ "$(field session_id)" = "$SESSION_ID" ]; then echo "replay with the same key: same receipt"; else echo "replay differed: $CODE $BODY (first: $FIRST)" >&2; exit 1; fi

# 4) Turn 폴링. 종결 상태(SUCCEEDED/FAILED/CANCELED/EXPIRED) 또는 REQUIRES_ACTION 까지.
for _ in $(seq 1 "${UPSERVE_POLL_MAX:-300}"); do
  call GET "/v1/sessions/$SESSION_ID/turns/$TURN_ID"
  [ "$CODE" = 200 ] || { echo "get turn -> $CODE: $BODY" >&2; exit 1; }
  STATUS=$(field status)
  case "$STATUS" in SUCCEEDED|FAILED|CANCELED|EXPIRED|REQUIRES_ACTION) break ;; esac
  sleep "${UPSERVE_POLL_SECONDS:-2}"
done

# 5) 결과 출력. outputs 의 TEXT 는 output.text 에 있다.
echo "status: $STATUS"
echo "$BODY"
[ "$STATUS" = SUCCEEDED ]
