#!/usr/bin/env bash
# tidbcloud-openapi.sh - List and extract operations from OpenAPI specs.
#
# Usage:
#   scripts/tidbcloud-openapi.sh list   --sut tidbx [--query cluster] [--limit 50]
#   scripts/tidbcloud-openapi.sh extract --sut tidbx --operation-id ClusterService_CreateCluster

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

_resolve_spec_paths() {
  local sut="$1"
  local ref_dir="$SKILL_ROOT/references/$sut"

  case "$sut" in
    tidbx)
      echo "$ref_dir/openapi.json"
      ;;
    tidbx-premium)
      echo "$ref_dir/tidb.swagger.json"
      echo "$ref_dir/cmek.swagger.json"
      ;;
    *)
      echo >&2 "ERROR: Unknown SUT: $sut"
      return 1
      ;;
  esac
}

_load_merged_spec() {
  local sut="$1"
  local specs
  specs="$(_resolve_spec_paths "$sut")"

  local primary
  primary="$(echo "$specs" | head -1)"
  if [[ ! -f "$primary" ]]; then
    echo >&2 "ERROR: OpenAPI spec not found: $primary"
    return 1
  fi

  local merged
  merged="$(cat "$primary")"

  while IFS= read -r extra; do
    [[ "$extra" == "$primary" ]] && continue
    [[ -f "$extra" ]] || continue
    merged="$(jq -s '
      .[0] as $base | .[1] as $extra |
      $base |
      .paths += ($extra.paths // {}) |
      .definitions += ($extra.definitions // {})
    ' <(echo "$merged") "$extra")"
  done <<< "$specs"

  echo "$merged"
}

_list_operations() {
  local spec="$1" query="${2:-}" limit="${3:-200}"

  echo "$spec" | jq -r --arg q "$query" --argjson limit "$limit" '
    [.paths // {} | to_entries[] | .key as $path |
      .value | to_entries[] |
      select(.value.operationId != null) |
      {
        operationId: .value.operationId,
        method: (.key | ascii_upcase),
        path: $path,
        summary: (.value.summary // ""),
        tags: (.value.tags // [])
      }
    ] |
    if $q != "" then
      map(select(
        (.operationId + " " + .method + " " + .path + " " + .summary) |
        ascii_downcase | contains($q | ascii_downcase)
      ))
    else . end |
    .[:$limit]
  '
}

_extract_operation() {
  local spec="$1" operation_id="$2"

  echo "$spec" | jq --arg opid "$operation_id" '
    # Find the operation
    (.paths // {}) | to_entries[] |
    .key as $path |
    .value | to_entries[] |
    select(.value.operationId == $opid) |
    {path: $path, method: .key, operation: .value}
  ' | jq -s '
    if length == 0 then
      error("Operation not found")
    else .[0] end
  ' | jq --arg opid "$operation_id" -r --slurpfile spec <(echo "$spec") '
    . as $found |
    $found.operation as $op |

    # Collect all $ref strings recursively
    def collect_refs:
      [.. | objects | .["$ref"]? // empty | select(startswith("#/definitions/"))] | unique;

    # Resolve refs transitively
    def resolve_all_refs($defs):
      . as $refs |
      if ($refs | length) == 0 then []
      else
        [$refs[] | ltrimstr("#/definitions/") | . as $name |
          $defs[$name] // null | select(. != null) |
          {($name): .}
        ] | add // {} |
        . as $resolved |
        ($resolved | [.. | objects | .["$ref"]? // empty | select(startswith("#/definitions/"))] | unique) as $new_refs |
        ($new_refs - $refs) as $unresolved |
        if ($unresolved | length) > 0 then
          ($refs + $unresolved) | unique | resolve_all_refs($defs)
        else
          $resolved
        end
      end;

    ($spec[0].definitions // {}) as $all_defs |
    ($op | collect_refs) as $refs |
    ($refs | resolve_all_refs($all_defs)) as $resolved_defs |
    ($resolved_defs | del(.googlerpcStatus, .protobufAny)) as $clean_defs |

    {
      paths: { ($found.path): { ($found.method): $op } },
      definitions: $clean_defs
    }
  '
}

main() {
  if [[ $# -lt 1 ]]; then
    echo >&2 "Usage: tidbcloud-openapi.sh <list|extract> --sut <sut_name> [options]"
    exit 1
  fi

  local command="$1"
  shift

  local sut="tidbx" query="" limit=200 operation_id=""
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --sut) sut="$2"; shift 2 ;;
      --query) query="$2"; shift 2 ;;
      --limit) limit="$2"; shift 2 ;;
      --operation-id) operation_id="$2"; shift 2 ;;
      *) shift ;;
    esac
  done

  case "$sut" in
    premium|tidbx_premium|tidbcloud_premium) sut="tidbx-premium" ;;
    tidbx|tidbcloud_serverless|"") sut="tidbx" ;;
  esac

  local spec
  spec="$(_load_merged_spec "$sut")"

  case "$command" in
    list)
      local ops
      ops="$(_list_operations "$spec" "$query" "$limit")"
      jq -n --argjson ops "$ops" '{operations: $ops}'
      ;;
    extract)
      if [[ -z "$operation_id" ]]; then
        echo >&2 "ERROR: --operation-id is required for extract"
        exit 1
      fi
      _extract_operation "$spec" "$operation_id"
      ;;
    *)
      echo >&2 "ERROR: Unknown command: $command. Use list or extract."
      exit 1
      ;;
  esac
}

main "$@"
