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

# generate-harnesses-json - build harnesses.json from each adapters/<h>.sh meta block.
#
# Usage:
#   bin/generate-harnesses-json            Generate harnesses.json (pretty, default)
#   bin/generate-harnesses-json --compact  Single-line output
#
# Each adapter carries a machine-readable capability block, delimited by
#   # rh-meta-start ... # rh-meta-end
# holding one comment-prefixed JSON object. Aggregated, they are the
# harness-adapter's self-describing capability manifest - the local analog of a
# UHP `GET /v1/harnesses` discovery response: what each harness can and cannot do
# (token/cost reporting, read-only enforcement, structured output, MCP, auth), in
# one queryable file instead of scattered across the README table and
# resolve-harness.sh.
#
# The manifest describes harness CAPABILITIES only. The resolver's default-model
# policy stays in scripts/resolve-harness.sh on purpose - mirroring it here would
# make this manifest go stale on every model-pin edit, and default model is a
# router decision, not a harness capability.
#
# The manifest is generated, never hand-edited: change the block in the adapter
# and re-run this. ci-harnesses-json.yml fails any PR whose committed manifest
# does not match a fresh regen.

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
ADAPTERS="$ROOT/adapters"
OUTPUT="$ROOT/harnesses.json"

command -v jq >/dev/null 2>&1 || { echo "generate-harnesses-json: jq is required" >&2; exit 1; }

FORMAT=(jq .)
[ "${1:-}" = "--compact" ] && FORMAT=(jq -c .)

# Required keys every adapter meta block must carry. Keep in sync with the enum
# assertions in scripts/tests/test_generate_harnesses_json.sh.
REQUIRED='["id","label","cli","invoke","round_trip","token_usage","cost","read_only","structured_output","mcp","max_turns","claude_md","auth","native_control_path"]'

extract_meta() {  # $1 = adapter file -> the enclosed JSON object on stdout
  sed -n '/rh-meta-start/,/rh-meta-end/p' "$1" \
    | grep -v 'rh-meta-start\|rh-meta-end' \
    | sed -E 's/^#[[:space:]]?//'
}

metas=""
for f in "$ADAPTERS"/*.sh; do
  base="$(basename "$f" .sh)"
  meta="$(extract_meta "$f")"
  [ -n "$meta" ] || { echo "error: no rh-meta block in adapters/$base.sh" >&2; exit 1; }
  echo "$meta" | jq empty 2>/dev/null || { echo "error: adapters/$base.sh rh-meta block is not valid JSON" >&2; exit 1; }
  missing="$(echo "$meta" | jq -r --argjson req "$REQUIRED" '($req - (keys)) | join(", ")')"
  [ -z "$missing" ] || { echo "error: adapters/$base.sh meta missing key(s): $missing" >&2; exit 1; }
  id="$(echo "$meta" | jq -r '.id')"
  [ "$id" = "$base" ] || { echo "error: adapters/$base.sh meta id '$id' does not match filename '$base'" >&2; exit 1; }
  metas+="$meta"$'\n'
done

harnesses="$(printf '%s' "$metas" | jq -s 'sort_by(.id)')"
generated="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

jq -n --argjson h "$harnesses" --arg gen "$generated" '
  {
    note: "harness-adapter capability manifest - the local analog of a UHP GET /v1/harnesses discovery response. Generated by bin/generate-harnesses-json from each adapters/<h>.sh rh-meta block; do not hand-edit. Describes harness capabilities only; default-model policy lives in scripts/resolve-harness.sh.",
    contract: {
      stdin: "prompt",
      stdout: "{result, usage{input_tokens,output_tokens,cache_read_input_tokens,cache_creation_input_tokens}, session_id?, total_cost_usd?}",
      exit: { "0": "ok", "3": "abnormal-stop-no-output", "124": "timeout" }
    },
    generated: $gen,
    count: ($h | length),
    harnesses: $h
  }' | "${FORMAT[@]}" > "$OUTPUT"

echo "generate-harnesses-json: wrote $OUTPUT ($(echo "$harnesses" | jq 'length') harnesses)" >&2
