#!/usr/bin/env bash
# Server-side examples. Do not run with shell tracing (set -x).
set -euo pipefail
umask 077
: "${ZDW_API_BASE:?Inject the API base URL ending in /api/open/v1}"
: "${ZDW_API_KEY:?Inject an API key from your secret manager}"
base="${ZDW_API_BASE%/}"
case "$base" in
  https://*|http://localhost:*|http://127.0.0.1:*) ;;
  *) printf '%s\n' 'Use HTTPS, or HTTP on localhost only' >&2; exit 1 ;;
esac
if [[ "$ZDW_API_KEY" == *$'\n'* || "$ZDW_API_KEY" == *$'\r'* ]]; then
  printf '%s\n' 'Invalid API key' >&2; exit 1
fi

api() {
  local response_file
  response_file="$(mktemp)"
  # Read the key from stdin rather than putting it in curl's process arguments.
  # A file lets curl discard a failed response before retrying, so JSON is not concatenated.
  if printf 'X-Api-Key: %s\n' "$ZDW_API_KEY" | curl --silent --show-error --fail-with-body \
    --connect-timeout 10 --max-time 60 --retry 3 --retry-max-time 180 \
    --header @- --header 'Accept: application/json' --output "$response_file" "$@"; then
    cat "$response_file"
    rm -f -- "$response_file"
  else
    # Only public error metadata is printed; no key or request body is logged.
    jq -c '{code,requestId}' "$response_file" >&2 2>/dev/null || true
    rm -f -- "$response_file"
    return 1
  fi
}
segment() { jq -rn --arg value "$1" '$value | @uri'; }
wait_task() {
  local path="$1" delay=3 elapsed=0 task state
  while (( elapsed < 1800 )); do
    task="$(api "$base$path")"
    state="$(jq -r '.executionStatus' <<<"$task")"
    case "$state" in
      queued|waiting_resource|processing) sleep "$delay"; elapsed=$((elapsed + delay)); delay=$((delay * 2)); (( delay <= 30 )) || delay=30 ;;
      succeeded|partial|failed|cancelled) jq '{id,status,executionStatus,coverageComplete,sourceStatus}' <<<"$task"; return ;;
      *) printf '%s\n' 'Unknown executionStatus; read the existing task later without creating another task' >&2; return 1 ;;
    esac
  done
  printf 'Polling timeout; continue GET %s later without creating another task\n' "$path" >&2
  return 1
}

idempotency_key=''
key_supplied=false
arguments=()
while (( $# )); do
  case "$1" in
    --idempotency-key)
      if [[ "$key_supplied" == true || $# -lt 2 || ! "$2" =~ ^[A-Za-z0-9_.:-]{1,128}$ ]]; then
        printf '%s\n' 'Provide one valid --idempotency-key (1-128 letters, digits, _ . : -)' >&2; exit 2
      fi
      idempotency_key="$2"; key_supplied=true; shift 2 ;;
    --*) printf '%s\n' 'Unknown option' >&2; exit 2 ;;
    *) arguments+=("$1"); shift ;;
  esac
done
if (( ${#arguments[@]} )); then set -- "${arguments[@]}"; else set --; fi
command="${1:-}"
case "$command" in
  query|check)
    if [[ "$command" == query && $# -ne 2 ]] || [[ "$command" == check && $# -ne 3 && $# -ne 4 ]]; then
      printf '%s\n' 'Provide a query enterprise, or a check enterprise, keyword and optional source query ID' >&2; exit 2
    fi
    subject="${2:?Provide the complete enterprise name}"
    source_query="${4:-}"
    if [[ "$command" == query ]]; then
      path=/queries
      body="$(jq -cn --arg subject "$subject" '{subjectNames:[$subject]}')"
    else
      keyword="${3:?Provide a keyword}"
      path=/checks
      body="$(jq -cn --arg subject "$subject" --arg keyword "$keyword" --arg source "$source_query" \
        '{applicant:$subject,criteria:[{kind:"keyword",value:$keyword}]} + (if $source == "" then {} else {sourceRegistryQueryId:$source} end)')"
    fi
    if [[ "$key_supplied" == false ]]; then idempotency_key="$(python3 -c 'import uuid; print(uuid.uuid4())')"; fi
    # On restart, supply --idempotency-key and the same original business arguments.
    # Production callers persist the key and exact request before the first send.
    printf 'Idempotency-Key=%s\n' "$idempotency_key" >&2
    accepted="$(api --header 'Content-Type: application/json' --header "Idempotency-Key: $idempotency_key" --data "$body" "$base$path")"
    if [[ "$command" == query ]]; then id="$(jq -er '.queries[0].id' <<<"$accepted")"; else id="$(jq -er '.id' <<<"$accepted")"; fi
    printf 'Accepted %s/%s\n' "$path" "$id" >&2
    wait_task "$path/$(segment "$id")"
    ;;
  download)
    if [[ "$key_supplied" == true ]]; then printf '%s\n' '--idempotency-key applies to query/check only' >&2; exit 2; fi
    if (( $# != 3 )); then printf '%s\n' 'Provide a document ID and new output file path' >&2; exit 2; fi
    document_id="${2:?Provide a document ID}"
    output="${3:?Provide a new output file path}"
    # Reserve the destination without overwriting any existing file.
    (set -o noclobber; : > "$output") || exit 1
    if ! printf 'X-Api-Key: %s\n' "$ZDW_API_KEY" | curl --silent --show-error --fail \
      --connect-timeout 10 --max-time 60 --retry 3 --retry-max-time 180 --header @- \
      "$base/documents/$(segment "$document_id")/content" --output "$output"; then
      rm -f -- "$output"; exit 1
    fi
    printf '%s\n' 'Download completed' >&2
    ;;
  *) printf 'Usage: %s query SUBJECT [--idempotency-key KEY] | check SUBJECT KEYWORD [SOURCE_QUERY_ID] [--idempotency-key KEY] | download DOCUMENT_ID OUTPUT_FILE\n' "$0" >&2; exit 2 ;;
esac
